Skip to content

Mid-session format change leaves the stream desynced until a manual pause/play #30

Description

@chrisuthe

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 Add native PulseAudio and PipeWire output backends #27 never fired.
  • Not an output-backend write failure. Every warning is tagged sendspin.player or
    sendspin.sync_task. Nothing logged under the audio: 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 reported player 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 pulse and -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 sync events 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions