/
/
# What does this implement/fix? Some AirPlay receivers gate their rendering on an explicit timeline anchor. A WiiM Amp that got a flush-and-restart mid-session (play_media on a live session, which is also the path every skip and seek takes) reported itself STOPPED, kept rendering for about two minutes, then muted. It stayed silent while the server streamed loud audio into a healthy RTP session, and un-muted within 100 ms of the first `progress:` SET_PARAMETER that arrived, at the next track boundary. The receiver never got that anchor earlier because of a gap in `send_metadata`: after a SENDMETA identity push, `_last_progress_sent` was set to 0 on the assumption that the push itself resets the device position to zero. For a track starting at position 0 the follow-up progress correction (the post-anchor media-updated nudge) then never cleared the >= 2s dedup gate, so a restarted track never sent PROGRESS at all. During crossfaded playback the boundary offset (~17s) happened to pass the gate every track, which is why steady playback was fine and only the restart path starved the device. The fix sets `_last_progress_sent` to `None` after every identity push, so exactly one explicit PROGRESS anchor follows each SENDMETA, position 0 included. Dedup takes over again after that one push. Pre-anchor pushes stay harmless: cliraop drops PROGRESS while the session is not yet streaming (`raopcl_set_progress` returns early below `RAOP_STREAMING`). - `send_metadata` now owes one explicit PROGRESS after every SENDMETA instead of assuming the implicit reset to zero is enough - regression test: a track change landing at position 0 is followed by `PROGRESS=0` - updated the tests that pinned the old "no PROGRESS at zero" behavior and the positional command indexes the extra write shifted **Related issue (if applicable):** - related issue N/A (diagnosed from live server logs, 2.10.0.dev2026082503) ## 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. - [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. Co-authored-by: Marcel van der Veldt <[email protected]>