From d660574a93845d8b8dee375cf4c2913b39710686 Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Mon, 10 Aug 2026 05:29:16 +1000 Subject: [PATCH] [client] audio: recover immediately from provider underruns Treat a negative provider-controlled playback ring as a timeline discontinuity rather than carrying its underrun debt. Rebase to the normal low-water target and reset feedback correction so guest stalls resume at low latency instead of discarding audio for seconds. --- client/src/audio.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/client/src/audio.c b/client/src/audio.c index 2916c8f5..bedd4ae4 100644 --- a/client/src/audio.c +++ b/client/src/audio.c @@ -1525,7 +1525,16 @@ static void playbackData(const void * data, size_t frameCount, inputFrames = sourceData->framesIn; } - bool discontinuity = sourceClock && sourceClock->discontinuity; + const bool providerRateControl = + audio.playback.rateControl == PLAYBACK_RATE_PROVIDER; + /* Do not carry an underrun as buffer debt. Provider feedback is bounded, + * so repaying a guest stall by rate correction would discard resumed audio + * for many seconds. Rebase at the first packet instead. */ + const bool providerUnderrun = + providerRateControl && playbackGetState() == STREAM_STATE_RUN && + ringbuffer_getCount(audio.playback.buffer) < 0; + bool discontinuity = + providerUnderrun || (sourceClock && sourceClock->discontinuity); const int64_t packetTime = playbackMapMediaTime(sourceData, sourceClock, frames, audio.playback.sampleRate, now, &discontinuity); @@ -1556,8 +1565,6 @@ static void playbackData(const void * data, size_t frameCount, const bool sourceRateWasValid = sourceData->sourceRateValid; - const bool providerRateControl = - audio.playback.rateControl == PLAYBACK_RATE_PROVIDER; const int64_t sourceRateTimeMs = providerRateControl ? (now - sourceData->mediaLocalOrigin) / INT64_C(1000000) : sourceData->mediaTimeMs; @@ -1719,6 +1726,11 @@ static void playbackData(const void * data, size_t frameCount, sourceData->offsetError = 0.0; sourceData->offsetErrorIntegral = 0.0; sourceData->ratioIntegral = 0.0; + if (providerUnderrun) + { + sourceData->lastRatio = 1.0; + sourceData->nextFeedbackTime = 0; + } playbackSetState(STREAM_STATE_RUN); } else if ((discontinuity ||