From: Marcel van der Veldt Date: Thu, 30 Jun 2022 21:38:28 +0000 (+0200) Subject: Centralize polling logic (#390) X-Git-Url: https://git.kitaultman.com/?a=commitdiff_plain;h=e0eeef0beaa94e70dc2de352b60a30bc8181f092;p=music-assistant-server.git Centralize polling logic (#390) Move polling logic to player manager --- diff --git a/music_assistant/controllers/players.py b/music_assistant/controllers/players.py index 425780c8..2ac4b371 100755 --- a/music_assistant/controllers/players.py +++ b/music_assistant/controllers/players.py @@ -1,9 +1,10 @@ """Logic to play music from MusicProviders to supported players.""" from __future__ import annotations +import asyncio from typing import TYPE_CHECKING, Dict, Tuple -from music_assistant.models.enums import EventType +from music_assistant.models.enums import EventType, PlayerState from music_assistant.models.errors import AlreadyRegisteredError from music_assistant.models.event import MassEvent from music_assistant.models.player import Player @@ -13,9 +14,6 @@ if TYPE_CHECKING: from music_assistant.mass import MusicAssistant -DB_TABLE = "queue_settings" - - class PlayerController: """Controller holding all logic to play music from MusicProviders to supported players.""" @@ -28,7 +26,7 @@ class PlayerController: async def setup(self) -> None: """Async initialize of module.""" - # nothing to setup (yet) + self.mass.create_task(self._poll_players()) async def cleanup(self) -> None: """Cleanup on exit.""" @@ -91,3 +89,20 @@ class PlayerController: self.mass.signal_event( MassEvent(EventType.PLAYER_ADDED, object_id=player.player_id, data=player) ) + + async def _poll_players(self) -> None: + """Poll players every X interval.""" + interval = 30 + cur_tick = 0 + while True: + for player in self.players: + if cur_tick == interval or player.state in ( + PlayerState.PLAYING, + PlayerState.PAUSED, + ): + player.update_state() + if cur_tick == interval: + cur_tick = 0 + else: + cur_tick += 1 + await asyncio.sleep(1) diff --git a/music_assistant/models/player.py b/music_assistant/models/player.py index a8003025..43ee4c1e 100755 --- a/music_assistant/models/player.py +++ b/music_assistant/models/player.py @@ -270,6 +270,9 @@ class Player(ABC): """Toggle power on player.""" await self.power(not self.powered) + def on_update(self) -> None: + """Call when player is about to be updated in the player manager.""" + def on_child_update(self, player_id: str, changed_keys: set) -> None: """Call when one of the child players of a playergroup updates.""" self.update_state(skip_forward=True) @@ -296,9 +299,12 @@ class Player(ABC): if self.mass is None or self.mass.closed: # guard return + self.on_update() # basic throttle: do not send state changed events if player did not change cur_state = self.to_dict() - changed_keys = get_changed_keys(self._prev_state, cur_state) + changed_keys = get_changed_keys( + self._prev_state, cur_state, ignore_keys=["elapsed_time"] + ) # always update the playerqueue self.mass.players.get_player_queue(self.player_id).on_player_update() @@ -307,10 +313,9 @@ class Player(ABC): return self._prev_state = cur_state - if changed_keys != {"elapsed_time"}: - self.mass.signal_event( - MassEvent(EventType.PLAYER_UPDATED, object_id=self.player_id, data=self) - ) + self.mass.signal_event( + MassEvent(EventType.PLAYER_UPDATED, object_id=self.player_id, data=self) + ) if skip_forward: return diff --git a/music_assistant/models/player_queue.py b/music_assistant/models/player_queue.py index e6b25f53..ea3e5b8e 100644 --- a/music_assistant/models/player_queue.py +++ b/music_assistant/models/player_queue.py @@ -5,7 +5,7 @@ import asyncio import os import pathlib import random -from asyncio import Task, TimerHandle +from asyncio import TimerHandle from dataclasses import dataclass from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Union @@ -62,7 +62,6 @@ class PlayerQueue: self._last_state = str self._items: List[QueueItem] = [] self._save_task: TimerHandle = None - self._update_task: Task = None self._last_player_update: int = 0 self._last_stream_id: str = "" self._snapshot: Optional[QueueSnapShot] = None @@ -595,20 +594,6 @@ class PlayerQueue: self.signal_next = False self.mass.create_task(self.resume()) - # start poll/updater task if playback starts on player - async def updater() -> None: - """Update player queue every second while playing.""" - while True: - await asyncio.sleep(1) - self.update_state() - - if self.player.state == PlayerState.PLAYING and self.active: - if not self._update_task or self._update_task.done(): - self._update_task = self.mass.create_task(updater) - elif self._update_task: - self._update_task.cancel() - self._update_task = None - self.update_state() def update_state(self) -> None: