From: Marcel van der Veldt Date: Sat, 10 Oct 2020 21:25:46 +0000 (+0200) Subject: throttle commands to chromecast socket X-Git-Url: https://git.kitaultman.com/?a=commitdiff_plain;h=5d6b46cd0d934860bae1726cfae7b39607b68a07;p=music-assistant-server.git throttle commands to chromecast socket --- diff --git a/music_assistant/providers/chromecast/player.py b/music_assistant/providers/chromecast/player.py index f2d718ff..7349a15a 100644 --- a/music_assistant/providers/chromecast/player.py +++ b/music_assistant/providers/chromecast/player.py @@ -5,6 +5,7 @@ from datetime import datetime from typing import List, Optional import pychromecast +from asyncio_throttle import Throttler from music_assistant.helpers.typing import MusicAssistantType from music_assistant.helpers.util import async_yield_chunks, compare_strings from music_assistant.models.config_entry import ConfigEntry @@ -52,6 +53,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) @property def player_id(self) -> str: @@ -195,8 +197,8 @@ class ChromecastPlayer(Player): if self._chromecast and not self._available: try: self.disconnect() - except Exception as exc: # pylint: disable=broad-except - LOGGER.exception(exc) + except Exception: # pylint: disable=broad-except + pass elif self._chromecast is not None: return LOGGER.debug( @@ -298,7 +300,7 @@ class ChromecastPlayer(Player): self._available = new_available self.update_state() if self._cast_info.is_audio_group and new_available: - self.try_chromecast_command( + self.__try_chromecast_command( self._chromecast.mz_controller.update_members ) @@ -308,7 +310,9 @@ class ChromecastPlayer(Player): "group_player" ): # the group player wants very accurate elapsed_time state so we request it very often - self.try_chromecast_command(self._chromecast.media_controller.update_status) + await self.__async_try_chromecast_command( + self._chromecast.media_controller.update_status + ) self.update_state() # ========== Service Calls ========== @@ -316,31 +320,43 @@ class ChromecastPlayer(Player): async def async_cmd_stop(self) -> None: """Send stop command to player.""" if self._chromecast and self._chromecast.media_controller: - self.try_chromecast_command(self._chromecast.media_controller.stop) + await self.__async_try_chromecast_command( + self._chromecast.media_controller.stop + ) async def async_cmd_play(self) -> None: """Send play command to player.""" if self._chromecast.media_controller: - self.try_chromecast_command(self._chromecast.media_controller.play) + await self.__async_try_chromecast_command( + self._chromecast.media_controller.play + ) async def async_cmd_pause(self) -> None: """Send pause command to player.""" if self._chromecast.media_controller: - self.try_chromecast_command(self._chromecast.media_controller.pause) + await self.__async_try_chromecast_command( + self._chromecast.media_controller.pause + ) async def async_cmd_next(self) -> None: """Send next track command to player.""" if self._chromecast.media_controller: - self.try_chromecast_command(self._chromecast.media_controller.queue_next) + await self.__async_try_chromecast_command( + self._chromecast.media_controller.queue_next + ) async def async_cmd_previous(self) -> None: """Send previous track command to player.""" if self._chromecast.media_controller: - self.try_chromecast_command(self._chromecast.media_controller.queue_prev) + await self.__async_try_chromecast_command( + self._chromecast.media_controller.queue_prev + ) async def async_cmd_power_on(self) -> None: """Send power ON command to player.""" - self.try_chromecast_command(self._chromecast.set_volume_muted, False) + await self.__async_try_chromecast_command( + self._chromecast.set_volume_muted, False + ) async def async_cmd_power_off(self) -> None: """Send power OFF command to player.""" @@ -349,17 +365,25 @@ class ChromecastPlayer(Player): or self.media_status.player_is_paused or self.media_status.player_is_idle ): - self.try_chromecast_command(self._chromecast.media_controller.stop) + await self.__async_try_chromecast_command( + self._chromecast.media_controller.stop + ) # chromecast has no real poweroff so we send mute instead - self.try_chromecast_command(self._chromecast.set_volume_muted, True) + await self.__async_try_chromecast_command( + self._chromecast.set_volume_muted, True + ) async def async_cmd_volume_set(self, volume_level: int) -> None: """Send new volume level command to player.""" - self.try_chromecast_command(self._chromecast.set_volume, volume_level / 100) + await self.__async_try_chromecast_command( + self._chromecast.set_volume, volume_level / 100 + ) async def async_cmd_volume_mute(self, is_muted: bool = False) -> None: """Send mute command to player.""" - self.try_chromecast_command(self._chromecast.set_volume_muted, is_muted) + await self.__async_try_chromecast_command( + self._chromecast.set_volume_muted, is_muted + ) async def async_cmd_play_uri(self, uri: str) -> None: """Play single uri on player.""" @@ -370,7 +394,9 @@ class ChromecastPlayer(Player): queue_item.name = "Music Assistant" queue_item.uri = uri return await self.async_cmd_queue_load([queue_item, queue_item]) - self.try_chromecast_command(self._chromecast.play_media, uri, "audio/flac") + await self.__async_try_chromecast_command( + self._chromecast.play_media, uri, "audio/flac" + ) async def async_cmd_queue_load(self, queue_items: List[QueueItem]) -> None: """Load (overwrite) queue with new items.""" @@ -385,7 +411,7 @@ class ChromecastPlayer(Player): "startIndex": 0, # Item index to play after this request or keep same item if undefined "items": cc_queue_items, # only load 50 tracks at once or the socket will crash } - self.try_chromecast_command(self.__send_player_queue, queuedata) + await self.__async_try_chromecast_command(self.__send_player_queue, queuedata) if len(queue_items) > 50: await self.async_cmd_queue_append(queue_items[51:]) @@ -398,7 +424,9 @@ class ChromecastPlayer(Player): "insertBefore": None, "items": chunk, } - self.try_chromecast_command(self.__send_player_queue, queuedata) + await self.__async_try_chromecast_command( + self.__send_player_queue, queuedata + ) def __create_queue_items(self, tracks) -> None: """Create list of CC queue items from tracks.""" @@ -454,7 +482,11 @@ class ChromecastPlayer(Player): else: send_queue() - def try_chromecast_command(self, func, *args, **kwargs): + async def __try_chromecast_command(self, func, *args, **kwargs): + """Try to execute Chromecast command.""" + self.mass.add_job(self.__async_try_chromecast_command(func, *args, **kwargs)) + + async def __async_try_chromecast_command(self, func, *args, **kwargs): """Try to execute Chromecast command.""" def handle_command(func, *args, **kwarg): @@ -464,16 +496,20 @@ class ChromecastPlayer(Player): or not self._available ): LOGGER.error( - "Error while executing command on player %s: Chromecast is not available!" + "Error while executing command %s on player %s: Chromecast is not available!", + func.__name__, + self.name, ) + return try: return func(*args, **kwargs) except ( pychromecast.NotConnected, pychromecast.ChromecastConnectionError, ) as exc: - LOGGER.error( - "Error while executing command on player %s: %s", + LOGGER.warning( + "Error while executing command %s on player %s: %s", + func.__name__, self.name, str(exc), ) @@ -481,4 +517,5 @@ class ChromecastPlayer(Player): except Exception as exc: # pylint: disable=broad-except LOGGER.exception(exc) - self.mass.add_job(handle_command, func, *args, **kwargs) + async with self._throttler: + self.mass.add_job(handle_command, func, *args, **kwargs)