/
/
/
1# Universal Player Provider
2
3## Overview
4
5The Universal Player provider creates virtual players that merge multiple protocol players (AirPlay, Chromecast, DLNA, Squeezelite, SendSpin) for the same physical device into a single unified player.
6
7## When is a Universal Player Created?
8
9A Universal Player is automatically created by the PlayerController when:
10
111. **One or more protocol players are detected for the same device** - Matching prefers MAC/serial/UUID-style identifiers and only falls back to IP as a last resort
122. **No native player provider exists** - e.g., a Denon AVR with Chromecast, AirPlay, and DLNA but no native Denon integration
13
14## Example Scenario
15
16Consider a Denon AVR receiver that supports:
17- Chromecast built-in
18- AirPlay 2
19- DLNA
20
21Without a native Denon provider in Music Assistant, the system would normally show three separate players:
22- "Living Room (Chromecast)"
23- "Living Room (AirPlay)"
24- "Living Room (DLNA)"
25
26With the Universal Player provider, these are merged into a single:
27- "Living Room" (Universal Player)
28 - Output protocols: Chromecast, AirPlay, DLNA
29
30## How It Works
31
32### Device Matching
33
34Protocol players are matched to the same device using:
351. **MAC address** - Most reliable, extracted from device info
362. **Serial / UUID / protocol-specific IDs** - Used before any IP fallback
373. **IP address** - Last resort when strong identifiers are missing or unreliable
38
39The controller will also try to validate or enrich reported MAC addresses with ARP before falling back to weaker matching.
40
41### Player Creation Flow
42
43```
441. Chromecast player registers â No native parent â delayed evaluation is scheduled
452. No native player appears â PlayerController creates a UniversalPlayer, even for this single unmatched protocol
463. AirPlay player registers â Matches existing UniversalPlayer by identifiers â gets linked to it
474. DLNA player registers â Matches existing UniversalPlayer â Added as linked protocol
48```
49
50### Feature Aggregation
51
52The Universal Player aggregates features from all linked protocols:
53- Volume control from the protocol that supports it best
54- Power control from any protocol that supports it
55- Pause/Play from active protocol
56
57### Playback Routing
58
59The Universal Player does NOT have `PLAY_MEDIA` capability. Instead:
601. User selects "Living Room" and starts playback
612. PlayerController uses `_select_best_output_protocol()` to choose best protocol
623. Playback is routed to the selected protocol player (e.g., Chromecast)
634. User can switch to different protocol in player settings
64
65## Configuration
66
67Universal Players are auto-created and require no user configuration. However, users can:
68- Rename the player
69- Choose preferred output protocol
70- Disable/enable the player
71- Remove the universal player to wipe its config and restart protocol discovery from scratch
72
73## Cleanup
74
75When a Universal Player is permanently removed, all protocol parent links are cleared so discovery can start over cleanly.
76
77If a native provider is later installed (e.g., Denon integration), the Universal Player is replaced by the native player, with all protocols linked to it instead.
78
79## Technical Details
80
81### Player ID
82
83Universal players use the format `up{random}`, minted once when the device is first
84wrapped. The id carries no device information and is never recomputed.
85
86This matters because the player id is the identity API consumers (e.g. the Home
87Assistant integration) bind their entities to, so it has to stay stable for the
88lifetime of the device. A universal player is therefore always resolved through the
89`protocol_parent_id` that each of its protocol players persists, never by deriving an
90id from the identifiers that happen to be available at that moment. Deriving the id
91made it shift whenever a different set of protocol players was registered - from a
92MAC-based to a UUID-based id, for example - which orphaned the consumer's entity.
93
94As a consequence a universal player config is only ever deleted when the user removes
95the player, when a native player takes over the device, or when it is absorbed by
96another universal player of the same device in a merge. The latter two carry its
97settings over to the player that replaces it first. When the protocol players of a
98universal player merely disappear it becomes unavailable but keeps its config, because
99an opaque id cannot be recreated from the device.
100
101### File Structure
102
103```
104universal_player/
105âââ __init__.py # Provider setup
106âââ provider.py # UniversalPlayerProvider class
107âââ player.py # UniversalPlayer class
108âââ constants.py # Constants (prefix, etc.)
109âââ manifest.json # Provider manifest (builtin)
110âââ README.md # This file
111```
112
113### Provider Features
114
115The Universal Player provider has no special provider features - it doesn't support manual player creation via the UI. Players are only created automatically by the PlayerController.
116