/
/
# What does this implement/fix? Compatible generic LinkPlay speakers (such as the Edifier MS50A) are now discovered by the WiiM provider, alongside official WiiM and Audio Pro devices which keep using the official backend unchanged. Generic LinkPlay devices are added as a lightweight **control/identity shell**: their playback, transport state, current media and volume are delegated to the speaker's linked DLNA/AirPlay protocol players (the same mechanism the Universal Player uses), while the shell natively owns only the device identity and same‑backend LinkPlay multiroom grouping. This keeps a single, hardware‑verified native group path without reimplementing a full playback/eventing stack per device. This is the first stage of broader LinkPlay support; MA‑created mixed (WiiM + generic) grouping is intentionally out of scope here. **Related issue (if applicable):** - N/A **Key changes:** - Extracted the Universal Player's protocol‑delegation and external‑source behaviour into a neutral `ProtocolBackedPlayer` base class; the Universal Player now builds on it (behaviour unchanged). - Added a generic `Player.default_output_protocol_domain` seam so a player without native playback can steer automatic output selection at a preferred protocol domain; the generic LinkPlay shell prefers DLNA, an explicit user preference always wins, and it falls back to normal protocol priority otherwise. - Added a generic `Player.prefer_native_grouping` seam so a device that runs its own multiroom (the LinkPlay shell) groups natively rather than routing grouping through a linked protocol that is merely its preferred playback output; compatibility still decides whether native grouping is possible. - New `LinkPlayPlayer` shell (native `PlayerType.PLAYER`) exposing only device identity and same‑backend multiroom grouping, driven by the low‑level public `WiiMClient` GroupAPI over Music Assistant's shared HTTP session. No high‑level pywiim `Player`, UPnP client, DMR eventing or MA notify route is used. - Native grouping is gated on reachability and compatibility (modern, router‑based, same multiroom generation), validates the whole request before touching any hardware, and same‑backend generic groups can be managed by explicit user command. Externally‑created **mixed** (official + generic) groups are read‑only from both sides via a generic `Player.grouping_locked` policy hook that also suppresses protocol‑derived grouping, and MA cannot create a mixed group in this PR. - Restored the shared UPnP notify helper and the DLNA helper to their original form (no longer needed), substantially reducing the change. - Provider display name is now `WiiM / LinkPlay` (domain unchanged) with an updated description; `pywiim==2.3.0` is kept for the low‑level mTLS client and GroupAPI. **Follow‑ups (out of scope here):** - MA‑created mixed (official + generic) grouping, and startup reconciliation / read‑only enforcement of **pre‑existing** externally‑created mixed groups, are delivered by the dependent layer‑2 PR (#5737); this PR blocks MA‑created mixed grouping defensively and represents mixed topology read‑only where both members are already registered. - Legacy Gen1 Wi‑Fi‑Direct multiroom grouping (older LinkPlay devices) — currently rejected rather than half‑supported. ## Types of changes - [ ] Bugfix (non-breaking change which fixes an issue) — `bugfix` - [ ] New feature (non-breaking change which adds functionality) — `new-feature` - [x] Enhancement to an existing feature — `enhancement` - [ ] New music/player/metadata/plugin provider — `new-provider` - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) — `breaking-change` - [ ] Refactor (no behaviour change) — `refactor` - [ ] Documentation only — `documentation` - [ ] Maintenance / chore — `maintenance` - [ ] CI / workflow change — `ci` - [ ] Dependencies bump — `dependencies` ## Checklist - [x] The code change is tested and works locally. - [x] `pre-commit run --all-files` passes. - [x] `pytest` passes, and tests have been added/updated under `tests/` where applicable. - [ ] For changes to shared models, the companion PR in `music-assistant/models` is linked. - [ ] For changes affecting the UI, the companion PR in `music-assistant/frontend` is linked. - [x] I have read and complied with the project's [AI Policy](https://github.com/music-assistant/.github/blob/main/AI_POLICY.md) for any AI-assisted contributions. - [ ] I have [raised a PR against the documentation repository](https://github.com/music-assistant/music-assistant.io/blob/main/CONTRIBUTING.md) targeting the main or beta branch as appropriate.