From c710d9bced22f38fb33663f16b6b24e3cb1567d6 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Sat, 16 Nov 2024 16:23:21 +0100 Subject: [PATCH] Fix: Sonos airplay mode infinite loop --- music_assistant/providers/sonos/player.py | 13 ++++++++----- music_assistant/providers/sonos/provider.py | 15 +++++++++++++-- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/music_assistant/providers/sonos/player.py b/music_assistant/providers/sonos/player.py index 9af19073..4aee6abf 100644 --- a/music_assistant/providers/sonos/player.py +++ b/music_assistant/providers/sonos/player.py @@ -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 diff --git a/music_assistant/providers/sonos/provider.py b/music_assistant/providers/sonos/provider.py index 636ec288..fa83e0e3 100644 --- a/music_assistant/providers/sonos/provider.py +++ b/music_assistant/providers/sonos/provider.py @@ -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 -- 2.34.1