WebSocket Protocol
After starting a session via REST, connect to the WebSocket endpoint for real-time bidirectional audio streaming.
TEXT
wss://ultravoice.us.inc/api/v1/voice/ws/{session_id}Audio Format
Sending Audio (Client → Server)
- Format: Raw PCM Int16 (16-bit signed integer)
- Sample rate: 16,000 Hz (16kHz)
- Channels: Mono (1 channel)
- Frame size: Any size, 4096 samples recommended
- Frame type: Binary WebSocket frames
Receiving Audio (Server → Client)
- Format: WAV-wrapped PCM audio (binary frames)
- Sample rate: Matches TTS provider output (typically 22050 or 24000 Hz)
- Channels: Mono
Events Reference
The server sends JSON text frames alongside audio binary frames:
JAVASCRIPT
// Session start
{ "type": "session_start", "session_id": "...", "agent_id": "..." }
// Transcript (partial)
{ "type": "transcript_partial", "text": "Hello, how can I", "is_final": false }
// Transcript (final)
{ "type": "transcript_final", "text": "Hello, how can I help you today?", "is_final": true }
// AI response (streaming)
{ "type": "llm_token", "text": "I'd", "turn_id": "t1" }
// AI response (complete)
{ "type": "llm_complete", "text": "I'd be happy to help!", "turn_id": "t1" }
// Tool call
{ "type": "tool_call", "name": "lookup_order", "args": {"order_id": "ORD-123"} }
// Tool result
{ "type": "tool_result", "name": "lookup_order", "result": "Order shipped on Jan 15" }
// Session end
{ "type": "session_end", "reason": "user_ended" }
// Error
{ "type": "error", "code": "asr_timeout", "message": "ASR provider timed out" }Browser Client Example
JAVASCRIPT
const ws = new WebSocket('wss://ultravoice.us.inc/api/v1/voice/ws/SESSION_ID');
ws.binaryType = 'arraybuffer';
// Capture microphone
const stream = await navigator.mediaDevices.getUserMedia({
audio: { sampleRate: 16000, channelCount: 1, echoCancellation: true }
});
const ctx = new AudioContext({ sampleRate: 16000 });
const source = ctx.createMediaStreamSource(stream);
const processor = ctx.createScriptProcessor(4096, 1, 1);
source.connect(processor);
processor.connect(ctx.destination);
// Send audio
processor.onaudioprocess = (e) => {
if (ws.readyState !== WebSocket.OPEN) return;
const float32 = e.inputBuffer.getChannelData(0);
const int16 = new Int16Array(float32.length);
for (let i = 0; i < float32.length; i++) {
int16[i] = Math.max(-32768, Math.min(32767, float32[i] * 32768));
}
ws.send(int16.buffer);
};
// Receive messages
ws.onmessage = (e) => {
if (e.data instanceof ArrayBuffer) {
playAudio(e.data); // Play TTS audio
} else {
const event = JSON.parse(e.data);
console.log(event.type, event.text || '');
}
};