Overview
English Companion is a phone-call-style app for practicing spoken English. You tap Start Conversation, talk naturally, and an AI companion called Alex answers out loud, asks follow-up questions and lets you interrupt, just like a real call.
I built it to improve my own spoken fluency, with two hard constraints: zero running cost, and no API keys inside the app.
The challenge
Real-time voice is unforgiving:
Audio has to stream both ways with low delay, or the conversation feels like a walkie-talkie.
On loudspeaker, the AI can hear its own voice and keep interrupting itself.
When you cut in, the AI has to stop talking almost immediately.
A mobile app can't safely hold a permanent API key.
What I built
Voice pipeline
Gemini Live API (native audio in and out) over a WebSocket, with voice activity detection and barge-in.
Echo-cancelled 16 kHz microphone capture (iOS voice-processing I/O; Android VOICE_COMMUNICATION + AcousticEchoCanceler), so the loudspeaker works without the AI hearing itself.
A low-pass resampler that converts Gemini's 24 kHz output to the 16 kHz the echo-cancelling audio path supports.
A playback pacer that keeps only ~300 ms of audio queued on the native side. The audio module has no "clear queue" call, so this is what lets an interruption cut the AI off quickly.
Secure, free backend
A Cloudflare Worker holds the Gemini key and issues single-use, short-lived ephemeral tokens locked to the model and the companion's settings, which is Google's recommended pattern for client apps.
An app access code and rate limiting keep casual misuse off the quota.
The companion's personality, voice and turn-taking settings live on the backend, so they change with a redeploy instead of an app rebuild.
App architecture
An explicit call state machine, plus a call controller that owns audio, session and cleanup in one place.
Automatic reconnection with a fresh token when Gemini rotates long sessions.
An audio-reactive voice orb that shows when Alex is listening, thinking or speaking, and readable errors for offline, quota and configuration problems.
Quality
80 unit tests (59 app, 21 backend) covering audio handling (PCM, resampler accuracy, pacer timing and interruption), the Live wire protocol, the call state machine, the full call lifecycle and the backend routes.
Mutation checks: deliberately breaking flush, cleanup or mute makes the tests fail.
The backend's token request is tested to match what Google's official SDK sends.
App bundles scanned to confirm no API key ships inside them.
Cost
$0 to run: Gemini Live free tier, Cloudflare Workers free plan, and Expo's free cloud builds for a standalone Android app.
Stack
React Native · Expo · TypeScript · Gemini Live API · Cloudflare Workers · @speechmatics/expo-two-way-audio
0 likes · 4 views · Oct 25, 2026
Personal project: a phone-call-style app for practicing spoken English with an AI companion. Real-time voice, interruptions, echo cancellation, $0 to run.