Fix: Sonos airplay mode infinite loop
authorMarcel van der Veldt <m.vanderveldt@outlook.com>
Sat, 16 Nov 2024 15:23:21 +0000 (16:23 +0100)
committerMarcel van der Veldt <m.vanderveldt@outlook.com>
Sat, 16 Nov 2024 15:23:21 +0000 (16:23 +0100)
music_assistant/providers/sonos/player.py
music_assistant/providers/sonos/provider.py

index 9af19073e7352ee514885433565457b0a83e71bd..4aee6abf31a9e44c55456615a8016abd249936b4 100644 (file)
@@ -91,7 +91,7 @@ class SonosPlayer:
             return None
         if not airplay_player.available:
             return None
-        if active_only and not airplay_player.powered:
+        if active_only and not airplay_player.powered and not airplay_player.group_childs:
             return None
         return airplay_player
 
@@ -182,7 +182,8 @@ class SonosPlayer:
         ) and airplay.state != PlayerState.IDLE:
             # linked airplay player is active, redirect the command
             self.logger.debug("Redirecting STOP command to linked airplay player.")
-            await self.mass.players.cmd_stop(airplay.player_id)
+            if player_provider := self.mass.get_provider(airplay.provider):
+                await player_provider.cmd_stop(airplay.player_id)
             return
         try:
             await self.client.player.group.stop()
@@ -200,7 +201,8 @@ class SonosPlayer:
         ) and airplay.state != PlayerState.IDLE:
             # linked airplay player is active, redirect the command
             self.logger.debug("Redirecting PLAY command to linked airplay player.")
-            await self.mass.players.cmd_play(airplay.player_id)
+            if player_provider := self.mass.get_provider(airplay.provider):
+                await player_provider.cmd_play(airplay.player_id)
             return
         await self.client.player.group.play()
 
@@ -214,7 +216,8 @@ class SonosPlayer:
         ) and airplay.state != PlayerState.IDLE:
             # linked airplay player is active, redirect the command
             self.logger.debug("Redirecting PAUSE command to linked airplay player.")
-            await self.mass.players.cmd_pause(airplay.player_id)
+            if player_provider := self.mass.get_provider(airplay.provider):
+                await player_provider.cmd_pause(airplay.player_id)
             return
         await self.client.player.group.pause()
 
@@ -264,7 +267,7 @@ class SonosPlayer:
             self.mass_player.synced_to = active_group.coordinator_id
             self.mass_player.active_source = active_group.coordinator_id
 
-        if airplay := self.get_linked_airplay_player(True):
+        if airplay := self.get_linked_airplay_player(True, True):
             # linked airplay player is active, update media from there
             self.mass_player.state = airplay.state
             self.mass_player.powered = airplay.powered
index 636ec288a8cee01f784fccd70383a245b4007636..fa83e0e38111db110ab9ff5f7de4c7b9b8fb581a 100644 (file)
@@ -133,22 +133,33 @@ class SonosPlayerProvider(PlayerProvider):
             return base_entries
         return (
             *base_entries,
+            ConfigEntry(
+                key="airplay_detected",
+                type=ConfigEntryType.BOOLEAN,
+                label="airplay_detected",
+                hidden=True,
+                required=False,
+                default_value=sonos_player.get_linked_airplay_player(False) is not None,
+            ),
             ConfigEntry(
                 key=CONF_AIRPLAY_MODE,
                 type=ConfigEntryType.BOOLEAN,
                 label="Enable Airplay mode (experimental)",
                 description="Almost all newer Sonos speakers have Airplay support. "
                 "If you have the Airplay provider enabled in Music Assistant, "
-                "your Sonos speakers will also be detected as Airplay speakers, meaning "
+                "your Sonos speaker will also be detected as a Airplay speaker, meaning "
                 "you can group them with other Airplay speakers.\n\n"
                 "By default, Music Assistant uses the Sonos protocol for playback but with this "
                 "feature enabled, it will use the Airplay protocol instead by redirecting "
                 "the playback related commands to the linked Airplay player in Music Assistant, "
                 "allowing you to mix and match Sonos speakers with Airplay speakers. \n\n"
+                "NOTE: You need to have the Airplay provider enabled. "
+                "Also make sure that the Airplay version of this player is enabled. \n\n"
                 "TIP: When this feature is enabled, it make sense to set the underlying airplay "
                 "players to hide in the UI in the player settings to prevent duplicate players.",
                 required=False,
                 default_value=False,
+                depends_on="airplay_detected",
                 hidden=SonosCapability.AIRPLAY
                 not in sonos_player.discovery_info["device"]["capabilities"],
             ),
@@ -224,7 +235,7 @@ class SonosPlayerProvider(PlayerProvider):
             raise PlayerCommandFailed(msg)
         # for now always reset the active session
         sonos_player.client.player.group.active_session_id = None
-        if airplay := sonos_player.get_linked_airplay_player(True):
+        if airplay := sonos_player.get_linked_airplay_player(True, True):
             # linked airplay player is active, redirect the command
             self.logger.debug("Redirecting PLAY_MEDIA command to linked airplay player.")
             mass_player.active_source = airplay.active_source