Skip to content

Commit b70d07b

Browse files
committed
fix issues with chromecast
1 parent 45e7164 commit b70d07b

File tree

7 files changed

+653
-45
lines changed

7 files changed

+653
-45
lines changed

music_assistant/config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ def __setitem__(self, key, value):
252252
self.mass.get_provider(self._parent_item_key).async_on_reload()
253253
)
254254
if self._base_type == ConfigBaseType.PLAYER:
255-
255+
# force update of player if it's config changed
256256
player = self.mass.player_manager.get_player(self._parent_item_key)
257257
if player:
258258
self.mass.add_job(

music_assistant/constants.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""All constants for Music Assistant."""
22

3-
__version__ = "0.0.36"
3+
__version__ = "0.0.37"
44
REQUIRED_PYTHON_VER = "3.7"
55

66
CONF_USERNAME = "username"

music_assistant/models/player_queue.py

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,10 @@ def __init__(self, media_item=None):
5454
class PlayerQueue:
5555
"""Class that holds the queue items for a player."""
5656

57-
def __init__(self, mass, player):
57+
def __init__(self, mass, player_id: str):
5858
"""Initialize class."""
5959
self.mass = mass
60-
self._player = player
60+
self._player_id = player_id
6161
self._items = []
6262
self._shuffle_enabled = False
6363
self._repeat_enabled = False
@@ -78,12 +78,12 @@ async def async_close(self):
7878
@property
7979
def player(self):
8080
"""Return handle to player."""
81-
return self._player
81+
return self.mass.player_manager.get_player(self._player_id)
8282

8383
@property
8484
def player_id(self):
8585
"""Return handle to player."""
86-
return self._player.player_id
86+
return self._player_id
8787

8888
@property
8989
def shuffle_enabled(self):
@@ -213,9 +213,21 @@ def use_queue_stream(self):
213213
For example if crossfading is requested but a player doesn't natively support it
214214
we will send a constant stream of audio to the player with all tracks.
215215
"""
216-
supports_crossfade = PlayerFeature.CROSSFADE in self.player.features
217-
supports_queue = PlayerFeature.QUEUE in self.player.features
218-
return not supports_crossfade if self.crossfade_enabled else not supports_queue
216+
return (
217+
not self.supports_crossfade
218+
if self.crossfade_enabled
219+
else not self.supports_queue
220+
)
221+
222+
@property
223+
def supports_queue(self):
224+
"""Return if this player supports native queue."""
225+
return PlayerFeature.QUEUE in self.player.features
226+
227+
@property
228+
def supports_crossfade(self):
229+
"""Return if this player supports native crossfade."""
230+
return PlayerFeature.CROSSFADE in self.player.features
219231

220232
@callback
221233
def get_item(self, index):
@@ -240,7 +252,6 @@ async def async_next(self):
240252
return
241253
if self.use_queue_stream:
242254
return await self.async_play_index(self.cur_index + 1)
243-
await self.mass.player_manager.async_cmd_power_on(self.player_id)
244255
return await self.mass.player_manager.get_player_provider(
245256
self.player_id
246257
).async_cmd_next(self.player_id)
@@ -249,18 +260,15 @@ async def async_previous(self):
249260
"""Play the previous track in the queue."""
250261
if self.cur_index is None:
251262
return
252-
await self.mass.player_manager.async_cmd_power_on(self.player_id)
253263
if self.use_queue_stream:
254264
return await self.async_play_index(self.cur_index - 1)
255265
return await self.mass.player_manager.async_cmd_previous(self.player_id)
256266

257267
async def async_resume(self):
258268
"""Resume previous queue."""
259269
if self.items:
260-
await self.mass.player_manager.async_cmd_power_on(self.player_id)
261270
prev_index = self.cur_index
262-
supports_queue = PlayerFeature.QUEUE in self.player.features
263-
if self.use_queue_stream or not supports_queue:
271+
if self.use_queue_stream or not self.supports_queue:
264272
await self.async_play_index(prev_index)
265273
else:
266274
# at this point we don't know if the queue is synced with the player
@@ -272,14 +280,12 @@ async def async_resume(self):
272280
await self.async_play_index(prev_index)
273281
else:
274282
LOGGER.warning(
275-
"resume queue requested for %s but queue is empty", self.player.name
283+
"resume queue requested for %s but queue is empty", self.player_id
276284
)
277285

278286
async def async_play_index(self, index):
279287
"""Play item at index X in queue."""
280-
await self.mass.player_manager.async_cmd_power_on(self.player_id)
281288
player_prov = self.mass.player_manager.get_player_provider(self.player_id)
282-
supports_queue = PlayerFeature.QUEUE in self.player.features
283289
if not isinstance(index, int):
284290
index = self.__index_by_id(index)
285291
if not len(self.items) > index:
@@ -297,7 +303,7 @@ async def async_play_index(self, index):
297303
return await player_prov.async_cmd_play_uri(
298304
self.player_id, queue_stream_uri
299305
)
300-
if supports_queue:
306+
if self.supports_queue:
301307
try:
302308
return await player_prov.async_cmd_queue_play_index(
303309
self.player_id, index
@@ -342,14 +348,12 @@ async def async_move_item(self, queue_item_id, pos_shift=1):
342348

343349
async def async_load(self, queue_items: List[QueueItem]):
344350
"""Load (overwrite) queue with new items."""
345-
await self.mass.player_manager.async_cmd_power_on(self.player_id)
346-
supports_queue = PlayerFeature.QUEUE in self.player.features
347351
for index, item in enumerate(queue_items):
348352
item.sort_index = index
349353
if self._shuffle_enabled:
350354
queue_items = self.__shuffle_items(queue_items)
351355
self._items = queue_items
352-
if self.use_queue_stream or not supports_queue:
356+
if self.use_queue_stream or not self.supports_queue:
353357
await self.async_play_index(0)
354358
else:
355359
player_prov = self.mass.player_manager.get_player_provider(self.player_id)
@@ -366,7 +370,6 @@ async def async_insert(self, queue_items: List[QueueItem], offset=0):
366370
:param queue_items: a list of QueueItem
367371
:param offset: offset from current queue position
368372
"""
369-
supports_queue = PlayerFeature.QUEUE in self.player.features
370373

371374
if (
372375
not self.items
@@ -393,7 +396,7 @@ async def async_insert(self, queue_items: List[QueueItem], offset=0):
393396
+ queue_items
394397
+ self._items[insert_at_index:]
395398
)
396-
if self.use_queue_stream or not supports_queue:
399+
if self.use_queue_stream:
397400
if offset == 0:
398401
await self.async_play_index(insert_at_index)
399402
else:
@@ -417,7 +420,6 @@ async def async_insert(self, queue_items: List[QueueItem], offset=0):
417420

418421
async def async_append(self, queue_items: List[QueueItem]):
419422
"""Append new items at the end of the queue."""
420-
supports_queue = PlayerFeature.QUEUE in self.player.features
421423
for index, item in enumerate(queue_items):
422424
item.sort_index = len(self.items) + index
423425
if self.shuffle_enabled:
@@ -427,7 +429,7 @@ async def async_append(self, queue_items: List[QueueItem]):
427429
items = played_items + [self.cur_item] + next_items
428430
return await self.async_update(items)
429431
self._items = self._items + queue_items
430-
if supports_queue and not self.use_queue_stream:
432+
if self.supports_queue and not self.use_queue_stream:
431433
# send queue to player's own implementation
432434
player_prov = self.mass.player_manager.get_player_provider(self.player_id)
433435
try:
@@ -446,9 +448,8 @@ async def async_append(self, queue_items: List[QueueItem]):
446448

447449
async def async_update(self, queue_items: List[QueueItem]):
448450
"""Update the existing queue items, mostly caused by reordering."""
449-
supports_queue = PlayerFeature.QUEUE in self.player.features
450451
self._items = queue_items
451-
if supports_queue and not self.use_queue_stream:
452+
if self.supports_queue and not self.use_queue_stream:
452453
# send queue to player's own implementation
453454
player_prov = self.mass.player_manager.get_player_provider(self.player_id)
454455
try:
@@ -467,10 +468,9 @@ async def async_update(self, queue_items: List[QueueItem]):
467468

468469
async def async_clear(self):
469470
"""Clear all items in the queue."""
470-
supports_queue = PlayerFeature.QUEUE in self.player.features
471471
await self.mass.player_manager.async_cmd_stop(self.player_id)
472472
self._items = []
473-
if supports_queue:
473+
if self.supports_queue:
474474
# send queue cmd to player's own implementation
475475
player_prov = self.mass.player_manager.get_player_provider(self.player_id)
476476
try:

music_assistant/player_manager.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,9 +98,8 @@ def providers(self) -> List[PlayerProvider]:
9898
def get_player(self, player_id: str) -> Player:
9999
"""Return player by player_id or None if player does not exist."""
100100
player = self._players.get(player_id)
101-
if not player or not player.available:
101+
if not player:
102102
LOGGER.warning("Player %s is not available!", player_id)
103-
return None
104103
return player
105104

106105
@callback
@@ -147,7 +146,9 @@ async def async_add_player(self, player: Player) -> None:
147146
if is_new_player:
148147
# create player queue
149148
if player.player_id not in self._player_queues:
150-
self._player_queues[player.player_id] = PlayerQueue(self.mass, player)
149+
self._player_queues[player.player_id] = PlayerQueue(
150+
self.mass, player.player_id
151+
)
151152
# TODO: turn on player if it was previously turned on ?
152153
LOGGER.info(
153154
"New player added: %s/%s",

music_assistant/providers/chromecast/__init__.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,13 @@ async def async_on_start(self) -> bool:
5959
self.__chromecast_remove_callback,
6060
self.__chromecast_add_update_callback,
6161
)
62-
self._browser = pychromecast.discovery.start_discovery(
63-
self._listener, self.mass.zeroconf
64-
)
62+
63+
def start_discovery():
64+
self._browser = pychromecast.discovery.start_discovery(
65+
self._listener, self.mass.zeroconf
66+
)
67+
68+
self.mass.add_job(start_discovery)
6569
return True
6670

6771
async def async_on_stop(self):
@@ -76,7 +80,7 @@ async def async_on_stop(self):
7680

7781
async def async_cmd_play_uri(self, player_id: str, uri: str):
7882
"""
79-
Play the specified uri/url on the goven player.
83+
Play the specified uri/url on the given player.
8084
8185
:param player_id: player_id of the player to handle the command.
8286
"""
@@ -191,15 +195,13 @@ def __chromecast_add_update_callback(self, cast_uuid, cast_service_name):
191195
port=service[5],
192196
)
193197
player_id = cast_info.uuid
194-
LOGGER.debug(
195-
"Chromecast discovered: %s (%s)", cast_info.friendly_name, player_id
196-
)
197198
if player_id in self._players:
198199
# player already added, the player will take care of reconnects itself.
200+
return
201+
else:
199202
LOGGER.debug(
200-
"Player is already added: %s (%s)", cast_info.friendly_name, player_id
203+
"Chromecast discovered: %s (%s)", cast_info.friendly_name, player_id
201204
)
202-
else:
203205
player = ChromecastPlayer(self.mass, cast_info)
204206
self._players[player_id] = player
205207
self.mass.add_job(self.mass.player_manager.async_add_player(player))

music_assistant/providers/chromecast/player.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,6 @@ def _invalidate(self):
210210

211211
def new_cast_status(self, cast_status):
212212
"""Handle updates of the cast status."""
213-
LOGGER.debug("received cast status for %s", self.name)
214213
self.cast_status = cast_status
215214
self._is_speaker_group = (
216215
self._cast_info.is_audio_group
@@ -224,15 +223,13 @@ def new_cast_status(self, cast_status):
224223

225224
def new_media_status(self, media_status):
226225
"""Handle updates of the media status."""
227-
LOGGER.debug("received media_status for %s", self.name)
228226
self.media_status = media_status
229227
self.mass.add_job(self.mass.player_manager.async_update_player(self))
230228
if media_status.player_is_playing:
231229
self._powered = True
232230

233231
def new_connection_status(self, connection_status):
234232
"""Handle updates of connection status."""
235-
LOGGER.debug("received connection_status for %s", self._cast_info.friendly_name)
236233
if connection_status.status == CONNECTION_STATUS_DISCONNECTED:
237234
self._available = False
238235
self._invalidate()
@@ -305,7 +302,9 @@ def power_off(self):
305302
LOGGER.warning("Ignore player command: Socket client is not connected.")
306303
return
307304
if self.media_status and (
308-
self.media_status.player_is_playing or self.media_status.player_is_paused
305+
self.media_status.player_is_playing
306+
or self.media_status.player_is_paused
307+
or self.media_status.player_is_idle
309308
):
310309
self._chromecast.media_controller.stop()
311310
self._powered = False

0 commit comments

Comments
 (0)