Connection Details
WebSocket Endpoint
URL: wss://your-server-url/voice-stream
Sending (Mic → Server)
Raw PCM, 16,000 Hz, 16-bit Signed Little-Endian, Mono
Receiving (Server → Client)
Same format - PCM audio from the AI
Connection Flow
Open WebSocket
Connect to the WebSocket endpoint URL
Send Token
Immediately send your JWT token as a text message
Wait for Confirmation
Server sends savant_voice_connected when ready
Start Streaming
Begin bidirectional audio streaming
Message Types
Server → Client
Connection Confirmed:
{
"type": "savant_voice_connected",
"message": "Connection established"
}
Error Message:
{
"type": "error",
"error": {
"message": "Error description",
"code": "ERROR_CODE"
}
}
Audio Data: Binary data containing PCM audio from AI
Client → Server
- Token: String containing JWT
- Audio: Binary PCM data from microphone
Implementation Example
websocket_connection.dart
class WebSocketManager {
WebSocketChannel? _channel;
StreamSubscription<dynamic>? _subscription;
Future<void> connect(String token) async {
// 1. Connect to WebSocket
final wsUrl = '${dotenv.env['API_BASE_URL']}'
.replaceFirst(RegExp(r'^http'), 'ws') + '/voice-stream';
_channel = WebSocketChannel.connect(Uri.parse(wsUrl));
// 2. Listen for messages
_subscription = _channel!.stream.listen(
_handleMessage,
onError: _handleError,
onDone: _handleDisconnection,
);
// 3. Send authentication token
_channel!.sink.add(token);
}
void _handleMessage(dynamic message) {
if (message is String) {
final data = jsonDecode(message);
if (data['type'] == 'vapi_connected') {
// Start audio streaming
_startAudioStreaming();
}
} else if (message is List<int>) {
// Handle incoming audio
_playAudioChunk(Uint8List.fromList(message));
}
}
}
Error Handling
Always implement proper error handling for connection issues, authentication failures, and unexpected disconnections.
Next Steps