@tundra-audio/react-native
v0.1.1
Published
Real-time voice call native library for Expo
Readme
@tundra/react-native
Real-time voice call native library for Expo. Provides a native audio engine (record + playback), a WebSocket service, and a useVoiceCall hook that wires them together for streaming voice AI conversations.
Installation
This package is consumed via yalc for local development. It is not published to npm.
# One-time setup (from woolly/)
yalc add @tundra/react-native
npm installDev workflow
After any JS/TS change in tundra:
cd tundra/packages/react-native
npm run push # build + yalc push → updates woolly's node_modules automaticallyThen press R in the Expo terminal to reload. No npm install needed.
For native Swift/Kotlin changes, expo prebuild + Xcode rebuild is still required.
Public API
useVoiceCall(options)
Main hook. Manages the full call lifecycle: permissions, WebSocket handshake, audio init, recording, and playback.
import { useVoiceCall } from '@tundra/react-native';
const { status, micStatus, speakerStatus, initialize, end, startMic, stopMic, lastFrame } =
useVoiceCall({
wsUrl: 'wss://your-backend/ws',
getSignedUrl: () => fetchSignedUrl(), // optional — overrides wsUrl at connect time
});Options
| Prop | Type | Description |
|------|------|-------------|
| wsUrl | string | WebSocket endpoint |
| getSignedUrl | () => Promise<string> | Optional. Called at connect time to get a short-lived signed URL |
Returns
| Value | Type | Description |
|-------|------|-------------|
| status | CallStatus | idle | initializing | listening | thinking | speaking |
| micStatus | 'stopped' \| 'recording' | Microphone state |
| speakerStatus | 'idle' \| 'playing' | Playback state |
| initialize | () => Promise<void> | Start a call |
| end | () => Promise<void> | End a call and clean up |
| startMic | () => Promise<void> | Resume mic after muting |
| stopMic | () => Promise<void> | Mute mic without ending call |
| lastFrame | AudioFramePayload \| undefined | Latest audio frame (level meter data) |
webSocketService
Singleton WebSocketService instance. Used internally by useVoiceCall. Exposed for advanced use.
import { webSocketService } from '@tundra/react-native';
webSocketService.connect(url);
webSocketService.sendMessage({ type: 'start', recording_sample_rate: 16000 });
webSocketService.disconnect();tundraAudio
Native module (TundraAudio). Used internally by useVoiceCall. Exposed for advanced use.
import { tundraAudio } from '@tundra/react-native';
await tundraAudio.initialize({ playbackSampleRate: 24000, frameDurationMs: 50 });
await tundraAudio.startRecording({ frameDurationMs: 50 });
await tundraAudio.stopRecording();
await tundraAudio.cleanup();
tundraAudio.feedBytes(base64String);tundra_version
Package version string. Useful for debugging and integration tests.
import { tundra_version } from '@tundra/react-native';
console.log(tundra_version); // '0.1.0'WebSocket protocol
The library speaks the following wire protocol with the voice backend:
Client → Server
| Message | When |
|---------|------|
| { type: "start", recording_sample_rate: N } | Immediately after WebSocket connects |
| Raw ArrayBuffer (PCM16 LE) | While status === 'listening' and speaker is idle |
Server → Client
| Message | Description |
|---------|-------------|
| { type: "session_config", tts_provider, playback_sample_rate, voice } | Sent once after start — configures audio engine |
| { type: "status", message: "ready" \| "asr_start" \| ... } | Call lifecycle events |
| Raw ArrayBuffer (PCM16 LE) | TTS audio chunks fed directly to the native player |
Testing
cd tundra/packages/react-native
npm test # run all tests
npm run test:watch # watch modeTests cover WebSocketService and useVoiceCall using Jest + jest-websocket-mock. The native module (tundraAudio) is mocked automatically via src/__mocks__/TundraAudioModule.ts.
Package structure
src/
index.ts # Public exports
useVoiceCall.ts # Main hook
WebSocketService.ts # Singleton WS client
TundraAudioModule.ts # Native module JS bindings
TundraAudio.types.ts # Shared types
__mocks__/ # Jest manual mocks (TundraAudioModule)
__tests__/ # Unit tests
__mocks__/ # Jest module stubs (expo, expo-modules-core)
ios/
TundraAudioModule.swift
android/
expo/modules/tundraaudio/
build/ # Compiled output (tsc) — not committed