[client] audio: harden playback at small period sizes
Some checks failed
build / client (Debug, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client (Debug, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client (Debug, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client (Debug, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled
build / client (Release, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client (Release, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client (Release, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client (Release, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled
build / module (push) Has been cancelled
build / host-linux (push) Has been cancelled
build / host-windows-cross (push) Has been cancelled
build / host-windows-native (push) Has been cancelled
build / idd (push) Has been cancelled
build / obs (clang) (push) Has been cancelled
build / obs (gcc) (push) Has been cancelled
build / docs (push) Has been cancelled

Bound playback writes and synchronization slews to the physical ring
storage, preventing overwritten samples from being treated as valid PCM.
Trigger clock resynchronization when output must be dropped.

Wait for enough startup audio to cover backend demand and a complete
source packet. Generate silence if playback begins early instead of
rewinding the reader into stale ring storage.

Honor PipeWire playback frame requests and fully initialize empty chunks.
This keeps playback reliable when using small device period sizes.
This commit is contained in:
Geoffrey McRae
2026-07-28 22:54:04 +10:00
parent d956dd8fd3
commit 76230726cc
2 changed files with 127 additions and 22 deletions

View File

@@ -140,19 +140,31 @@ static void pipewire_onPlaybackProcess(void * userdata)
struct spa_buffer * sbuf = pbuf->buffer;
uint8_t * dst;
if (!(dst = sbuf->datas[0].data))
if (sbuf->n_datas == 0 || !sbuf->datas[0].chunk ||
!(dst = sbuf->datas[0].data))
{
#if PW_CHECK_VERSION(1, 4, 0)
pw_stream_return_buffer(pw.playback.stream, pbuf);
#else
pw_stream_queue_buffer(pw.playback.stream, pbuf);
#endif
return;
}
int frames = sbuf->datas[0].maxsize / pw.playback.stride;
if (pw.playback.rateMatch && pw.playback.rateMatch->size > 0)
frames = min(frames, pw.playback.rateMatch->size);
#if PW_CHECK_VERSION(0, 3, 50)
else if (pbuf->requested > 0)
frames = min(frames, pbuf->requested);
#endif
frames = pw.playback.pullFn(dst, frames);
if (!frames)
{
pbuf->size = 0;
sbuf->datas[0].chunk->offset = 0;
sbuf->datas[0].chunk->stride = pw.playback.stride;
sbuf->datas[0].chunk->size = 0;
pw_stream_queue_buffer(pw.playback.stream, pbuf);
pipewire_updatePlaybackLatency();