From: Marcel van der Veldt Date: Sat, 28 Nov 2020 23:20:31 +0000 (+0100) Subject: another fix for chromecast stability X-Git-Url: https://git.kitaultman.com/?a=commitdiff_plain;h=d0585c341fd9777220272f0425bc7dd07d0f1d89;p=music-assistant-server.git another fix for chromecast stability --- diff --git a/music_assistant/providers/chromecast/__init__.py b/music_assistant/providers/chromecast/__init__.py index f09d52ad..e0ec0751 100644 --- a/music_assistant/providers/chromecast/__init__.py +++ b/music_assistant/providers/chromecast/__init__.py @@ -94,7 +94,7 @@ class ChromecastProvider(PlayerProvider): if not player: player = ChromecastPlayer(self.mass, cast_info) # if player was already added, it player will take care of reconnects itself. - self.mass.add_job(player.set_cast_info, cast_info) + self.mass.add_job(player.async_set_cast_info, cast_info) self.mass.add_job(self.mass.players.async_add_player(player)) @staticmethod @@ -104,4 +104,4 @@ class ChromecastProvider(PlayerProvider): player_id = str(cast_service[1]) friendly_name = cast_service[3] LOGGER.debug("Chromecast removed: %s - %s", friendly_name, player_id) - # we ignore this event completely as the Chromecast socket clients handles this on its own + # we ignore this event completely as the Chromecast socket client handles this itself diff --git a/music_assistant/providers/chromecast/player.py b/music_assistant/providers/chromecast/player.py index c85529b8..d65f9707 100644 --- a/music_assistant/providers/chromecast/player.py +++ b/music_assistant/providers/chromecast/player.py @@ -54,7 +54,7 @@ class ChromecastPlayer(Player): self._available = False self._status_listener: Optional[CastStatusListener] = None self._is_speaker_group = False - self._throttler = Throttler(rate_limit=2, period=1) + self._throttler = Throttler(rate_limit=1, period=0.25) @property def player_id(self) -> str: @@ -192,22 +192,20 @@ class ChromecastPlayer(Player): """Return player specific config entries (if any).""" return PLAYER_CONFIG_ENTRIES - def set_cast_info(self, cast_info: ChromecastInfo) -> None: + async def async_set_cast_info(self, cast_info: ChromecastInfo) -> None: """Set the cast information and set up the chromecast object.""" self._cast_info = cast_info - if self._chromecast and not self._available: - try: - self.disconnect() - except Exception: # pylint: disable=broad-except - pass - elif self._chromecast is not None: + # Only setup the chromecast once, changes will automatically be picked up. + if self._chromecast is not None: return LOGGER.debug( "[%s] Connecting to cast device by service %s", self._cast_info.friendly_name, self.services, ) - chromecast = pychromecast.get_chromecast_from_service( + chromecast = await self.mass.loop.run_in_executor( + None, + pychromecast.get_chromecast_from_service, ( self.services, cast_info.uuid, @@ -230,20 +228,23 @@ class ChromecastPlayer(Player): chromecast.mz_controller = mz_controller self._chromecast.start() - def disconnect(self) -> None: + async def async_disconnect(self): """Disconnect Chromecast object if it is set.""" - self._available = False if self._chromecast is None: + # Can't disconnect if not connected. return - LOGGER.warning( - "[%s] Disconnecting from chromecast socket", self._cast_info.friendly_name + LOGGER.debug( + "[%s %s] Disconnecting from chromecast socket", + self.player_id, + self._cast_info.friendly_name, ) - if ( - self._chromecast.socket_client - and not self._chromecast.socket_client.is_stopped - ): - self._chromecast.disconnect() + self._available = False + self.update_state() + + await self.mass.loop.run_in_executor(None, self._chromecast.disconnect) + self._invalidate() + self.update_state() def _invalidate(self) -> None: """Invalidate some attributes.""" @@ -258,7 +259,7 @@ class ChromecastPlayer(Player): async def async_on_remove(self) -> None: """Call when player is removed from the player manager.""" - self.mass.add_job(self.disconnect) + await self.async_disconnect() # ========== Callbacks ========== @@ -301,7 +302,7 @@ class ChromecastPlayer(Player): self._available = new_available self.update_state() if self._cast_info.is_audio_group and new_available: - self.chromecast_command(self._chromecast.mz_controller.update_members) + self.mass.add_job(self._chromecast.mz_controller.update_members) async def async_on_update(self) -> None: """Call when player is periodically polled by the player manager (should_poll=True).""" @@ -406,11 +407,7 @@ class ChromecastPlayer(Player): def __create_queue_items(self, tracks) -> None: """Create list of CC queue items from tracks.""" - queue_items = [] - for track in tracks: - queue_item = self.__create_queue_item(track) - queue_items.append(queue_item) - return queue_items + return [self.__create_queue_item(track) for track in tracks] def __create_queue_item(self, track): """Create CC queue item from track info.""" @@ -458,10 +455,6 @@ class ChromecastPlayer(Player): else: send_queue() - def chromecast_command(self, func, *args, **kwargs): - """Try to execute Chromecast command.""" - self.mass.add_job(self.async_chromecast_command(func, *args, **kwargs)) - async def async_chromecast_command(self, func, *args, **kwargs): """Execute command on Chromecast.""" # Chromecast socket really doesn't like multiple commands arriving at the same time