📞 English documentation
日本語 →

📞Layer 1: Voice Edge

The call's entry point (HGW / Asterisk / bridge). Current operations vs. Phase C v2.

The physical entry point for calls (the Voice Edge). A Hikari Denwa HGW receives the call, Asterisk passes the audio to bridge.py over AudioSocket, and OpenAI Realtime makes the decision.

Architecture

Raspberry Pi 3B (edge, on-premises) HGW (Hikari Denwa) SIP REGISTER extension Asterisk 22 (chan_pjsip) dialplan / chan_audiosocket bridge.py AudioSocket :9092 / μlaw↔PCM OpenAI Realtime classify_call to be ported (32→64bit) see Remaining Issues RTS RDS Arrowfone AMI :5039 Status → Hangup target channel matched by AEGIS_UUID spam → Hangup(21) fail-safe allow → Dial(ALLOW_DESTINATION) normal forward unknown/empty → Dial(HUMAN_PEER) fail-open (C-2(b))
Diagram: solid = audio path (μlaw 8k ↔ PCM 24k). Dashed = decision→hangup (Plan B, current): on the AI's should_terminate the bridge looks up the target channel via AMI Status and hangs it up; spam is cut (fail-safe), allow/unknown fall through to the dialplan (fail-open). The solid purple box is the Raspberry Pi 3B device boundary (on-premises); the HGW and OpenAI sit outside it (the bottom row shows call outcomes the Pi's dialplan executes). Note: the legacy Plan A (verdict via AstDB) is archived. Dotted = existing Rhodium features that will co-locate on the Pi after the 64-bit port.

Current operations vs. Phase C v2

Current operations (v1) voice-edge A22 (pre on-device test)
Hardware Existing equipment New Raspberry Pi 3B
OS Raspbian 9 Raspberry Pi OS Bookworm 64-bit
Asterisk Asterisk 11 Asterisk 22
SIP chan_sip chan_pjsip
Audio link (legacy path) AudioSocket → bridge.py
Setup Via ChatVoice deploy.sh / verify.sh / systemd
How failures fall (important)

spam is a Hangup (fail-safe = block); anything undecidable or any fault goes to a human (fail-open = stay in business). We do not use cutting everything off (fail-closed); it was removed in C-2(b). See the glossary for details.

Key parameters

  • AudioSocket: 127.0.0.1:9092 (μlaw 8kHz ↔ PCM16 24kHz resampling; also supports GA audio/pcmu direct-send, which bypasses the resample — see below)
  • AMI: 127.0.0.1:5039 (Plan B, current: look up the target channel via Status and Hangup; the legacy Plan A DBPut / AstDB verdict is archived)
  • OpenAI Realtime: gpt-realtime (GA), connecting over /v1/realtime
  • dialplan placeholders: <ALLOW_DESTINATION> (allow forwarding target) / <HUMAN_PEER> (fail-open hand-off target)
OpenAI Realtime migrated to GA

The OpenAI Realtime Beta API was retired on 2026-05-12. bridge.py is migrated to GA (gpt-realtime) and verified live against real OpenAI (connect / session.update accepted / classify_call fires / full pipeline: classify → closing line → AMI Hangup). No legacy Beta headers or wording remain.

ℹ️Audio format: μlaw direct-send supported (opt-in; default is pcm)

GA accepts audio/pcmu (μlaw) on both input and output. bridge.py supports μlaw direct-send, which bypasses the 8kHz μlaw ↔ 24kHz PCM resample (opt-in via AUDIO_FORMAT=ulaw). The default stays pcm16 (the current resample path), and verdict parity between pcm16 and μlaw has been measured live. Making μlaw the default will be considered after verification on real HGW hardware.

ℹ️Second gate implementation: in transition (Plan A → Plan B)

The decision→hangup path is now Plan B (function calling + AMI Hangup). The AI returns should_terminate, and after a brief closing line bridge.py hangs up the target channel via AMI. The legacy Plan A (verdict via AstDB) is archived and will be removed once on-device testing of Plan B passes.