/
/
# What does this implement/fix? Two things that both come down to holding audio back longer than there is any reason to. **Crossfade buffering.** The tail of a track was held back from the player for its whole length, and at every transition the flow then waited for the *entire* requested fade window of the next track before emitting anything — up to 45 seconds of audio, even when the fade being built only blends 8 of them and passes the rest through untouched. Measured on a real transition: 41 seconds collected, 8.5 seconds of silence, for an 8 second crossfade. After a seek near the end of a track, where the player has only its warmup in hand, that silence is audible as a skip. **Realtime streams.** Radio, live audio sources and music providers that stream through a paced local daemon hand over their audio at about playback pace. The stream logic assumed every source can be read ahead of playback, so it spent that headroom on buffering and fades the source cannot afford. - Hold a track's tail back only once its source is done delivering, so the audio a player has in hand is never traded for a fade that may not happen. - Wait only for the part of the incoming track a fade actually blends, instead of the whole requested window. - Keep a source that delivers at playback pace out of the crossfade path entirely, in both the flow and single-track paths, and report that honestly in the audio pipeline. - Start such sources with a smaller buffer, and pass a seek to the source instead of playing the skipped audio away first (a 30 second seek used to exceed the startup budget and marked the track unplayable). - Mark radio and live audio sources as delivering at playback pace, so radio starts about a second sooner. - Treat a queue flow as buffered audio on Sendspin: a flow only ever carries buffered items, so it was being denied the startup lead its player asked for. - Log how long each transition waits for the incoming track, since nothing measured this before. Groundwork for #5832 (Spotify Soloist playback), which needs the realtime half. **Related issue (if applicable):** - needs music-assistant/models#368 (adds the `StreamDetails.is_realtime` flag) ## 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. - [x] 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.