Skip to content

Commit

Permalink
Snapcast: Add configuration options (#1692)
Browse files Browse the repository at this point in the history
  • Loading branch information
SantiagoSotoC authored Oct 5, 2024
1 parent a65616a commit 4021217
Showing 1 changed file with 51 additions and 24 deletions.
75 changes: 51 additions & 24 deletions music_assistant/server/providers/snapcast/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,27 @@
CONF_SERVER_CONTROL_PORT = "snapcast_server_control_port"
CONF_USE_EXTERNAL_SERVER = "snapcast_use_external_server"
CONF_SERVER_BUFFER_SIZE = "snapcast_server_built_in_buffer_size"
CONF_SERVER_CHUNK_MS = "snapcast_server_built_in_chunk_ms"
CONF_SERVER_INITIAL_VOLUME = "snapcast_server_built_in_initial_volume"
CONF_SERVER_TRANSPORT_CODEC = "snapcast_server_built_in_codec"
CONF_SERVER_SEND_AUDIO_TO_MUTED = "snapcast_server_built_in_send_muted"
CONF_STREAM_IDLE_THRESHOLD = "snapcast_stream_idle_threshold"


CONF_CATEGORY_GENERIC = "generic"
CONF_CATEGORY_ADVANCED = "advanced"
CONF_CATEGORY_BUILT_IN = "Built-in Snapserver Settings"

CONF_HELP_LINK = (
"https://raw.githubusercontent.com/badaix/snapcast/refs/heads/master/server/etc/snapserver.conf"
)

# airplay has fixed sample rate/bit depth so make this config entry static and hidden
CONF_ENTRY_SAMPLE_RATES_SNAPCAST = create_sample_rates_config_entry(48000, 16, 48000, 16, True)

DEFAULT_SNAPSERVER_IP = "127.0.0.1"
DEFAULT_SNAPSERVER_PORT = 1705
DEFAULT_SNAPSTREAM_IDLE_THRESHOLD = 60000

SNAPWEB_DIR: Final[pathlib.Path] = pathlib.Path(__file__).parent.resolve().joinpath("snapweb")

Expand Down Expand Up @@ -119,38 +132,45 @@ async def get_config_entries(
ConfigEntry(
key=CONF_SERVER_BUFFER_SIZE,
type=ConfigEntryType.INTEGER,
range=(500, 6000),
range=(200, 6000),
default_value=1000,
label="Snapserver buffer size",
description="Buffer[ms]. The end-to-end latency, "
"from capturing a sample on the snapserver until "
"the sample is played-out on the client ",
required=False,
category="Built-in Snapserver Settings",
category=CONF_CATEGORY_BUILT_IN,
hidden=not local_snapserver_present,
help_link=CONF_HELP_LINK,
),
ConfigEntry(
key=CONF_SERVER_CHUNK_MS,
type=ConfigEntryType.INTEGER,
range=(10, 100),
default_value=26,
label="Snapserver chunk size",
required=False,
category=CONF_CATEGORY_BUILT_IN,
hidden=not local_snapserver_present,
help_link="https://raw.githubusercontent.com/badaix/snapcast/86cd4b2b63e750a72e0dfe6a46d47caf01426c8d/server/etc/snapserver.conf",
help_link=CONF_HELP_LINK,
),
ConfigEntry(
key=CONF_SERVER_INITIAL_VOLUME,
type=ConfigEntryType.INTEGER,
range=(0, 100),
default_value=25,
label="Snapserver initial volume",
description="Volume assigned to new snapclients [percent]",
required=False,
category="Built-in Snapserver Settings",
category=CONF_CATEGORY_BUILT_IN,
hidden=not local_snapserver_present,
help_link="https://raw.githubusercontent.com/badaix/snapcast/86cd4b2b63e750a72e0dfe6a46d47caf01426c8d/server/etc/snapserver.conf",
help_link=CONF_HELP_LINK,
),
ConfigEntry(
key=CONF_SERVER_SEND_AUDIO_TO_MUTED,
type=ConfigEntryType.BOOLEAN,
default_value=False,
label="Send audio to muted clients",
required=False,
category="Built-in Snapserver Settings",
category=CONF_CATEGORY_BUILT_IN,
hidden=not local_snapserver_present,
help_link="https://raw.githubusercontent.com/badaix/snapcast/86cd4b2b63e750a72e0dfe6a46d47caf01426c8d/server/etc/snapserver.conf",
help_link=CONF_HELP_LINK,
),
ConfigEntry(
key=CONF_SERVER_TRANSPORT_CODEC,
Expand All @@ -175,31 +195,27 @@ async def get_config_entries(
),
default_value="flac",
label="Snapserver default transport codec",
description="This is the codec used by snapserver to send audio to clients",
required=False,
category="Built-in Snapserver Settings",
category=CONF_CATEGORY_BUILT_IN,
hidden=not local_snapserver_present,
help_link="https://raw.githubusercontent.com/badaix/snapcast/86cd4b2b63e750a72e0dfe6a46d47caf01426c8d/server/etc/snapserver.conf",
help_link=CONF_HELP_LINK,
),
ConfigEntry(
key=CONF_USE_EXTERNAL_SERVER,
type=ConfigEntryType.BOOLEAN,
default_value=not local_snapserver_present,
label="Use existing Snapserver",
required=False,
description="Music Assistant by default already includes a Snapserver. \n\n"
"Checking this option allows you to connect to your own/external existing Snapserver "
"and not use the builtin one provided by Music Assistant.",
category="advanced" if local_snapserver_present else "generic",
category=CONF_CATEGORY_ADVANCED if local_snapserver_present else CONF_CATEGORY_GENERIC,
),
ConfigEntry(
key=CONF_SERVER_HOST,
type=ConfigEntryType.STRING,
default_value="127.0.0.1",
default_value=DEFAULT_SNAPSERVER_IP,
label="Snapcast server ip",
required=False,
depends_on=CONF_USE_EXTERNAL_SERVER,
category="advanced" if local_snapserver_present else "generic",
category=CONF_CATEGORY_ADVANCED if local_snapserver_present else CONF_CATEGORY_GENERIC,
),
ConfigEntry(
key=CONF_SERVER_CONTROL_PORT,
Expand All @@ -208,7 +224,15 @@ async def get_config_entries(
label="Snapcast control port",
required=False,
depends_on=CONF_USE_EXTERNAL_SERVER,
category="advanced" if local_snapserver_present else "generic",
category=CONF_CATEGORY_ADVANCED if local_snapserver_present else CONF_CATEGORY_GENERIC,
),
ConfigEntry(
key=CONF_STREAM_IDLE_THRESHOLD,
type=ConfigEntryType.INTEGER,
default_value=DEFAULT_SNAPSTREAM_IDLE_THRESHOLD,
label="Snapcast idle threshold stream parameter",
required=True,
category=CONF_CATEGORY_ADVANCED,
),
)

Expand Down Expand Up @@ -266,6 +290,7 @@ async def handle_async_init(self) -> None:
self._snapcast_server_host = "127.0.0.1"
self._snapcast_server_control_port = DEFAULT_SNAPSERVER_PORT
self._snapcast_server_buffer_size = self.config.get_value(CONF_SERVER_BUFFER_SIZE)
self._snapcast_server_chunk_ms = self.config.get_value(CONF_SERVER_CHUNK_MS)
self._snapcast_server_initial_volume = self.config.get_value(CONF_SERVER_INITIAL_VOLUME)
self._snapcast_server_send_to_muted = self.config.get_value(
CONF_SERVER_SEND_AUDIO_TO_MUTED
Expand All @@ -277,6 +302,7 @@ async def handle_async_init(self) -> None:
else:
self._snapcast_server_host = self.config.get_value(CONF_SERVER_HOST)
self._snapcast_server_control_port = self.config.get_value(CONF_SERVER_CONTROL_PORT)
self._snapcast_stream_idle_threshold = self.config.get_value(CONF_STREAM_IDLE_THRESHOLD)
self._stream_tasks = {}
self._ids_map = bidict({})

Expand Down Expand Up @@ -588,7 +614,7 @@ async def _create_stream(self) -> tuple[Snapstream, int]:
result = await self._snapserver.stream_add_stream(
# NOTE: setting the sampleformat to something else
# (like 24 bits bit depth) does not seem to work at all!
f"tcp://0.0.0.0:{port}?name={name}&sampleformat=48000:16:2",
f"tcp://0.0.0.0:{port}?name={name}&sampleformat=48000:16:2&idle_threshold={self._snapcast_stream_idle_threshold}",
)
if "id" not in result:
# if the port is already taken, the result will be an error
Expand Down Expand Up @@ -656,8 +682,9 @@ async def _builtin_server_runner(self) -> None:
"--http.port=1780",
f"--http.doc_root={SNAPWEB_DIR}",
"--tcp.enabled=true",
"--tcp.port=1705",
f"--stream.buffer={self._snapcast_server_control_port}",
f"--tcp.port={self._snapcast_server_control_port}",
f"--stream.buffer={self._snapcast_server_buffer_size}",
f"--stream.chunk_ms={self._snapcast_server_chunk_ms}",
f"--stream.codec={self._snapcast_server_transport_codec}",
f"--stream.send_to_muted={str(self._snapcast_server_send_to_muted).lower()}",
f"--streaming_client.initial_volume={self._snapcast_server_initial_volume}",
Expand Down

0 comments on commit 4021217

Please sign in to comment.