Skip to content

fix(hooks): allow VAD streamInsert/streamStop during streaming - #1196

Merged
msluszniak merged 1 commit into
mainfrom
@ms/vad-streaming-side-channel
May 29, 2026
Merged

fix(hooks): allow VAD streamInsert/streamStop during streaming#1196
msluszniak merged 1 commit into
mainfrom
@ms/vad-streaming-side-channel

Conversation

@msluszniak

@msluszniak msluszniak commented May 28, 2026

Copy link
Copy Markdown
Member

Description

useVAD exposed stream, streamInsert, and streamStop all through useModuleFactory.runForward, which rejects calls while isGenerating === true. Once stream() was in flight, every streamInsert(chunk) rejected with "model is currently generating" — making the streaming API unusable in practice.

Add a runSideChannel primitive to useModuleFactory that only checks isReady (never isGenerating and never flips it). Streaming hooks now have two regimes:

  • Gated (runForward): forward, stream — one at a time.
  • Side-channel (runSideChannel): streamInsert, streamStop — allowed during a running stream.

useVAD.streamInsert / streamStop now use runSideChannel. useTextToSpeech and useSpeechToText aren't affected (they avoid useModuleFactory entirely for their side-channel methods); they're candidates for a follow-up migration onto the new primitive.

Introduces a breaking change?

  • Yes
  • No

Type of change

  • Bug fix (change which fixes an issue)
  • New feature (change which adds functionality)
  • Documentation update (improves or adds clarity to existing documentation)
  • Other (chores, tests, code style improvements etc.)

Tested on

  • iOS
  • Android

Testing instructions

End-to-end on the apps/speech Voice Activity Detection screen:

  1. Build and install the speech app on an Android device (mic required; the screen disables Start on simulators).
  2. Tap Start VAD Stream multiple times very quick, speak and pause. With this PR: SPEAKING / SILENT events appear in the log as expected. Without it (git checkout HEAD~1 -- packages/react-native-executorch/src/hooks/{useModuleFactory.ts,natural_language_processing/useVAD.ts} and reload Metro): streamInsert rejects on every 100 ms audio chunk and no SPEAKING transition fires and error occurs.

Related issues

Fixes #1173

useVAD exposed stream, streamInsert, and streamStop all through runForward,
which rejects calls while isGenerating === true. While stream() was in
flight, every streamInsert(chunk) rejected with "model is currently
generating" — making the streaming API unusable.

Add a runSideChannel primitive to useModuleFactory that only checks
isReady, never isGenerating. Streaming hooks now have two regimes:

- Gated (runForward): forward, stream — one at a time.
- Side-channel (runSideChannel): streamInsert, streamStop — allowed
  during a running stream.

Migrate useVAD.streamInsert/streamStop onto runSideChannel. Future
streaming hooks (and the planned TTS/STT migration onto useModuleFactory)
can use the same primitive.

Fixes #1173
@msluszniak msluszniak self-assigned this May 28, 2026
@msluszniak msluszniak added the bug fix PRs that are fixing bugs label May 28, 2026
@msluszniak
msluszniak requested a review from IgorSwat May 28, 2026 10:28

@benITo47 benITo47 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.

Tested on iOS - fix works ✅

@msluszniak
msluszniak merged commit 5c43bd3 into main May 29, 2026
4 checks passed
@msluszniak
msluszniak deleted the @ms/vad-streaming-side-channel branch May 29, 2026 14:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug fix PRs that are fixing bugs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

VAD streaming: streamInsert/streamStop blocked by isGenerating gate — useModuleFactory lacks a side-channel primitive

2 participants