From 0124de8b53a371de34af51fca9f6a152b207b719 Mon Sep 17 00:00:00 2001 From: "j.foucher" Date: Mon, 2 Mar 2026 15:19:05 +0100 Subject: [PATCH] Fix audio pre-buffer bypass on clients due to network sub-chunking Raw PCM is split into 32KB sub-chunks for network transmission. On the client, these sub-chunks arrive nearly simultaneously, triggering the "second chunk arrived" fast-path which cancelled the pre-buffer after ~10ms instead of the intended 2000ms. Now the fast-path only applies on Authority (server) where chunks represent genuine separate TTS batches. Clients always wait the full pre-buffer duration via TickComponent timer. Co-Authored-By: Claude Opus 4.6 --- .../PS_AI_ConvAgent_ElevenLabsComponent.cpp | 32 +++++++++++-------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/Unreal/PS_AI_Agent/Plugins/PS_AI_ConvAgent/Source/PS_AI_ConvAgent/Private/PS_AI_ConvAgent_ElevenLabsComponent.cpp b/Unreal/PS_AI_Agent/Plugins/PS_AI_ConvAgent/Source/PS_AI_ConvAgent/Private/PS_AI_ConvAgent_ElevenLabsComponent.cpp index 48bd780..6d74758 100644 --- a/Unreal/PS_AI_Agent/Plugins/PS_AI_ConvAgent/Source/PS_AI_ConvAgent/Private/PS_AI_ConvAgent_ElevenLabsComponent.cpp +++ b/Unreal/PS_AI_Agent/Plugins/PS_AI_ConvAgent/Source/PS_AI_ConvAgent/Private/PS_AI_ConvAgent_ElevenLabsComponent.cpp @@ -1035,20 +1035,26 @@ void UPS_AI_ConvAgent_ElevenLabsComponent::EnqueueAgentAudio(const TArray else if (bPreBuffering) { // Second (or later) audio chunk arrived during pre-buffer period. - // We now have both chunks buffered — start playback immediately. - bPreBuffering = false; - if (bDebug) + // On Authority: this means a genuine second TTS chunk arrived from the + // WebSocket, so we have enough data buffered — start playback immediately. + // On Clients: sub-chunks from network splitting arrive nearly simultaneously, + // which would defeat the pre-buffer. Let the timer in TickComponent handle it. + if (GetOwnerRole() == ROLE_Authority) { - const double NowPb = FPlatformTime::Seconds(); - const double BufferedMs = (NowPb - PreBufferStartTime) * 1000.0; - const double Tpb3 = NowPb - SessionStartTime; - UE_LOG(LogPS_AI_ConvAgent_ElevenLabs, Log, - TEXT("[T+%.2fs] [Turn %d] Pre-buffer: second chunk arrived (%.0fms buffered). Starting playback."), - Tpb3, LastClosedTurnIndex, BufferedMs); - } - if (AudioPlaybackComponent && !AudioPlaybackComponent->IsPlaying()) - { - AudioPlaybackComponent->Play(); + bPreBuffering = false; + if (bDebug) + { + const double NowPb = FPlatformTime::Seconds(); + const double BufferedMs = (NowPb - PreBufferStartTime) * 1000.0; + const double Tpb3 = NowPb - SessionStartTime; + UE_LOG(LogPS_AI_ConvAgent_ElevenLabs, Log, + TEXT("[T+%.2fs] [Turn %d] Pre-buffer: second chunk arrived (%.0fms buffered). Starting playback."), + Tpb3, LastClosedTurnIndex, BufferedMs); + } + if (AudioPlaybackComponent && !AudioPlaybackComponent->IsPlaying()) + { + AudioPlaybackComponent->Play(); + } } SilentTickCount = 0; }