Skip to content

docs: add full-duplex voice AI assistant guide - #1344

Open
maciejkucmierz-swm wants to merge 2 commits into
software-mansion:mainfrom
maciejkucmierz-swm:docs/full-duplex-voice-ai-guide
Open

maciejkucmierz-swm wants to merge 2 commits into
software-mansion:mainfrom
maciejkucmierz-swm:docs/full-duplex-voice-ai-guide

Conversation

@maciejkucmierz-swm

Copy link
Copy Markdown
Contributor

Based on the APIs introduced in:

⚠️ Breaking changes ⚠️

  • None. Documentation-only change.

Introduced changes

  • Add “Build a full-duplex voice AI assistant” guide for React Native Audio API 1.0.
  • Demonstrate communication-session configuration, voice-processing capture, Android voice output classification, and OpenAI Realtime audio streaming.
  • Cover queued playback, barge-in, late-decode invalidation, and conservative conversation truncation.
  • Distinguish essential audio functionality from optional UI features. Keep application-specific error handling and cleanup as comments/pseudocode.
  • Include a call-path diagram, native setup instructions, and a suggested local MVP token server.
  • Clarify that echo suppression depends on the device, OS, and audio route.

Only the new guide is included; existing documentation pages are unchanged.

Checklist

  • Updated relevant documentation
  • Added/Conducted relevant tests — docs build, formatting, link checks, and six mocked audio-path checks passed. Physical-device validation was not performed.
  • Performed self-review of the code

@closetcaiman closetcaiman added the documentation Additions, corrections, or updates to documentation and technical specs label Oct 14, 2026
@github-actions

github-actions Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

WPT non-regression comparison

PASS — no regressions · 0 improved section(s) · overall 3427 → 3427 (0)

Unchanged sections (28)
Spec section Base pass Head pass Delta
Processing model 1 1 0
Other 56 56 0
AnalyserNode 138 138 0
AudioBuffer 140 140 0
AudioBufferSourceNode 220 220 0
AudioContext 58 58 0
AudioNode 261 261 0
AudioParam 680 680 0
BiquadFilterNode 275 275 0
ChannelMergerNode 30 30 0
ChannelSplitterNode 7 7 0
ConstantSourceNode 64 64 0
ConvolverNode 178 178 0
DelayNode 127 127 0
DestinationNode 0 0 0
DynamicsCompressorNode 4 4 0
GainNode 15 15 0
IIRFilterNode 87 87 0
MediaElementAudioSourceNode 0 0 0
MediaStreamAudioDestinationNode 1 1 0
MediaStreamAudioSourceNode 0 0 0
OfflineAudioContext 35 35 0
OscillatorNode 104 104 0
PannerNode 727 727 0
PeriodicWave 33 33 0
ScriptProcessorNode 0 0 0
StereoPannerNode 104 104 0
WaveShaperNode 82 82 0

Baseline: eb17d846e2e16cf3c82e0807a35f30565f10653e · Candidate: 6ee10db6abdcd1dbf5ecc52e079cb8a519a43bc2

Workflow run · this comment is updated on every push.

@mdydek mdydek left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

can it be written more begginer-friendly when it comes to using our library. I think we can assume the user's knowledge about tokens and other stuff, but focus more on the features used from our library

Comment thread packages/audiodocs/docs/guides/building-a-full-duplex-voice-ai-assistant.mdx Outdated
Comment thread packages/audiodocs/docs/guides/building-a-full-duplex-voice-ai-assistant.mdx Outdated
Comment thread packages/audiodocs/docs/guides/building-a-full-duplex-voice-ai-assistant.mdx Outdated
Comment thread packages/audiodocs/docs/guides/building-a-full-duplex-voice-ai-assistant.mdx Outdated

@mdydek mdydek left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I like the structure much better, but I feel like we could give some more code snippets rather than wall of text, prefer keeping it brief and giving some mini code snippets that can help the user to understand how to structure that

`}
/>

The examples below illustrate these interfaces, rather than a complete application. The communication settings described here require Android 12 (API 31)+ or iOS 14+.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
The examples below illustrate these interfaces, rather than a complete application. The communication settings described here require Android 12 (API 31)+ or iOS 14+.
The examples below illustrate these interfaces, but bear in mind that the communication settings described here require Android 12 (API 31)+ or iOS 14+.

`}
/>

The examples below illustrate these interfaces, rather than a complete application. The communication settings described here require Android 12 (API 31)+ or iOS 14+.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

and also we can wrap this in an info block

await AudioManager.setAudioSessionActivity(true);
```

The configuration must be in place before creating the audio context or starting capture. Microphone permission is still required; Android communication routing also needs `MODIFY_AUDIO_SETTINGS`. See [permissions](../other/non-expo-permissions.mdx) for the native declarations.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
The configuration must be in place before creating the audio context or starting capture. Microphone permission is still required; Android communication routing also needs `MODIFY_AUDIO_SETTINGS`. See [permissions](../other/non-expo-permissions.mdx) for the native declarations.
The configuration must be in place before starting the playback or capture. Microphone permission is still required; Android communication routing also needs `MODIFY_AUDIO_SETTINGS`. See [permissions](../other/non-expo-permissions.mdx) for the native declarations.

});
```

The output profile is fixed when the context is created and is ignored on iOS. It does **not** acquire audio focus, activate communication mode, or select a speaker by itself. Changing that one option is not a substitute for configuring the session and recorder.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
The output profile is fixed when the context is created and is ignored on iOS. It does **not** acquire audio focus, activate communication mode, or select a speaker by itself. Changing that one option is not a substitute for configuring the session and recorder.


The output profile is fixed when the context is created and is ignored on iOS. It does **not** acquire audio focus, activate communication mode, or select a speaker by itself. Changing that one option is not a substitute for configuring the session and recorder.

On **Android**, the settings can also be combined differently: keep the `inCommunication` session, speaker request, and `voiceCommunication` microphone preset, but create the context with `androidOutputProfile: 'media'` (the default). This keeps media-classified playback while the communication session is active.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

are you sure it will work with the media output profile?

await recorder.start();
```

Channel indices start at zero, so `getChannelData(0)` returns the mono channel as a `Float32Array`. Its samples are floating-point values, normally between `-1` and `1`; they are not already PCM16 bytes or base64 text.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
Channel indices start at zero, so `getChannelData(0)` returns the mono channel as a `Float32Array`. Its samples are floating-point values, normally between `-1` and `1`; they are not already PCM16 bytes or base64 text.
`getChannelData()` returns the channel as a `Float32Array`. Its samples are floating-point values, normally between `-1` and `1`; they are not already PCM16 bytes or base64 text.


An AI reply often arrives as many small pieces rather than one complete recording. [`AudioBufferQueueSourceNode`](../sources/audio-buffer-queue-source-node.mdx) is a playback source that consumes a queue of decoded audio buffers in order. Unlike creating a separate source for every chunk, it gives the reply one continuous playback path.

`connect()` attaches the source to the graph. `audioContext.destination` is the graph's output to the device:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

also links to the documentation parts


Call `start()` only once for that queue source, not once per chunk or reply. More buffers can be enqueued while it is playing. An empty queue waits for more audio, so it can also be reused for later replies in the same conversation.

**If pieces of a reply play in the wrong order**, check the decoding flow. The queue preserves enqueue order, but independent asynchronous decode calls may finish in a different order from arrival. The app needs to serialize decoding and enqueueing; the queue cannot restore the original order afterwards. Gaps can also mean the queue is waiting for data, rather than that another `start()` call is needed.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

wrap it in the tip block

Comment on lines +198 to +200
- `AudioManager` configures the communication session and route.
- `AudioRecorder` supplies microphone samples through callbacks.
- `AudioContext` and `AudioBufferQueueSourceNode` decode and play streamed replies.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

same case with links to docs pages

- `AudioContext` and `AudioBufferQueueSourceNode` decode and play streamed replies.
- The app coordinates audio formats, decode ordering, and interruption decisions.

Understanding those boundaries helps distinguish an audio-data problem from a routing or conversation-state problem. See the [AudioManager](../system/audio-manager.mdx), [AudioRecorder](../inputs/audio-recorder.mdx), and [queue source](../sources/audio-buffer-queue-source-node.mdx) references for the individual APIs.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
Understanding those boundaries helps distinguish an audio-data problem from a routing or conversation-state problem. See the [AudioManager](../system/audio-manager.mdx), [AudioRecorder](../inputs/audio-recorder.mdx), and [queue source](../sources/audio-buffer-queue-source-node.mdx) references for the individual APIs.
See the [AudioManager](../system/audio-manager.mdx), [AudioRecorder](../inputs/audio-recorder.mdx), and [queue source](../sources/audio-buffer-queue-source-node.mdx) references for the individual APIs.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Additions, corrections, or updates to documentation and technical specs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants