# openalice-voice

> Rust SFU media server for real-time voice rooms (LiveKit-inspired): WebRTC/ICE/DTLS/SRTP signalling, pluggable TTS/STT providers, and transcript dispatch to live-control and social-api.

## At a glance
| field | value |
|---|---|
| kind | `service` |
| priority | `P3` |
| default branch | `mvp` |
| last activity | 2026-06-16T02:59:53+00:00 |
| features catalogued | **9** |
| runtime deps declared | **5** |

## Manifest
`.atlas-deps.yml` — parsed cleanly: **yes**

### Runtime deps
- **`openalice-agent-protocol-rs`** · `other` · via `cargo` — AgentRuntimeConfig + fetch_agent_config() helper for deserialising the unified agent config returned by openalice-auth's internal endpoint.
- **`openalice-auth`** · `http` · via `AUTH_INTERNAL_URL` — Fetch per-user unified agent_config (TTS/STT provider, voice id, emotion, pace, language) via /internal/agent-config/:user_id.
- **`openalice-axum-common`** · `other` · via `cargo` — Shared axum plumbing: internal_client() builder and verify_internal_secret() used by every inbound /api/v1/say and /internal/* call.
- **`openalice-live-control`** · `http` · via `VOICE_DISPATCH_URL` · _optional_ — POST /internal/agent/dispatch with ConnectorEvent::VoiceUtterance once the SFU's STT audio-capture path is wired (TranscriptDispatcher).
- **`openalice-social-api`** · `http` · via `VOICE_DISPATCH_URL` · _optional_ — Same dispatch endpoint — product=social path. Optional: voice does not need social-api at startup.

### Consumed env
- `VOICE_JWT_SECRET`
- `SHARED_JWT_SECRET`
- `VOICE_ALLOW_INSECURE`
- `INTERNAL_BROADCAST_SECRET`
- `INTERNAL_SECRET`
- `VOICE_API_KEY`
- `VOICE_API_SECRET`
- `VOICE_PORT`
- `VOICE_UDP_PORT`
- `VOICE_BIND`
- `VOICE_CORS_ORIGINS`
- `VOICE_RATE_LIMIT`
- `VOICE_MAX_ROOMS`
- `VOICE_MAX_PARTICIPANTS`
- `TTS_PROVIDER`
- `ELEVENLABS_API_KEY`
- `ELEVENLABS_BASE_URL`
- `ELEVENLABS_VOICE_ID`
- `ELEVENLABS_MODEL_ID`
- `ELEVENLABS_STREAMING_MODEL_ID`
- `CARTESIA_API_KEY`
- `CARTESIA_BASE_URL`
- `CARTESIA_MODEL`
- `CARTESIA_DEFAULT_VOICE`
- `CARTESIA_VOICE_ID`
- `OPENAI_API_KEY`
- `OPENAI_BASE_URL`
- `OPENAI_REALTIME_API_KEY`
- `OPENAI_REALTIME_BASE_URL`
- `OPENAI_REALTIME_MODEL`
- `OPENAI_REALTIME_VOICE`
- `OPENAI_TTS_MODEL`
- `OPENAI_TTS_VOICE`
- `HUME_API_KEY`
- `HUME_BASE_URL`
- `HUME_DEFAULT_VOICE`
- `GOOGLE_GEMINI_API_KEY`
- `GEMINI_API_KEY`
- `GEMINI_BASE_URL`
- `GEMINI_TTS_MODEL`
- `GEMINI_DEFAULT_VOICE`
- `OPENROUTER_API_KEY`
- `OPENROUTER_TTS_MODEL_ID`
- `DASHSCOPE_API_KEY`
- `DASHSCOPE_BASE_URL`
- `QWEN3_API_KEY`
- `QWEN3_TTS_MODEL`
- `QWEN3_DEFAULT_VOICE`
- `SESAME_ENDPOINT`
- `STT_PROVIDER`
- `DEEPGRAM_API_KEY`
- `DEEPGRAM_MODEL`
- `WHISPER_MODEL`
- `ASSEMBLYAI_API_KEY`
- `VOICE_CACHE_DIR`
- `OTEL_EXPORTER_OTLP_ENDPOINT`
- `OTEL_SERVICE_NAME`

### Exposes
- `docker_image` — openalice-voice
- `http_endpoint` — POST /api/v1/say — TTS synthesis (internal-secret-gated)
- `http_endpoint` — POST /api/v1/say-stream — streaming TTS + lipsync SSE (ElevenLabs)
- `http_endpoint` — POST /api/v1/rooms — create voice room
- `http_endpoint` — GET /api/v1/rooms — list voice rooms
- `http_endpoint` — POST /api/v1/tokens — issue room JWT
- `ws_endpoint` — WS /ws — WebRTC signalling (join/leave/offer/answer/ICE)
- `http_endpoint` — GET /internal/me/:tenant_id/export.json — GDPR TTS-cache export (internal-secret-gated)

## Live reachability
- last probe: **up** · `https://voice.blal.pro/health` · HTTP 200 · 1ms
- uptime 24h: **100.0%**

## Features (9)

### voice/agents
- **`voice.alice.tools`** · _experimental_ · since 0.1.0 — Voice tool schemas (voice_join, voice_leave, voice_speak, voice_status) for AI agents to participate in rooms.  
  *src/alice.rs:61*

### voice/audio
- **`voice.speaker.detect`** · _stable_ · since 0.1.0 — Active speaker detection using LiveKit 2-gate + EMA over RFC 6464 audio levels.  
  *src/rtp/speaker.rs:58*

### voice/auth
- **`voice.auth.token`** · _stable_ · since 0.1.0 — Issue a signed JWT (HS256) for joining a room with publish/subscribe scopes.  
  *src/lib.rs:138*

### voice/cluster
- **`voice.cluster.select-node`** · _stable_ · since 0.1.0 — Pick the best node for a new room using strategy (Any, LowestSysload, TwoChoice, RegionAware).  
  *src/cluster.rs:77*

### voice/quality
- **`voice.quality.mos`** · _stable_ · since 0.1.0 — Per-participant connection quality MOS score using LiveKit E-model with asymmetric smoothing.  
  *src/rtp/quality.rs:31*

### voice/rooms
- **`voice.rooms.create`** · _stable_ · since 0.1.0 — Create a new voice room with a name and participant cap.  
  *src/lib.rs:73*
- **`voice.rooms.list`** · _stable_ · since 0.1.0 — List active voice rooms with participant counts.  
  *src/lib.rs:103*

### voice/signal
- **`voice.signal.websocket`** · _stable_ · since 0.1.0 — WebSocket signalling channel for join/leave/mute/offer/answer/ICE.  
  *src/lib.rs:209*

### voice/transport
- **`voice.transport.udp-mux`** · _stable_ · since 0.1.0 — Single-port UDP mux with RFC 5764 packet classification (STUN/DTLS/RTP/RTCP).  
  *src/transport/mod.rs:91*

---

*Generated by [openalice-atlas](https://atlas.blal.pro) — single source of truth for the openalicelabs ecosystem.*
