@ottervoice/runtime-react-native
The React Native runtime does not hard-depend on Expo packages: you inject recording/playback primitives so the adapter stays testable and Expo Go–friendly.
import { createExpoRuntime } from '@ottervoice/runtime-react-native';
const runtime = createExpoRuntime({ input: { requestPermission: () => /* requestRecordingPermissionsAsync */, createPcmStream: (options, onBuffer) => /* useAudioStream bridge */, }, output: { createSound: (uri) => /* createAudioPlayer */, createPcmPlaylist: () => /* AudioPlaylist */, writePcmChunk: (input) => /* PCM16 → temp WAV URI */, deleteAudioFile: (uri) => /* cleanup */, },});Full binding: examples/react-native-expo/src/expo-adapters.ts.
ExpoRuntimeOptions
Section titled “ExpoRuntimeOptions”| Field | Notes |
|---|---|
input |
Required — see ExpoAudioInputOptions |
output |
Required — see ExpoAudioOutputOptions |
No network adapter: providers use React Native’s global fetch / WebSocket.
ExpoAudioInputOptions
Section titled “ExpoAudioInputOptions”| Field | Notes |
|---|---|
createPcmStream |
Preferred: native PCM mic (wrap Expo SDK 57 useAudioStream) |
requestPermission |
Microphone permission |
createRecording / readAudioFile |
Legacy whole-file recording; prefer PCM for full duplex |
now |
Test clock |
Prefer 16 kHz · mono · PCM16. Chunks may set delivery: 'stream' | 'turn': streaming ASR consumes small buffers; batch / Audio LLM consumes full-turn WAV.
ExpoAudioOutputOptions
Section titled “ExpoAudioOutputOptions”| Field | Notes |
|---|---|
createSound |
URI → playable sound |
createPcmPlaylist |
Gapless PCM playlist for streamed replies |
writePcmChunk |
One PCM16 slice → temp WAV URI |
writeAudioFile / deleteAudioFile |
Full-buffer write and cleanup |
The createSound status bridge must forward the native playing field. Playback
exposes two distinct lifecycle signals:
runtime.audioOutput.onPlaybackRequested(() => { // Audio is ready and native play/playAsync is about to be called; it may still fail or cancel.});runtime.audioOutput.onStart(() => { // The native sound/playlist first reported playing: true; resume does not fire this again.});Whole-file and streamed PCM playback share the same order:
onPlaybackRequested → onStart → onEnd. A failure or cancellation before
audible playback emits only the first signal.
start() and stop() are safe to overlap across React Native lifecycle
changes. If native microphone, sound, or playlist setup completes after
stop(), the runtime immediately stops or destroys that stale object instead
of resuming work in the background. Temporary files created by writeAudioFile
and writePcmChunk are best-effort removed through deleteAudioFile on normal,
cancelled, and failed paths.
During assistant playback, suspend encoded capture while keeping volume callbacks for real barge-in.
Example: examples/react-native-expo. Types: API reference.