self.domain, f"default_enqueue_action_{media_item.media_type.value}"
)
)
+ # clear queue if needed
+ if option == QueueOption.REPLACE:
+ self.clear(queue_id)
# collect tracks to play
ctrl = self.mass.music.get_controller(media_item.media_type)
# overwrite or append radio source items
if option not in (QueueOption.ADD, QueueOption.PLAY, QueueOption.NEXT):
- queue.radio_source = radio_mode
+ queue.radio_source = radio_source
else:
- queue.radio_source += radio_mode
+ queue.radio_source += radio_source
# Use collected media items to calculate the radio if radio mode is on
if radio_mode:
tracks = await self._get_radio_tracks(queue_id)
# handle replace: clear all items and replace with the new items
if option == QueueOption.REPLACE:
- self.clear(queue_id)
self.load(
queue_id,
queue_items=queue_items,
)
# handle syncgroup - get attributes from first player that has this group as source
if player.player_id.startswith(SYNCGROUP_PREFIX):
- if sync_leader := self.get_sync_leader(player):
+ if player.powered and (sync_leader := self.get_sync_leader(player)):
player.state = sync_leader.state
player.current_item_id = sync_leader.current_item_id
player.elapsed_time = sync_leader.elapsed_time
# - every 30 seconds if the player is powered
# - every 10 seconds if the player is playing
if (
- (player.available or count == 360)
- and (
- (player.powered and count % 30 == 0)
- or (player_playing and count % 10 == 0)
- or count == 360
- )
- and (player_prov := self.get_player_provider(player_id))
- ):
+ (player.powered and count % 30 == 0)
+ or (player_playing and count % 10 == 0)
+ or count == 360
+ ) and (player_prov := self.get_player_provider(player_id)):
try:
await player_prov.poll_player(player_id)
except PlayerUnavailableError:
) -> tuple[ConfigEntry, ...]:
"""Return Config Entries for the given player."""
base_entries = await super().get_player_config_entries(player_id)
- if not (sonos_player := self.sonosplayers.get(player_id)):
- return base_entries
return base_entries + (
CONF_ENTRY_CROSSFADE,
ConfigEntry(
default_value=0,
range=(-10, 10),
description="Set the Bass level for the Sonos player",
- value=sonos_player.soco.bass,
advanced=True,
),
ConfigEntry(
default_value=0,
range=(-10, 10),
description="Set the Treble level for the Sonos player",
- value=sonos_player.soco.treble,
advanced=True,
),
ConfigEntry(
label="Loudness compensation",
default_value=True,
description="Enable loudness compensation on the Sonos player",
- value=sonos_player.soco.loudness,
advanced=True,
),
)
player_id,
)
return
- await asyncio.to_thread(sonos_player.soco.stop)
+ await self.mass.create_task(sonos_player.soco.stop)
async def cmd_play(self, player_id: str) -> None:
"""Send PLAY command to given player."""
player_id,
)
return
- await asyncio.to_thread(sonos_player.soco.play)
+ await self.mass.create_task(sonos_player.soco.play)
async def cmd_pause(self, player_id: str) -> None:
"""Send PAUSE command to given player."""
# pause not possible
await self.cmd_stop(player_id)
return
- await asyncio.to_thread(sonos_player.soco.pause)
+ await self.mass.create_task(sonos_player.soco.pause)
async def cmd_volume_set(self, player_id: str, volume_level: int) -> None:
"""Send VOLUME_SET command to given player."""
sonos_player = self.sonosplayers[player_id]
sonos_player.soco.volume = volume_level
- await asyncio.to_thread(set_volume_level, player_id, volume_level)
+ await self.mass.create_task(set_volume_level, player_id, volume_level)
async def cmd_volume_mute(self, player_id: str, muted: bool) -> None:
"""Send VOLUME MUTE command to given player."""
sonos_player = self.sonosplayers[player_id]
sonos_player.soco.mute = muted
- await asyncio.to_thread(set_volume_mute, player_id, muted)
+ await self.mass.create_task(set_volume_mute, player_id, muted)
async def cmd_sync(self, player_id: str, target_player: str) -> None:
"""Handle SYNC command for given player.
"accept play_media command, it is synced to another player."
)
metadata = create_didl_metadata(self.mass, url, queue_item)
- self.mass.create_task(sonos_player.soco.play_uri, url, meta=metadata)
+ await self.mass.create_task(sonos_player.soco.play_uri, url, meta=metadata)
async def play_stream(self, player_id: str, stream_job: MultiClientStreamJob) -> None:
"""Handle PLAY STREAM on given player.
)
# set crossfade according to player setting
crossfade = await self.mass.config.get_player_config_value(player_id, CONF_CROSSFADE)
- if sonos_player.soco.cross_fade != crossfade:
+ if sonos_player.crossfade != crossfade:
def set_crossfade():
with suppress(Exception):
sonos_player.soco.cross_fade = crossfade
+ sonos_player.crossfade = crossfade
await asyncio.to_thread(set_crossfade)
self.mass_player: Player = mass_player
self.available: bool = True
# cached attributes
+ self.crossfade: bool = False
self.play_mode: str | None = None
self.playback_status: str | None = None
self.channel: str | None = None
def setup(self) -> None:
"""Run initial setup of the speaker (NOT async friendly)."""
- # update volume
+ self.crossfade = self.soco.cross_fade
self.mass_player.volume_level = self.soco.volume
self.mass_player.volume_muted = self.soco.mute
+ self.mass.loop.call_soon_threadsafe(
+ self.mass.config.set_raw_player_config_value,
+ self.player_id,
+ "sonos_loudness",
+ self.soco.loudness,
+ )
+ self.mass.loop.call_soon_threadsafe(
+ self.mass.config.set_raw_player_config_value,
+ self.player_id,
+ "sonos_bass",
+ self.soco.bass,
+ )
+ self.mass.loop.call_soon_threadsafe(
+ self.mass.config.set_raw_player_config_value,
+ self.player_id,
+ "sonos_treble",
+ self.soco.treble,
+ )
self.update_groups()
if not self.sync_coordinator:
self.poll_media()
return
if crossfade := event.variables.get("current_crossfade_mode"):
- self.logger.debug("crossfade changed to %s", crossfade)
+ self.crossfade = bool(int(crossfade))
# Missing transport_state indicates a transient error
if (new_status := event.variables.get("transport_state")) is None:
if loudness := variables.get("loudness"):
# TODO: handle this is a better way
- self.mass.config.set_raw_player_config_value(
- self.player_id, "sonos_loudness", loudness["Master"] == "1"
+ self.mass.loop.call_soon_threadsafe(
+ self.mass.config.set_raw_player_config_value,
+ self.player_id,
+ "sonos_loudness",
+ loudness["Master"] == "1",
)
for int_var in (
):
if int_var in variables:
# TODO: handle this is a better way
- self.mass.config.set_raw_player_config_value(
- self.player_id, f"sonos_{int_var}", variables[int_var]
+ self.mass.loop.call_soon_threadsafe(
+ self.mass.config.set_raw_player_config_value,
+ self.player_id,
+ f"sonos_{int_var}",
+ variables[int_var],
)
self.update_player()
# zone topology (syncing/grouping) details
self.mass_player.can_sync_with = tuple(
- x.player_id for x in self.sonos_prov.sonosplayers.values() if x.sync_coordinator is None
+ x.player_id
+ for x in self.sonos_prov.sonosplayers.values()
+ if x.sync_coordinator is None and x.player_id != self.player_id
)
if self.sync_coordinator:
# player is syned to another player