fix radio playback
authorMarcel van der Veldt <m.vanderveldt@outlook.com>
Mon, 28 Dec 2020 14:48:27 +0000 (15:48 +0100)
committerMarcel van der Veldt <m.vanderveldt@outlook.com>
Mon, 28 Dec 2020 14:48:27 +0000 (15:48 +0100)
music_assistant/helpers/process.py
music_assistant/managers/players.py
music_assistant/managers/streams.py

index 7c029272caacedf4ead12b3e8435d9ec2b5d46c5..e2e57151b83ff73dc3c5562e5a9aa822dda4999e 100644 (file)
@@ -37,7 +37,7 @@ class AsyncProcess:
             stdout=subprocess.PIPE,
             stdin=subprocess.PIPE if enable_write else None,
             # bufsize needs to be very high for smooth playback
-            bufsize=64000000,
+            bufsize=4000000,
         )
         self.loop = asyncio.get_running_loop()
         self._cancelled = False
@@ -53,7 +53,7 @@ class AsyncProcess:
             # process needs to be cleaned up..
             await self.loop.run_in_executor(None, self.__close)
 
-        return exc_type not in (GeneratorExit, asyncio.CancelledError)
+        return exc_type
 
     async def iterate_chunks(
         self, chunksize: int = DEFAULT_CHUNKSIZE
@@ -93,9 +93,7 @@ class AsyncProcess:
     def __read(self, chunksize: int = DEFAULT_CHUNKSIZE):
         """Try read chunk from process."""
         try:
-            chunk = self._proc.stdout.read(chunksize)
-            self._proc.stdout.flush()
-            return chunk
+            return self._proc.stdout.read(chunksize)
         except (BrokenPipeError, ValueError, AttributeError):
             # Process already exited
             return b""
@@ -104,6 +102,7 @@ class AsyncProcess:
         """Write data to process stdin."""
         try:
             self._proc.stdin.write(data)
+            self._proc.stdin.flush()
         except (BrokenPipeError, ValueError, AttributeError):
             # Process already exited
             pass
@@ -119,17 +118,27 @@ class AsyncProcess:
     def __close(self):
         """Prevent subprocess deadlocking, make sure it closes."""
         LOGGER.debug("Cleaning up process %s...", self._id)
-        try:
-            self._proc.stdout.close()
-        except BrokenPipeError:
-            pass
-        if self._proc.stdin:
+        # close stdout
+        if not self._proc.stdout.closed:
+            try:
+                self._proc.stdout.close()
+            except BrokenPipeError:
+                pass
+        # close stdin if needed
+        if self._proc.stdin and not self._proc.stdin.closed:
             try:
                 self._proc.stdin.close()
             except BrokenPipeError:
                 pass
-        self._proc.kill()
-        self._proc.wait()
+        # send terminate
+        self._proc.terminate()
+        # wait for exit
+        try:
+            self._proc.wait(5)
+            LOGGER.debug("Process %s exited with %s.", self._id, self._proc.returncode)
+        except subprocess.TimeoutExpired:
+            LOGGER.error("Process %s did not terminate in time.", self._id)
+            self._proc.kill()
         LOGGER.debug("Process %s closed.", self._id)
 
 
index d3593e1ac5fb579b9f7c53efdcb29ed81190b074..a9243ce270da34439945ec262b5f8ce67c034d11 100755 (executable)
@@ -282,6 +282,13 @@ class PlayerManager:
                 tracks = await self.mass.music.async_get_playlist_tracks(
                     media_item.item_id, provider_id=media_item.provider
                 )
+            elif media_item.media_type == MediaType.Radio:
+                # single radio
+                tracks = [
+                    await self.mass.music.async_get_radio(
+                        media_item.item_id, provider_id=media_item.provider
+                    )
+                ]
             else:
                 # single track
                 tracks = [
index 202dd5f935d0d14c390626c15c331b6811c562a6..2b17bde55bf1b8c45137b8d753558f9ced125b63 100755 (executable)
@@ -66,11 +66,12 @@ class StreamManager:
             output_format = [output_format.value, "-c", "2"]
         else:
             output_format = [output_format.value]
-        args = (
-            ["sox", "-t", streamdetails.content_type.value, "-", "-t"]
-            + output_format
-            + ["-"]
-        )
+        if streamdetails.content_type in [ContentType.AAC, ContentType.MPEG]:
+            input_format = "flac"
+        else:
+            input_format = streamdetails.content_type.value
+
+        args = ["sox", "-t", input_format, "-", "-t"] + output_format + ["-"]
         if gain_db_adjust:
             args += ["vol", str(gain_db_adjust), "dB"]
         if resample:
@@ -356,7 +357,6 @@ class StreamManager:
         # support for AAC/MPEG created with ffmpeg in between
         if streamdetails.content_type in [ContentType.AAC, ContentType.MPEG]:
             stream_type = StreamType.EXECUTABLE
-            streamdetails.content_type = ContentType.FLAC
             stream_path = f'ffmpeg -v quiet -i "{stream_path}" -f flac -'
 
         # signal start of stream event