Mid-session format change leaves the stream desynced until a manual pause/play
Nobody has claimed this yet.
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 38/100
- Issue type
- Bug
- Clarity
- Needs clarification
- Activity status
- Active
- Tech stack
- cpp, debian, linux, raspberry-pi
- Domain
- audio-video-rtc, cli
Research direction
Start by reproducing a mid-session format change with alternating sample rates using the -o pipewire path, then compare -o pulse and -o alsa. Trace the stream restart and codec-header handling in sendspin-cpp, using the sink-open, sync, and chunk-failure logs as checkpoints. Done means the new format receives and processes its codec header and playback remains synchronized without manual pause/play.
Written by the indexing model from the issue text.
Description
Summary
On a live format renegotiation (FLAC 48 kHz/16-bit -> 192 kHz/24-bit) mid-session, the
output sink reconfigures to the new format but no codec header is ever processed for
it. The player then loses sync and fails to place audio chunks for the rest of that
stream. It does not self-recover: audio stayed audibly wrong until a manual pause/play,
which tore the stream down and started a new one that did process a codec header and
then played correctly.
Environment
| sendspin-cli | 0.1.4, commit 52d0f2c (release artifact linux-arm64, CI run 33119241602) |
| sendspin-cpp | v0.7.2 |
| Host | Raspberry Pi 5, Debian 13 (trixie), aarch64, kernel 6.12.47 |
| Output | -o pipewire (native backend), libpipewire 1.4.2 + wireplumber |
| Sink | Built-in HDMI, s32le 2ch 48000Hz (so the graph resamples 4:1 from 192 kHz) |
| Server | Music Assistant |
Timeline
I player: Stream started
I audio: pipewire: 'pipewire' open at 48000 Hz, 2 ch, 16-bit (4 bytes/frame, 19201-byte ring)
I sendspin.sync_task: Processed new codec header: flac, 48000 Hz, 2 ch, 16-bit
I metadata: Now playing: Ed Sheeran - Perfect
I player: Static delay set to 0 ms by the server
I player: Stream started
I audio: pipewire: 'pipewire' open at 192000 Hz, 2 ch, 24-bit (6 bytes/frame, 115201-byte ring)
W sendspin.sync_task: Lost sync (43890us off), reporting error
I sendspin.sync_task: Regained sync, reporting synchronized
W sendspin.sync_task: Lost sync (64710us off), reporting error
W sendspin.player: Failed to send audio chunk
... x76 ...
Then the manual pause/play:
I player: Stream ended
I player: Stream started
I audio: pipewire: 'pipewire' open at 192000 Hz, 2 ch, 24-bit (6 bytes/frame, 115201-byte ring)
I sendspin.sync_task: Processed new codec header: flac, 192000 Hz, 2 ch, 24-bit
No further warnings after that: the counter held at 76 across a 10 s window, through two
more 192 kHz stream opens and a track change.
The suspicious part
Three sink opens in one run, and only the broken one is missing its codec header:
| Stream open | Sink opened at | Processed new codec header |
|---|---|---|
| 1st | 48 kHz / 16-bit | yes |
| 2nd (broken) | 192 kHz / 24-bit | absent |
| 3rd, after pause/play | 192 kHz / 24-bit | yes |
So the sink was reconfigured to the new format while the decode path had never been told
about it. That is consistent with the symptom -- the two Lost sync figures (43.9 ms and
64.7 ms) are roughly what a 4x sample-rate mismatch would produce against a stream clock.
What it does not appear to be
- Not sink starvation, and not ring mis-sizing. The ring was correct for both formats:
19201 bytes / 4 bytes-per-frame = 4800 frames = 100 ms at 48 kHz, and
115201 / 6 = 19200 frames = also 100 ms at 192 kHz. The quantum-starvation warning
added in #27 never fired. - Not an output-backend write failure. Every warning is tagged
sendspin.playeror
sendspin.sync_task. Nothing logged under theaudio:tag at all, so the sink never
reported a short write, a dead stream, or a recovery attempt. - Not volume or mute. The stream sat at 100% / 0.00 dB in the graph throughout, and
the player reportedplayer volume: 100 (default; no server has set it).
That points at the stream-restart / codec-header path rather than the output backend. It
may well live in sendspin-cpp rather than in this repo -- filing here because this is
where it was observed and where -o pipewire lives, and the triage can move it.
Open questions
- Does it reproduce on
-o pulseand-o alsa? If so it is backend-independent, which
would confirm the diagnosis above. - Does it need the 4x rate jump specifically, or does any mid-session format change do it?
- Is the codec header dropped in flight, never sent, or processed out of order relative to
the sink reconfigure? - The two
Lost syncevents precede the chunk failures. Cause or symptom? - Does the 4:1 resample matter? This host advertises rates up to 192 kHz because the
PipeWire node reports them, but the HDMI sink runs at 48 kHz, so every hi-res stream is
downsampled by the graph anyway. CPU went 0.6% -> 3.3% across the change.
Reproduction
Not yet reduced to reliable steps -- observed once, on a Music Assistant queue that moved
from a 48 kHz/16-bit track to a 192 kHz/24-bit track mid-session. Worth trying a queue
deliberately alternating sample rates.
- Dominant language
- C++
- Stars
- 3
- Forks
- 3
- Avg merge
- 5h 26m
- Merged PRs (30d)
- 35
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from Sendspin/sendspin-cpp-cli
-
Difficulty 3/5 1-2 days Newbie friendliness 78/100
Sendspin/sendspin-cpp-cli#70 ·
-
Recovering from a device outage reports a sync error and plays silence for the swallowed lookahead Openenhancement
Difficulty 5/5 Over a week Newbie friendliness 25/100
Sendspin/sendspin-cpp-cli#63 · 1 comment ·
-
bug
Difficulty 4/5 3-5 days Newbie friendliness 45/100
Sendspin/sendspin-cpp-cli#32 · 1 comment ·
All issues in Sendspin/sendspin-cpp-cli
Similar issues
-
Difficulty 1/5 1-3 hours Newbie friendliness 92/100
autowarefoundation/autoware_universe#13413 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
-
automated-analysis bug memory-safety
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 86/100
-
Sensor initialization takes very long when `--initial-sim-time` is set to current UNIX timestamp Open
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
gazebosim/gz-sensors#662 · 1 comment ·