Skip to content

Commit

Permalink
Fixes for the Active source being wrong in some cases (#1099)
Browse files Browse the repository at this point in the history
  • Loading branch information
marcelveldt authored Feb 20, 2024
1 parent a91a996 commit 76dd42e
Show file tree
Hide file tree
Showing 7 changed files with 20 additions and 21 deletions.
14 changes: 10 additions & 4 deletions music_assistant/server/controllers/players.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ def update(
if player_id not in self._players:
return
player = self._players[player_id]
# calculate active_source
# calculate active_source (if needed)
player.active_source = self._get_active_source(player)
# calculate group volume
player.group_volume = self._get_group_volume_level(player)
Expand Down Expand Up @@ -534,6 +534,7 @@ async def cmd_group_power(self, player_id: str, power: bool) -> None:
elif member.active_source == group_player.player_id:
# turn off child player when group turns off
tg.create_task(self.cmd_power(member.player_id, False))
member.active_source = None
# edge case: group turned on but no members are powered, power them all!
if not members_powered and power:
for member in self.iter_group_members(group_player, only_powered=False):
Expand Down Expand Up @@ -789,9 +790,14 @@ def _get_active_source(self, player: Player) -> str:
"""Return the active_source id for given player."""
# if player is synced, return group leader's active source
if player.synced_to and (parent_player := self.get(player.synced_to)):
return parent_player.player_id
if active_player_group := self._get_active_player_group(player):
return active_player_group.player_id
return parent_player.active_source
# fallback to the first active group player
if player.powered:
for group_player in self._get_player_groups(
player, available_only=True, powered_only=True
):
if group_player.state in (PlayerState.PLAYING, PlayerState.PAUSED):
return group_player.active_source
# defaults to the player's own player id if not active source set
return player.active_source or player.player_id

Expand Down
11 changes: 1 addition & 10 deletions music_assistant/server/providers/airplay/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,6 @@ def __init__(
self.connected = False
self._connection_attempts = 0
self._connection_was_lost = False
self._task = None
self._playing: interface.Playing | None = None
self.logger = self.mass.players.logger.getChild("airplay").getChild(self.player_id)
self.cliraop_proc: AsyncProcess | None = None
Expand Down Expand Up @@ -229,9 +228,6 @@ async def disconnect(self):
if self.atv:
self.atv.close()
self.atv = None
if self._task:
self._task.cancel()
self._task = None
except Exception: # pylint: disable=broad-except
self.logger.exception("An error occurred while disconnecting")

Expand Down Expand Up @@ -416,11 +412,6 @@ def update_attributes(self) -> None:
mass_player.state = PlayerState.IDLE
self.mass.players.update(self.player_id)

@property
def is_connecting(self):
"""Return true if connection is in progress."""
return self._task is not None

def address_updated(self, address):
"""Update cached address in config entry."""
self.logger.debug("Changing address to %s", address)
Expand Down Expand Up @@ -974,7 +965,7 @@ async def log_watcher(cliraop_proc: AsyncProcess) -> None:
):
extra_args += ["-u"]
if self.mass.config.get_raw_player_config_value(
atv_player.player_id, CONF_ALAC_ENCODE, False
atv_player.player_id, CONF_ALAC_ENCODE, True
):
extra_args += ["-a"]
if self.mass.config.get_raw_player_config_value(
Expand Down
6 changes: 4 additions & 2 deletions music_assistant/server/providers/chromecast/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -527,8 +527,10 @@ def on_new_media_status(self, castplayer: CastPlayer, status: MediaStatus) -> No

# active source
if (
status.content_id and castplayer.player_id in status.content_id
) or castplayer.cc.app_id == pychromecast.config.APP_MEDIA_RECEIVER:
status.content_id
and self.mass.streams.base_url in status.content_id
and castplayer.player_id in status.content_id
):
castplayer.player.active_source = castplayer.player_id
else:
castplayer.player.active_source = castplayer.cc.app_display_name
Expand Down
2 changes: 1 addition & 1 deletion music_assistant/server/providers/chromecast/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ def removed_from_multizone(self, group_uuid) -> None:
if not self._valid:
return
if group_uuid == self.castplayer.player.active_source:
self.castplayer.player.active_source = ""
self.castplayer.player.active_source = None
self.prov.logger.debug(
"%s is removed from multizone: %s", self.castplayer.player.display_name, group_uuid
)
Expand Down
2 changes: 1 addition & 1 deletion music_assistant/server/providers/dlna/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ def get_state(device: DmrDevice) -> PlayerState:
return PlayerState.IDLE

@staticmethod
def get_supported_features(device: DmrDevice) -> set(PlayerFeature):
def get_supported_features(device: DmrDevice) -> set[PlayerFeature]:
"""Get player features that are supported at this moment.
Supported features may change as the device enters different states.
Expand Down
2 changes: 1 addition & 1 deletion music_assistant/server/providers/sonos/player.py
Original file line number Diff line number Diff line change
Expand Up @@ -710,7 +710,7 @@ def _update_attributes(self) -> None:

# media info (track info)
self.mass_player.current_item_id = self.uri
if self.uri and self.player_id in self.uri:
if self.uri and self.mass.streams.base_url in self.uri and self.player_id in self.uri:
self.mass_player.active_source = self.player_id
else:
self.mass_player.active_source = self.source_name
Expand Down
4 changes: 2 additions & 2 deletions music_assistant/server/providers/spotify/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ class SpotifyProvider(MusicProvider):

async def handle_async_init(self) -> None:
"""Handle async initialization of the provider."""
self._throttler = Throttler(rate_limit=1, period=0.1)
self._throttler = Throttler(rate_limit=1, period=1)
self._cache_dir = CACHE_DIR
self._ap_workaround = False
# try to get a token, raise if that fails
Expand Down Expand Up @@ -742,7 +742,7 @@ async def _get_data(self, endpoint, tokeninfo: dict | None = None, **kwargs):
async with self.mass.http_session.get(
url, headers=headers, params=kwargs, ssl=False, timeout=120
) as response:
# get text before json so we can log the body in case of errorrs
# get text before json so we can log the body in case of errors
result = await response.text()
result = json_loads(result)
if "error" in result or ("status" in result and "error" in result["status"]):
Expand Down

0 comments on commit 76dd42e

Please sign in to comment.