/
/
/
# What does this implement/fix? Music did not resume on a WiiM speaker after the speakers were regrouped: the now-playing screen froze with the progress running past the end of the track (7:20 on a 4:21 track), and playback only recovered minutes later on the next group change, by then on a different song. `WiimPlayer` only ever learned a position by copying whatever the device reported in `_sync_position()`. Nothing invalidated that position when Music Assistant handed the device a *new* stream, so the player kept reporting the position of the content the device was playing before. The queue's playback tracker adds the item's `streamdetails.seek_position` on top of the player position, so the two compounded: - resume at 167s (correct, the stored resume point) - plus a stale 273s still held from the previous AirPlay session - = `elapsed_time` of 440s on a 261s track A second play command then arrived while the queue was marked playing, so `resume()` took its `corrected_elapsed_time` branch and resumed at 440s. Seeking past the end of the track produced a stream with no audio, the device sat in `TRANSITIONING`, and the reported progress kept climbing past the duration. Two things make the fix work: - `play_media()` resets the position anchor and records the stream URL it handed over. - `_sync_position()` ignores the device's reported position until the device confirms that exact URL, then clears the guard so a later switch to an external source (AirPlay, Spotify, line-in) still reports its own position normally. The guard deliberately does not key off `_attr_current_media`: `_update_ma_state_from_sdk_cache()` rebuilds that from the device's own reported media, so it equals the device URI by construction and cannot tell us what MA handed over. It also rejects positions reported with an empty URI, which is a real state during the handover. **Related issue (if applicable):** - none; diagnosed from a production server log ## Types of changes <!-- Tick exactly one box. CI (.github/workflows/pr-labels.yaml) derives the label from the ticked box and applies it automatically; the release-notes generator uses that same label to slot this change into the next release notes. --> - [x] Bugfix (non-breaking change which fixes an issue) — `bugfix` - [ ] New feature (non-breaking change which adds functionality) — `new-feature` - [ ] 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. — ruff lint/format and mypy pass on both changed files; the only failures locally are ~35 pre-existing `mypy` errors in `providers/sendspin` from a local `aiosendspin` older than dev's pin, untouched by this PR. - [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. — n/a - [ ] For changes affecting the UI, the companion PR in `music-assistant/frontend` is linked. — n/a - [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. — n/a, no documented behaviour changes ## Tests `tests/providers/wiim/test_player.py` gains `TestStalePositionOnNewStream` (5 cases): the anchor reset, the end-to-end handover that reproduces the wedge, a position reported with no URI, a foreign URI, and the guard clearing once the device confirms MA's URI so an external-source switch is not blocked. All 5 fail with `assert 273 == 0` against the unmodified provider. With the fix, 27 passed, 1 skipped (the skip is pre-existing, pending wiim-sdk 0.1.5+).