/
/
/
1"""Constants for Chromecast Player provider."""
2
3from __future__ import annotations
4
5from music_assistant_models.config_entries import ConfigEntry
6from music_assistant_models.enums import ConfigEntryType
7
8from music_assistant.constants import (
9 CONF_ENTRY_FLOW_MODE,
10 CONF_ENTRY_HTTP_PROFILE_DEFAULT_3,
11 CONF_ENTRY_OUTPUT_CODEC,
12 CONF_ENTRY_PREFER_WAV_FOR_LIVE_SOURCES_DEFAULT_ENABLED,
13 create_sample_rates_config_entry,
14)
15
16MASS_APP_ID = "C35B0678"
17APP_MEDIA_RECEIVER = "CC1AD845"
18SENDSPIN_CAST_APP_ID = "DD107DDB"
19SENDSPIN_CAST_NAMESPACE = "urn:x-cast:sendspin"
20CONF_USE_MASS_APP = "use_mass_app"
21DASHBOARD_NAMESPACE = "urn:x-cast:io.music-assistant.cast"
22
23# Seconds to wait for a Cast receiver to acknowledge an app launch.
24APP_LAUNCH_TIMEOUT = 30.0
25
26# Seconds the receiver app is kept running after playback stopped, so a
27# follow-up command can reuse the Cast session instead of starting a new one.
28APP_QUIT_DELAY = 10.0
29
30# keepalive media the cast receiver plays while showing a dashboard
31DASHBOARD_KEEPALIVE_SUFFIXES = ("/dashboard-keepalive.mp4", "/keepalive.png")
32
33# Interval (seconds) before an unavailable player is re-evaluated as a possible
34# passive multichannel endpoint that should be removed from the setup.
35MULTICHANNEL_RECHECK_INTERVAL = 600
36
37# Translation key (owned by the Sendspin provider, which renders it) of the warning
38# shown on the Sendspin output of a Cast device. Its presence also makes that output
39# default to disabled, so Sendspin over Cast is opt-in per device.
40SENDSPIN_CAST_EXPERIMENTAL_NOTE = "sendspin_cast_experimental"
41
42# Marker on a Cast player whose receiver reported it cannot run the Sendspin client.
43# Kept on the Cast player rather than on the bridge, which is removed for good once set.
44CONF_SENDSPIN_UNSUPPORTED = "sendspin_unsupported"
45
46# Marker on a Cast player that was never offered the Sendspin bridge before, so its
47# output has to end up switched off. Persisted the moment the device is first bridged,
48# because applying the opt-out needs the protocol link, which may not be in place before
49# the run that decided it ends.
50CONF_SENDSPIN_OPT_OUT_PENDING = "sendspin_opt_out_pending"
51
52# Bounded wait for the protocol link of a freshly registered Sendspin Cast bridge to
53# be persisted, before the bridge is switched off again for the user to opt in.
54SENDSPIN_LINK_WAIT_INTERVAL = 0.5
55SENDSPIN_LINK_WAIT_TRIES = 20
56
57# Devices known to not work with the Sendspin Cast bridge.
58# Tuple of (manufacturer, model) where "*" is a wildcard.
59# These devices will not get a Sendspin bridge, allowing other protocols
60# (e.g. AirPlay bridge) to handle them instead.
61SENDSPIN_CAST_BLOCKLIST: set[tuple[str, str]] = {
62 ("Harman Luxury Audio", "*"),
63 ("*", "HK OMNI ADAPT+AMP"),
64}
65
66CAST_PLAYER_CONFIG_ENTRIES = (
67 CONF_ENTRY_OUTPUT_CODEC,
68 CONF_ENTRY_PREFER_WAV_FOR_LIVE_SOURCES_DEFAULT_ENABLED,
69 CONF_ENTRY_HTTP_PROFILE_DEFAULT_3,
70 # enable flow mode by default as cast devices handle a continuous
71 # flow stream more reliably than enqueueing individual tracks
72 ConfigEntry.from_dict({**CONF_ENTRY_FLOW_MODE.to_dict(), "default_value": True}),
73 ConfigEntry(
74 key=CONF_USE_MASS_APP,
75 type=ConfigEntryType.BOOLEAN,
76 default_value=True,
77 advanced=True,
78 ),
79)
80
81# originally/officially cast supports 96k sample rate (even for groups)
82# but it seems a (recent?) update broke this ?!
83# For now only set safe default values and let the user try out higher values
84CONF_ENTRY_SAMPLE_RATES_CAST = create_sample_rates_config_entry(
85 max_sample_rate=192000,
86 max_bit_depth=24,
87 safe_max_sample_rate=48000,
88 safe_max_bit_depth=16,
89)
90CONF_ENTRY_SAMPLE_RATES_CAST_GROUP = create_sample_rates_config_entry(
91 max_sample_rate=96000,
92 max_bit_depth=24,
93 safe_max_sample_rate=48000,
94 safe_max_bit_depth=16,
95)
96
97# Measured defaults for known Cast models.
98CAST_MODEL_STATIC_DELAY: dict[tuple[str, str], int] = {
99 ("Google Inc.", "Google Home Mini"): 330,
100 ("Google Inc.", "Google Nest Mini"): 427,
101 ("Google Inc.", "Chromecast Audio"): 335,
102 ("Google Inc.", "Google Nest Hub"): 188,
103}
104CAST_FALLBACK_STATIC_DELAY = 330
105
106
107def get_cast_model_static_delay(manufacturer: str, model: str) -> int:
108 """
109 Look up the default static delay for a Cast device model.
110
111 :param manufacturer: Device manufacturer (e.g., "Google Inc.").
112 :param model: Device model name (e.g., "Google Nest Mini").
113 """
114 return CAST_MODEL_STATIC_DELAY.get((manufacturer, model), CAST_FALLBACK_STATIC_DELAY)
115