auto select stream port (#285)
authorMarcel van der Veldt <m.vanderveldt@outlook.com>
Sat, 7 May 2022 19:20:06 +0000 (21:20 +0200)
committerGitHub <noreply@github.com>
Sat, 7 May 2022 19:20:06 +0000 (21:20 +0200)
music_assistant/controllers/stream.py
music_assistant/helpers/util.py
music_assistant/mass.py

index b4ba59de277858dc1f989c521ca4e5df14a8441b..32cce3a29dcf22d772d67f98343c53ac779156ca 100644 (file)
@@ -20,7 +20,7 @@ from music_assistant.helpers.audio import (
 )
 from music_assistant.helpers.process import AsyncProcess
 from music_assistant.helpers.typing import MusicAssistant
-from music_assistant.helpers.util import get_ip
+from music_assistant.helpers.util import get_ip, select_stream_port
 from music_assistant.models.errors import MediaNotFoundError, MusicAssistantError
 from music_assistant.models.media_items import ContentType, MediaType
 from music_assistant.models.player_queue import CrossFadeMode, PlayerQueue, QueueItem
@@ -29,11 +29,11 @@ from music_assistant.models.player_queue import CrossFadeMode, PlayerQueue, Queu
 class StreamController:
     """Controller to stream audio to players."""
 
-    def __init__(self, mass: MusicAssistant, port: int = 8095):
+    def __init__(self, mass: MusicAssistant, port: Optional[int] = None):
         """Initialize instance."""
         self.mass = mass
         self.logger = mass.logger.getChild("stream")
-        self._port = port
+        self._port = port or select_stream_port()
         self._ip: str = get_ip()
         self._subscribers: Dict[str, Set[str]] = {}
         self._client_queues: Dict[str, Dict[str, asyncio.Queue]] = {}
index 44c6f39f69504b1a84cc7dadaca28cd44ca2e4ed..e121d40ee4af7f5b9acc2f5e399c0a8d89167de8 100755 (executable)
@@ -5,6 +5,7 @@ import asyncio
 import os
 import platform
 import socket
+import socketserver
 import tempfile
 from typing import Any, Callable, Dict, List, Optional, Set, Tuple, TypeVar
 
@@ -174,6 +175,20 @@ def get_ip():
     return _ip
 
 
+def is_port_in_use(port: int) -> bool:
+    """Check if port is in use."""
+    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as _sock:
+        return _sock.connect_ex(("localhost", port)) == 0
+
+
+def select_stream_port() -> int:
+    """Automaticlaly find available stream port, prefer the default 8095."""
+    if not is_port_in_use(8095):
+        return 8095
+    with socketserver.TCPServer(("localhost", 0), None) as _sock:
+        return _sock.server_address[1]
+
+
 def get_folder_size(folderpath):
     """Return folder size in gb."""
     total_size = 0
index b5dc53111adc55a87c21d78cedbb5e175787915f..7dfe167361b46a32ca8763af4ae6119b7c8ae63e 100644 (file)
@@ -37,7 +37,6 @@ class MusicAssistant:
     def __init__(
         self,
         db_url: DatabaseURL,
-        stream_port: int = 8095,
         session: Optional[aiohttp.ClientSession] = None,
     ) -> None:
         """
@@ -63,7 +62,7 @@ class MusicAssistant:
         self.metadata = MetaDataController(self)
         self.music = MusicController(self)
         self.players = PlayerController(self)
-        self.streams = StreamController(self, stream_port)
+        self.streams = StreamController(self)
         self._tracked_tasks: List[asyncio.Task] = []
         self.closed = False