Some small fixes (#386)
authorMarcel van der Veldt <m.vanderveldt@outlook.com>
Fri, 24 Jun 2022 18:35:43 +0000 (20:35 +0200)
committerGitHub <noreply@github.com>
Fri, 24 Jun 2022 18:35:43 +0000 (20:35 +0200)
- another fix for reconnecting Kodi players
- fix for passive playback start

music_assistant/controllers/streams.py
music_assistant/models/player_queue.py

index d3567dc8c772d5b9c90379761c78a49ed24c10b9..294557adf306445a23895e38b8eced5b8ba12c45 100644 (file)
@@ -187,7 +187,10 @@ class StreamsController:
         }
 
         resp = web.StreamResponse(headers=headers)
-        await resp.prepare(request)
+        try:
+            await resp.prepare(request)
+        except ConnectionResetError:
+            return resp
 
         if request.method != "GET":
             # do not start stream on HEAD request
@@ -347,7 +350,7 @@ class QueueStream:
         self.signal_next: bool = False
         self.chunk_size = get_chunksize(output_format)
         self._runner_task: Optional[asyncio.Task] = None
-        self._prev_chunks: Dict[str, bytes] = {}
+        self._prev_chunk: bytes = b""
         if autostart:
             self.mass.create_task(self.start())
 
@@ -365,7 +368,7 @@ class QueueStream:
 
         self._runner_task = None
         self.connected_clients = {}
-        self._prev_chunks = {}
+        self._prev_chunk = b""
 
         # run garbage collection manually due to the high number of
         # processed bytes blocks
@@ -375,18 +378,23 @@ class QueueStream:
 
     async def subscribe(self, client_id: str, callback: CoroutineType[bytes]) -> None:
         """Subscribe callback and wait for completion."""
-        assert client_id not in self.connected_clients, "Client is already connected"
         assert not self.done.is_set(), "Stream task is already finished"
+        if client_id in self.connected_clients:
+            self.logger.warning(
+                "Simultanuous connections detected from %s, playback may be disturbed",
+                client_id,
+            )
+            client_id += uuid4().hex
+
         self.connected_clients[client_id] = callback
         self.logger.debug("client connected: %s", client_id)
         if len(self.connected_clients) == self.expected_clients:
             self.all_clients_connected.set()
 
-        if client_id in self._prev_chunks:
-            self.logger.warning(
-                "Reconnect of player %s detected, playback may be disturbed", client_id
-            )
-            await callback(self._prev_chunks[client_id])
+        # workaround for reconnecting clients (such as kodi)
+        # send the previous chunk if we have one
+        if self._prev_chunk:
+            await callback(self._prev_chunk)
         try:
             await self.done.wait()
         finally:
@@ -465,7 +473,7 @@ class QueueStream:
                     if await self._check_stop():
                         return
                 for client_id in set(self.connected_clients.keys()):
-                    self._prev_chunks[client_id] = chunk
+                    self._prev_chunk = chunk
                     try:
                         callback = self.connected_clients[client_id]
                         await callback(chunk)
index 1b2d315b3980cda1edb9ab92b2a39a1a9aabd8d9..8c70d82bc14af78e970e60d159ca251ee34e8a34 100644 (file)
@@ -310,7 +310,11 @@ class PlayerQueue:
 
         # start queue with alert sound(s)
         self._items = queue_items
-        await self.queue_stream_start(0, 0, False, is_alert=True)
+        stream = await self.queue_stream_start(
+            start_index=0, seek_position=0, fade_in=False, is_alert=True
+        )
+        # execute the play command on the player(s)
+        await self.player.play_url(stream.url)
 
         # wait for the player to finish playing
         play_started = asyncio.Event()
@@ -461,7 +465,15 @@ class PlayerQueue:
             return
         self._current_index = index
         # start the queue stream
-        await self.queue_stream_start(index, int(seek_position), fade_in, passive)
+        stream = await self.queue_stream_start(
+            start_index=index,
+            seek_position=int(seek_position),
+            fade_in=fade_in,
+            passive=passive,
+        )
+        # execute the play command on the player(s)
+        if not passive:
+            await self.player.play_url(stream.url)
 
     async def move_item(self, queue_item_id: str, pos_shift: int = 1) -> None:
         """
@@ -682,9 +694,6 @@ class PlayerQueue:
             is_alert=is_alert,
         )
         self._stream_id = stream.stream_id
-        # execute the play command on the player(s)
-        if not passive:
-            await self.player.play_url(stream.url)
         return stream
 
     def get_next_index(self, cur_index: Optional[int]) -> int: