mirror of
https://github.com/gesellix/Bose-SoundTouch.git
synced 2026-09-07 15:07:17 +00:00
fix(player): skip stereo polling on unsupported models
This commit is contained in:
committed by
Tobias Gesellchen
parent
ce66b103b4
commit
3b04a6eb57
@@ -52,6 +52,16 @@ type stereoPairMemberView struct {
|
||||
Available bool `json:"available"`
|
||||
}
|
||||
|
||||
func stereoPairCapable(info *models.DeviceInfo) bool {
|
||||
if info == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
typeName := strings.ToLower(strings.TrimSpace(info.Type))
|
||||
|
||||
return typeName == "st10" || typeName == "soundtouch 10"
|
||||
}
|
||||
|
||||
// deviceViewSnapshot projects the physical registry into logical control
|
||||
// targets for the HTTP API and the global player WebSocket.
|
||||
func (app *WebApp) deviceViewSnapshot() map[string]deviceView {
|
||||
|
||||
@@ -303,7 +303,13 @@ func (app *WebApp) UpdateDeviceStatus(_ string, conn *webtypes.DeviceConnection)
|
||||
return
|
||||
}
|
||||
|
||||
groupGeneration := conn.BeginGroupRefresh()
|
||||
// /getGroup is ST10-only; ST20/ST30 may accept the request but never reply.
|
||||
stereoCapable := stereoPairCapable(conn.DeviceInfo)
|
||||
|
||||
var groupGeneration uint64
|
||||
if stereoCapable {
|
||||
groupGeneration = conn.BeginGroupRefresh()
|
||||
}
|
||||
|
||||
// Phase 1: slow network fetches. Local vars only, no shared state
|
||||
// is touched yet. Errors are recorded so the merge below can tell
|
||||
@@ -313,7 +319,15 @@ func (app *WebApp) UpdateDeviceStatus(_ string, conn *webtypes.DeviceConnection)
|
||||
presets, presetsErr := conn.Client.GetPresets()
|
||||
sources, sourcesErr := conn.Client.GetSources()
|
||||
bass, bassErr := conn.Client.GetBass()
|
||||
group, groupErr := conn.Client.GetGroup()
|
||||
|
||||
var (
|
||||
group *models.Group
|
||||
groupErr error
|
||||
)
|
||||
|
||||
if stereoCapable {
|
||||
group, groupErr = conn.Client.GetGroup()
|
||||
}
|
||||
|
||||
// Phase 2: fast merge. Only fields we successfully fetched
|
||||
// overwrite; everything else keeps the value other goroutines may
|
||||
@@ -346,7 +360,7 @@ func (app *WebApp) UpdateDeviceStatus(_ string, conn *webtypes.DeviceConnection)
|
||||
statusUpdated = true
|
||||
}
|
||||
|
||||
statusUpdated = statusUpdated || groupErr == nil
|
||||
statusUpdated = statusUpdated || (stereoCapable && groupErr == nil)
|
||||
|
||||
// Mark as connected if we successfully got at least one
|
||||
// status from this round. Mirrors prior behaviour.
|
||||
@@ -354,7 +368,7 @@ func (app *WebApp) UpdateDeviceStatus(_ string, conn *webtypes.DeviceConnection)
|
||||
s.LastActivity = time.Now()
|
||||
})
|
||||
|
||||
if groupErr == nil {
|
||||
if stereoCapable && groupErr == nil {
|
||||
conn.ApplyPolledGroup(groupGeneration, group)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package soundtouchweb
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -23,7 +24,7 @@ func TestUpdateDeviceStatusRefreshesGroup(t *testing.T) {
|
||||
</group>`)
|
||||
defer server.Close()
|
||||
|
||||
conn := webtypes.NewDeviceConnection(client.NewClientFromHost(server.URL), nil)
|
||||
conn := webtypes.NewDeviceConnection(client.NewClientFromHost(server.URL), &models.DeviceInfo{Type: "SoundTouch 10"})
|
||||
NewWebApp().UpdateDeviceStatus("device-1", conn)
|
||||
|
||||
status := conn.Status()
|
||||
@@ -48,7 +49,7 @@ func TestUpdateDeviceStatusPreservesGroupOnError(t *testing.T) {
|
||||
server := newStatusTestServer(t, http.StatusInternalServerError, "group unavailable")
|
||||
defer server.Close()
|
||||
|
||||
conn := webtypes.NewDeviceConnection(client.NewClientFromHost(server.URL), nil)
|
||||
conn := webtypes.NewDeviceConnection(client.NewClientFromHost(server.URL), &models.DeviceInfo{Type: "SoundTouch 10"})
|
||||
existing := &models.Group{ID: "pair-old", Name: "Existing Pair"}
|
||||
conn.SetStatus(&webtypes.DeviceStatus{Group: existing})
|
||||
|
||||
@@ -64,6 +65,51 @@ func TestUpdateDeviceStatusPreservesGroupOnError(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateDeviceStatusSkipsGroupForNonStereoModel(t *testing.T) {
|
||||
var groupRequested atomic.Bool
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path == "/getGroup" {
|
||||
groupRequested.Store(true)
|
||||
http.Error(w, "unsupported endpoint", http.StatusInternalServerError)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
responses := map[string]string{
|
||||
"/now_playing": `<nowPlaying source="STANDBY"><playStatus>STOP_STATE</playStatus></nowPlaying>`,
|
||||
"/volume": `<volume><targetvolume>10</targetvolume><actualvolume>10</actualvolume><muteenabled>false</muteenabled></volume>`,
|
||||
"/presets": `<presets/>`,
|
||||
"/sources": `<sources/>`,
|
||||
"/bass": `<bass><targetbass>0</targetbass><actualbass>0</actualbass></bass>`,
|
||||
}
|
||||
body, ok := responses[r.URL.Path]
|
||||
if !ok {
|
||||
http.NotFound(w, r)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/xml")
|
||||
_, _ = w.Write([]byte(body))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
for _, model := range []string{"SoundTouch 20", "SoundTouch 30"} {
|
||||
t.Run(model, func(t *testing.T) {
|
||||
conn := webtypes.NewDeviceConnection(client.NewClientFromHost(server.URL), &models.DeviceInfo{Type: model})
|
||||
NewWebApp().UpdateDeviceStatus("device-1", conn)
|
||||
|
||||
if !conn.Status().IsConnected {
|
||||
t.Fatal("successful ordinary status requests should mark a non-stereo model connected")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if groupRequested.Load() {
|
||||
t.Fatal("UpdateDeviceStatus requested /getGroup for a non-stereo model")
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyGroupUpdatedEventReplacesGroup(t *testing.T) {
|
||||
conn := webtypes.NewDeviceConnection(nil, nil)
|
||||
previousActivity := time.Unix(1, 0)
|
||||
|
||||
Reference in New Issue
Block a user