Fall back to protocol-scoped key in get_player_config_value#3885
Fall back to protocol-scoped key in get_player_config_value#3885flomotlik wants to merge 1 commit into
Conversation
Universal players that wrap a protocol player (DLNA, Sonos, etc.) store per-protocol settings such as `sample_rates` and `http_profile` under `<protocol_id>||protocol||<key>` rather than at the top level of the player config. The universal_group flow stream handler calls `get_player_config_value(player_id, CONF_SAMPLE_RATES, ...)` (and the same for CONF_HTTP_PROFILE) against the universal_player's id, hits the missing top-level key, and raises KeyError. The Stream server returns HTTP 500 to every DLNA member fetching the UGP audio, so no audio is played for any DLNA-backed group member. This is reproducible with a Universal Group whose members are DLNA-wrapped universal_players (e.g. Teufel/Raumfeld, generic UPnP). The traceback ends in `_serve_ugp_stream` → `StreamsAudio.get_output_format` → `get_player_config_value(...)` → `KeyError: 'Config key sample_rates not found for player <id>'`. When the bare key is missing and the player has an `active_output_protocol`, retry with the protocol-namespaced key. All existing behavior (`default`, `KeyError`) is preserved when no protocol is active. The fix lives in the single chokepoint every caller goes through, so each latent KeyError of the same shape (sample_rates, http_profile, …) is fixed in one place.
|
Alternative we tested — UGP-localized fix (rejected after testing) Before settling on the config-layer fallback, I explored the more surgical option: change the UGP stream URL to address the member's Two-line patch in -uri=f"{base_url}?player_id={member.player_id}",
+uri=f"{base_url}?player_id={member.active_output_protocol or member.player_id}",(same pattern in Tested locally; here's what I observed
So this approach makes the bug intermittent rather than fixing it: every container restart / first-play-after-boot is silent, the second press works. From a user's seat: "press Styrbar, no music, press again, music plays" after every MA update — not acceptable for the user-visible Styrbar paths that motivated the fix. The config-layer fallback in this PR doesn't have the race because it runs at lookup time (when the DLNA member fetches the stream URL), by which point A heuristic-strengthened UGP-localized version (fall through to |
Problem
Universal Group (UGP) streams produce no audio for any DLNA-backed member (Teufel/Raumfeld, generic UPnP) because every member's HTTP fetch from the UGP stream server raises
KeyError. Reproducible against a Universal Group whose members are universal_players wrapping DLNA protocol players.The same KeyError fires for
CONF_HTTP_PROFILEimmediately afterwards in_serve_ugp_streamitself. Both lookups go throughConfigController.get_player_config_value().Root cause
Since 2.8.0 (
CONF_PROTOCOL_KEY_SPLITTER = "||protocol||"), universal_player wrappers store per-protocol settings (sample_rates,http_profile, etc.) under<protocol_id>||protocol||<key>rather than at the top level of the player config. Every caller still asks for the bare key, so the top-level lookup fails. The UGP stream handler is the most visible victim, but the latent shape is general.Live config of an affected universal_player (Teufel One M wrapping DLNA):
No top-level
sample_ratesorhttp_profileexists, soget_player_config_value(player_id, 'sample_rates')raises.Fix
In
ConfigController.get_player_config_value, when the bare key is missing and the player has anactive_output_protocol, retry withf"{active_protocol}{CONF_PROTOCOL_KEY_SPLITTER}{key}". Originaldefault/KeyErrorsemantics are preserved when no protocol is active.A single-point fix at the config layer covers every caller (
get_output_format,select_flow_format,select_pcm_format,_serve_ugp_stream'shttp_profilelookup, and any future callers).Verification
Applied locally on 2.8.7, then created a UGP with two DLNA-wrapped members and played a Spotify playlist via
music_assistant.play_media. Pre-patch: KeyError stack trace per member fetch, group reportsstate=playingbut speakers silent. Post-patch: no errors in logs, both speakers audible. Same result for a single-member UGP.Happy to add a test if maintainers want one —
get_player_config_valuedoesn't currently have direct coverage, so I'd add a fixture rather than extending an existing test.