Skip to content

fix(voice): gapless audio chunk playback#1747

Open
cjol wants to merge 2 commits into
mainfrom
fix/1736-gapless-audio-playback
Open

fix(voice): gapless audio chunk playback#1747
cjol wants to merge 2 commits into
mainfrom
fix/1736-gapless-audio-playback

Conversation

@cjol

@cjol cjol commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

This PR fixes audible clicks at audio chunk boundaries during agent speech in VoiceClient. Closes #1736.

Why

  • VoiceClient played each response chunk by starting it at currentTime and waiting for its ended event before scheduling the next. The round-trip latency (event-loop delay plus the next chunk's setup) left a few milliseconds of silence at every seam, audible as a periodic click.
  • We could have reduced the latency by overlapping decode and schedule, but the fundamental problem is that ended callbacks run on the main thread, not the audio clock, so there will always be some gap.
  • Instead, we now schedule chunks back-to-back on the audio clock itself using a playback cursor. Consecutive chunks butt together sample-tight because each starts exactly when the previous ends, regardless of main-thread latency.

Code Changes

  • packages/voice/src/voice-client.ts

    • Replaced the single #activeSource with a #scheduledSources set and a #playbackCursor. Each incoming chunk is scheduled at Math.max(currentTime, cursor), and the cursor is advanced by the chunk duration.
    • Playback now counts as active until the last scheduled source finishes, so barge-in detection (user transcript interrupt) keeps working through the scheduled tail.
    • #stopPlayback stops every scheduled source, not just the current one, so an interrupt or end-call cleanly cancels the whole pipeline.
    • Reset the cursor on end-call so a subsequent call starts fresh instead of picking up a stale offset.
  • packages/voice/src/tests/voice-client.test.ts

    • Added gapless playback tests: consecutive chunk scheduling, catch-up when the cursor falls behind currentTime, interrupt stops all scheduled chunks, barge-in works through the scheduled tail, and cursor reset on end-call.

Open in Devin Review

@changeset-bot

changeset-bot Bot commented Jun 12, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 8e4717e

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@cloudflare/voice Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Open in Devin Review

@pkg-pr-new

pkg-pr-new Bot commented Jun 12, 2026

Copy link
Copy Markdown

Open in StackBlitz

agents

npm i https://pkg.pr.new/agents@1747

@cloudflare/ai-chat

npm i https://pkg.pr.new/@cloudflare/ai-chat@1747

@cloudflare/codemode

npm i https://pkg.pr.new/@cloudflare/codemode@1747

create-think

npm i https://pkg.pr.new/create-think@1747

hono-agents

npm i https://pkg.pr.new/hono-agents@1747

@cloudflare/shell

npm i https://pkg.pr.new/@cloudflare/shell@1747

@cloudflare/think

npm i https://pkg.pr.new/@cloudflare/think@1747

@cloudflare/voice

npm i https://pkg.pr.new/@cloudflare/voice@1747

@cloudflare/worker-bundler

npm i https://pkg.pr.new/@cloudflare/worker-bundler@1747

commit: 8e4717e

@cjol cjol requested a review from threepointone June 15, 2026 11:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[voice] audible click at every audio chunk seam (w/ working fix)

1 participant