From 12d7f6fdd202c38f87242799000ecc9b664f8dc5 Mon Sep 17 00:00:00 2001 From: Matthew Stratford Date: Sun, 14 Feb 2021 13:23:51 +0000 Subject: [PATCH] Fix some queuing issues for playback position timers. --- config.py.example | 1 + player.py | 45 ++++++++++++++++++++++++++++++++++++++++++--- server.py | 20 ++++++-------------- websocket_server.py | 8 +++++--- 4 files changed, 54 insertions(+), 20 deletions(-) diff --git a/config.py.example b/config.py.example index 446a2a4..8fc81fe 100644 --- a/config.py.example +++ b/config.py.example @@ -4,3 +4,4 @@ VERSION: float = 1.0 # API Settings API_KEY: str = "" MYRADIO_BASE_URL: str = "https://ury.org.uk/myradio" +MYRADIO_API_URL: str = "https://ury.org.uk/api" diff --git a/player.py b/player.py index 8f9b153..e2a25ac 100644 --- a/player.py +++ b/player.py @@ -52,6 +52,8 @@ class Player(): last_time_update = None logger = None api = None + already_stopped = False + starting = False __default_state = { "initialised": False, @@ -140,6 +142,9 @@ class Player(): # Audio Playout Related Methods def play(self, pos: float = 0): + global starting + global already_stopped + starting = True try: mixer.music.play(0, pos) mixer.music.set_endevent(PLAYBACK_END) @@ -148,6 +153,8 @@ class Player(): self.logger.log.exception("Failed to play at pos: " + str(pos)) return False self.state.update("paused", False) + + already_stopped = False return True def pause(self): @@ -183,6 +190,9 @@ class Player(): self.state.update("pos_true", 0) self.state.update("paused", False) + global already_stopped + already_stopped = True + return True # return False @@ -316,6 +326,10 @@ class Player(): except: self.logger.log.exception("Failed to update the length of item.") return False + + if self.state.state["play_on_load"]: + self.play() + return True def unload(self): @@ -363,11 +377,29 @@ class Player(): loaded_item = self.state.state["loaded_item"] # check the existing state (not self.isPlaying) # Since this is called multiple times when pygame isn't playing. - if loaded_item == None or not self.isPlaying: + + global starting + + if starting: + print("Starting") + starting = False return - if self.out_q: - self.out_q.put("STOPPED") # Tell clients that we've stopped playing. + + + global already_stopped + + print(already_stopped, self.state.state["remaining"], self.isPlaying) + + if loaded_item == None or already_stopped or (self.state.state["remaining"] > 1): + return + + mixer.music.set_endevent(NOEVENT) + + already_stopped = True + + + stopping = True # Track has ended print("Finished", loaded_item.name) @@ -375,6 +407,7 @@ class Player(): # Repeat 1 if self.state.state["repeat"] == "ONE": self.play() + stopping = False # Auto Advance elif self.state.state["auto_advance"]: @@ -391,6 +424,12 @@ class Player(): # Play on Load if self.state.state["play_on_load"]: self.play() + stopping = False + + if stopping: + self.stop() + if self.out_q: + self.out_q.put("STOPPED") # Tell clients that we've stopped playing. def _updateState(self, pos: Optional[float] = None): diff --git a/server.py b/server.py index d948db7..45e483c 100644 --- a/server.py +++ b/server.py @@ -79,20 +79,12 @@ class PlayerHandler(): for channel in range(len(channel_from_q)): try: message = channel_from_q[channel].get_nowait() + websocket_to_q[channel].put(message) print("Player Handler saw:", message.split(":")[0]) - try: - websocket_to_q[channel].put_nowait(message) - except Exception as e: - print(e) - pass - try: - ui_to_q[channel].put_nowait(message) - except Exception as e: - print(e) - pass + ui_to_q[channel].put(message) except: pass - time.sleep(0.01) + time.sleep(0.1) app = Flask(__name__, static_url_path='') @@ -409,7 +401,7 @@ async def startServer(): channel_to_q.append(multiprocessing.Queue()) channel_from_q.append(multiprocessing.Queue()) ui_to_q.append(multiprocessing.Queue()) - websocket_to_q.append(multiprocessing.Queue()) + websocket_to_q.append(multiprocessing.Manager().Queue()) channel_p.append( multiprocessing.Process( target=player.Player, @@ -422,10 +414,10 @@ async def startServer(): - player_handler = multiprocessing.Process(target=PlayerHandler, args=[channel_from_q, websocket_to_q, ui_to_q]) + player_handler = multiprocessing.Process(target=PlayerHandler, args=(channel_from_q, websocket_to_q, ui_to_q)) player_handler.start() - websockets_server = multiprocessing.Process(target=WebsocketServer, args=[channel_to_q, channel_from_q, state]) + websockets_server = multiprocessing.Process(target=WebsocketServer, args=(channel_to_q, channel_from_q, state)) websockets_server.start() if not isMacOS(): diff --git a/websocket_server.py b/websocket_server.py index ce1a9c2..b5fe526 100644 --- a/websocket_server.py +++ b/websocket_server.py @@ -1,14 +1,14 @@ import asyncio import multiprocessing import queue -from typing import List +from typing import Dict, List, Optional import websockets import json baps_clients = set() -channel_to_q = None +channel_to_q: List[multiprocessing.Queue] webstudio_to_q: List[multiprocessing.Queue] -server_name = None +server_name: str @@ -97,6 +97,8 @@ async def websocket_handler(websocket, path): await asyncio.wait([conn.send(data) for conn in baps_clients]) except queue.Empty: pass + except Exception as e: + raise e await asyncio.sleep(0.01) from_webstudio = asyncio.create_task(handle_from_webstudio())