diff --git a/pkg/client/client.go b/pkg/client/client.go index ae13adb2..46bcf733 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -1428,9 +1428,14 @@ func (c *Client) GetZoneMembers() ([]string, error) { // An empty response is reported as a zero-value Group; callers can // distinguish with (*Group).IsEmpty(). // -// ST-10 is the only product that supports stereo pairs; on other devices -// the call is harmless but will always return an empty group. The endpoint -// is named /getGroup on the device (mirroring /getZone), even though some +// ST-10 is the only product that supports stereo pairs. Verified against +// real hardware: a SoundTouch 20 does not reply to /getGroup at all -- the +// request hangs until the client's own timeout (30s by default, see +// DefaultConfig) rather than returning an empty group quickly. Callers on +// a poll cycle must gate this call behind a stereo-pair-capable model check +// (see stereoPairCapable in pkg/service/soundtouchweb) instead of relying on +// a fast, harmless response on unsupported models. The endpoint is named +// /getGroup on the device (mirroring /getZone), even though some // third-party wikis document it as plain /group. func (c *Client) GetGroup() (*models.Group, error) { var g models.Group diff --git a/pkg/service/soundtouchweb/websocket.go b/pkg/service/soundtouchweb/websocket.go index 9df2b365..e2dfb742 100644 --- a/pkg/service/soundtouchweb/websocket.go +++ b/pkg/service/soundtouchweb/websocket.go @@ -303,7 +303,9 @@ func (app *WebApp) UpdateDeviceStatus(_ string, conn *webtypes.DeviceConnection) return } - // /getGroup is ST10-only; ST20/ST30 may accept the request but never reply. + // /getGroup must be gated to ST10 models -- see Client.GetGroup's doc + // comment (verified against real hardware: a ST20 never replies at all, + // hanging until the client's timeout instead of returning quickly). stereoCapable := stereoPairCapable(conn.DeviceInfo) var groupGeneration uint64