Voicebeta
Add the microphone to KletsoChat, drive voice sessions from your own UI, and bring your own audio stack if you need to.
kletso_flutter draws the mic button, the voice sheet and the avatar but ships no platform code. Add kletso_voice for the microphone and speaker:
flutter pub add kletso_voice
final client = await Kletso.init(KletsoConfig(publishableKey: 'kl_pub_…', agentId: 'agt_…'));
KletsoVoice.install(client);
That is all. When the agent has voice enabled, KletsoChat shows a microphone next to the send button. Tapping it asks for microphone permission, opens the voice sheet (big avatar, state label, live captions, rendered surfaces, mute, keyboard and End) and starts the session. The chat transcript fills in as the conversation goes.
Platforms
| Platform | Capture | Playback |
|---|---|---|
| Android | record_android (RECORD_AUDIO permission in your manifest) | audio_stream_player |
| iOS | record_ios (NSMicrophoneUsageDescription in Info.plist) | audio_stream_player |
| Web (JS and Wasm) | Web Audio through package:web (no dart:html) | audio_stream_player |
| macOS, Windows, Linux | record_* implementations | audio_stream_player |
Browsers need a user gesture before audio plays; the mic tap counts. Voice needs the WebSocket transport (the default); on the SSE fallback the mic button is hidden.
Driving it yourself
Everything the sheet does is available on client.voice, a KletsoVoiceController:
final voice = client.voice;
voice.status; // KletsoValueListenable<KletsoVoiceStatus>: idle, connecting, listening, thinking, speaking
voice.userTranscript; // what the user is saying (partial, then final)
voice.caption; // what the assistant is saying
voice.outputLevel; // 0..1 loudness of the assistant, for your own lip-sync or meter
voice.available; // agent has voice, socket can carry audio, audio IO installed
await voice.start(); // throws KletsoServerException(code: 'not_configured') when the customer has no key
voice.setMuted(true);
voice.sendText('Make that two tickets'); // typed text, answered aloud
voice.commit(); // push-to-talk release
await voice.stop();
Put a KletsoAvatar anywhere in your app; bound to the client it reacts to the same events as the chat (see the avatar section of the chat UI page).
Your own audio stack
Implement KletsoAudioIo from kletso_core (capture stream, enqueue, flush, playedMs, levels) and hand it to client.voice.setAudioIo(yourIo). If your app already plays and records audio, call client.voice.setHostHandlesAudio(true), feed client.voice.sendAudio(pcm) and play client.voice.audioOut. PCM is 16-bit little-endian mono at 24 kHz on both sides.
Testing
KletsoFakeBackend has a voice scenario: about one second of any audio counts as the utterance scenario.voiceTranscript, which the fake answers aloud (a synthesised tone with a transcript), so widget tests and the example app exercise the whole flow without a key or a microphone.