Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/soft-owls-buffer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@zapo-js/voip': patch
---

Increase the live audio buffer headroom to absorb upstream jitter without dropping recent speech.
4 changes: 2 additions & 2 deletions packages/voip/src/media/WaAudioEngine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,8 @@ export class WaAudioEngine {

this.extPreBufferSize = Math.floor(this.sampleRate * EXT_FEED_RESUME_FRACTION)
this.extTargetBuffer = Math.floor(this.sampleRate * 0.06)
this.extHighWater = Math.floor(this.sampleRate * 0.2)
this.extMaxBuffer = Math.floor(this.sampleRate * 0.5)
this.extHighWater = Math.floor(this.sampleRate * 0.45)
this.extMaxBuffer = Math.floor(this.sampleRate * 0.75)
}

setAudioSender(sender: AudioSender): void {
Expand Down
8 changes: 4 additions & 4 deletions packages/voip/src/media/__tests__/audio-engine.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,17 +63,17 @@ test('feedExternalAudio caps the live buffer and drops oldest on overflow', () =
for (let i = 0; i < 10; i++) {
level = engine.feedExternalAudio(new Float32Array(2000))
}
assert.equal(level, 500)
assert.equal(engine.getLiveBufferMs(), 500)
assert.equal(level, 750)
assert.equal(engine.getLiveBufferMs(), 750)
})

test('feedExternalAudio keeps only the tail of an oversized chunk', () => {
const engine = new WaAudioEngine()
engine.setExternalMode(true)

const level = engine.feedExternalAudio(new Float32Array(10_000))
assert.equal(level, 500)
assert.equal(engine.getLiveBufferMs(), 500)
assert.equal(level, 625)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: The 'keeps only the tail of an oversized chunk' test no longer exercises the truncation path. With the new 750 ms cap (12000 samples at 16 kHz), a 10000-sample chunk no longer exceeds extMaxBuffer, so the incoming.length > this.extMaxBuffer branch in feedExternalAudio is never entered. Feed a chunk larger than 12000 samples (e.g. 20000) and assert the resulting level (750 ms) so the oversized-chunk regression test still covers its intended code path.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/voip/src/media/__tests__/audio-engine.test.ts, line 75:

<comment>The 'keeps only the tail of an oversized chunk' test no longer exercises the truncation path. With the new 750 ms cap (12000 samples at 16 kHz), a 10000-sample chunk no longer exceeds extMaxBuffer, so the `incoming.length > this.extMaxBuffer` branch in feedExternalAudio is never entered. Feed a chunk larger than 12000 samples (e.g. 20000) and assert the resulting level (750 ms) so the oversized-chunk regression test still covers its intended code path.</comment>

<file context>
@@ -63,17 +63,17 @@ test('feedExternalAudio caps the live buffer and drops oldest on overflow', () =
     const level = engine.feedExternalAudio(new Float32Array(10_000))
-    assert.equal(level, 500)
-    assert.equal(engine.getLiveBufferMs(), 500)
+    assert.equal(level, 625)
+    assert.equal(engine.getLiveBufferMs(), 625)
 })
</file context>

assert.equal(engine.getLiveBufferMs(), 625)
})

test('feedExternalAudio is a no-op before external mode is enabled', () => {
Expand Down
Loading