)
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
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]] = {}
import os
import platform
import socket
+import socketserver
import tempfile
from typing import Any, Callable, Dict, List, Optional, Set, Tuple, TypeVar
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
def __init__(
self,
db_url: DatabaseURL,
- stream_port: int = 8095,
session: Optional[aiohttp.ClientSession] = None,
) -> None:
"""
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