From e4fe23a1e5639feed536c93d210713e8ca03af37 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 27 Apr 2026 02:26:30 +0000 Subject: [PATCH] fix(audio-rooms): DROP_OLDEST on the SubscribeHandle pump (audit #8) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The re-issuing pump's MutableSharedFlow used the default onBufferOverflow = SUSPEND. A stalled consumer (decoder, player, or anything downstream) back-pressured the pump → the inner handle.objects.collect → the underlying transport → the relay. Effect: the room caches up to 64 frames (~1.3s) on the consumer side, then the relay slows down sending us audio. For Opus audio the desired behavior is the inverse: drop OLD frames so playback stays live after a UI hiccup or a foreground transition. Switch to BufferOverflow.DROP_OLDEST so the relay keeps streaming at full rate and the consumer's audio stays synchronized with the speaker, at the cost of dropped frames during stalls (which would have been late anyway). --- .../nestsclient/ReconnectingNestsListener.kt | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/nestsClient/src/commonMain/kotlin/com/vitorpamplona/nestsclient/ReconnectingNestsListener.kt b/nestsClient/src/commonMain/kotlin/com/vitorpamplona/nestsclient/ReconnectingNestsListener.kt index 3403c4d69..e3686e4ec 100644 --- a/nestsClient/src/commonMain/kotlin/com/vitorpamplona/nestsclient/ReconnectingNestsListener.kt +++ b/nestsClient/src/commonMain/kotlin/com/vitorpamplona/nestsclient/ReconnectingNestsListener.kt @@ -27,6 +27,7 @@ import com.vitorpamplona.nestsclient.transport.WebTransportFactory import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job +import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow @@ -250,7 +251,16 @@ private class ReconnectingHandle( activeListener.value ?: error("no live session — wait for state == Connected before subscribing") - val frames = MutableSharedFlow(extraBufferCapacity = SUBSCRIBE_BUFFER) + // DROP_OLDEST so a stalled consumer doesn't back-pressure the + // pump → underlying handle → relay. For Opus audio the user + // wants playback to stay "live" rather than catch up on + // minutes-stale buffered frames after a UI hiccup or + // foreground/background transition. + val frames = + MutableSharedFlow( + extraBufferCapacity = SUBSCRIBE_BUFFER, + onBufferOverflow = BufferOverflow.DROP_OLDEST, + ) val liveHandleRef = AtomicReference(null) // Re-subscribe pump: every time activeListener changes, drop