Earshot is the reliable, protocol-flexible FreeSWITCH ↔ AI-agent audio bridge. This is the short version of what makes it different from the alternatives — the pitch for the open-source launch. (For the full capability list see FEATURES.md; for what's next, ROADMAP.md.)
The core call path below is validated on real SIP calls (sipp + real audio). Protocol adapters
vary by vendor: native, openai, deepgram, and pipecat are validated against the live
service/schema; elevenlabs and gemini ship adapter-complete and mock-tested in CI (see the status
table in README).
Every FreeSWITCH voice-AI write-up hits the same wall — the incumbent streaming module's playback
(application → caller) "simply didn't work reliably," forcing uuid_broadcast hacks and other
workarounds. Earshot's WRITE_REPLACE path is validated with real audio, full duplex, on one leg.
This is the wedge: if you've fought half-working agent audio on FreeSWITCH, Earshot is the fix.
-
Seven wire protocols, your agent unmodified.
native,twilio(Media Streams),openai(Realtime),deepgram(Voice Agent),elevenlabs,gemini(Live),pipecat(protobuf). Swap vendors by changing one word (proto=). Correlation, base64/JSON/protobuf framing, handshakes (OpenAIrealtimesubprotocol, ElevenLabs ping→pong, Gemini setup), and per-vendor barge-in signals are handled for you. -
Turn-taking that works with any agent. Module-side VAD endpointing (
switch_vad) emitsspeech_started/speech_stopped, opens a "ready gate" so callers never answer into silence, and does speech-triggered barge-in — for agents that do no endpointing themselves. Agents that bring their own VAD leave it off (docs/MODULE-VS-AGENT.md). -
The agent can drive the call. An opt-in, whitelisted control channel turns LLM tool calls into real telephony:
transfer,hangup,send_dtmf,play,record,hold,bridge,setvar— audited viaearshot::command. A dumb audio pipe becomes an AI-controllable endpoint. -
PCI/PII masking a SaaS charges dearly for. A masking window mutes caller audio and redacts DTMF to the agent during card entry, while digits still reach a secure collector. Self-hosted, on your box, no per-minute compliance surcharge.
-
One tap, many sinks. Multi-stream fan-out: run the agent + a live transcription fork + a supervisor monitor + compliance capture on the same call at once (
dir=inread-only forks). -
Latency you can see. Built-in KPIs in every metrics event: time-to-first-audio, per-turn response latency, and WebSocket RTT — the numbers voice teams actually optimize.
-
Any sample rate. Transparent resampling (8k ↔ 16k ↔ 24k, incl. asymmetric like Gemini's 16k-in/24k-out) via FreeSWITCH's bundled resampler — no extra dependency.
-
Built to stay up. Auto-reconnect with jittered backoff, a bounded outbound queue (buffers a blip, drops a long outage instead of replaying stale audio), and one clean teardown path.
-
Observable and traceable.
earshot::metricsevents (periodic / on-close / on-demand JSON), lifecycle + DTMF + command + speech events over the FreeSWITCH event socket, and correlation by SIP Call-ID + channel UUID on the handshake. -
Drop-in migration. A
uuid_audio_stream/audio_streamcompat shim runs existingmod_audio_streamdialplans unmodified (and refuses to register if that module is still loaded). -
MIT and tested. Portable core (codec, protobuf, backpressure queue) is unit-tested off-box — including adversarial protobuf input caught in peer review — and the core call path is exercised end-to-end with
sipp+ real audio.
A thin, reliable FreeSWITCH-side tap — not an agent framework, STT/TTS engine, media server/SFU, or IVR engine. It feeds pipecat / LiveKit / your own agent; it doesn't replace them. Staying sharp is the point.
The self-hosted answer to Twilio ConversationRelay's feature set — matched, then extended with the things only an on-prem module can do: your own models, PCI masking, fan-out, and agent-driven call control — on the FreeSWITCH stack you already run.