LiveKit Integration
The Estuary Unity SDK supports LiveKit as an optional transport for low-latency WebRTC voice. The public surface is the ILiveKitVoiceManager interface in the core Estuary namespace. The concrete implementation lives in a separate Estuary.LiveKit assembly that only compiles when the LiveKit Unity SDK is installed (the assembly is gated by the ESTUARY_LIVEKIT scripting define, set automatically when io.livekit.livekit-sdk is detected).
EstuaryManager creates and uses the manager internally -- you normally do not interact with it directly. Reach for it only when you need lip sync, custom mute logic, or other advanced integration.
ILiveKitVoiceManager
Namespace: Estuary
Access the active manager via:
ILiveKitVoiceManager liveKit = EstuaryManager.Instance.LiveKitManager;
Returns null if the LiveKit SDK is not installed. Check EstuaryManager.Instance.IsLiveKitEnabled first.
Properties
| Property | Type | Access | Description |
|---|---|---|---|
IsConnected | bool | get | true when connected to a LiveKit room |
IsPublishing | bool | get | true when the microphone track is publishing |
IsMuted | bool | get | true when the microphone is muted |
IsBotAudioMuted | bool | get | true when bot audio is muted (e.g., during interrupts) |
CurrentRoomName | string | get | Name of the current LiveKit room (null if not connected) |
OutputVolume | float | get/set | Bot audio output volume (0–1). Applied to the bot AudioSource. |
DebugLogging | bool | get/set | Toggle verbose logs |
Methods
| Method | Returns | Description |
|---|---|---|
SetCoroutineRunner(MonoBehaviour runner) | void | Set the MonoBehaviour used to run LiveKit coroutines |
ConnectAsync(string url, string token, string roomName) | Task<bool> | Connect to a LiveKit room |
DisconnectAsync() | Task | Leave the room and clean up |
StartPublishingAsync() | Task<bool> | Publish the microphone track |
StopPublishingAsync() | Task | Unpublish the microphone track |
MuteAsync() | Task | Mute the microphone |
UnmuteAsync() | Task | Unmute the microphone |
ToggleMuteAsync() | Task | Toggle mute state |
SignalInterruptAsync(string messageId = null, float interruptedAt = 0f) | Task | Notify the server to stop streaming TTS and immediately mute bot audio |
MuteBotAudio(bool muted) | void | Mute/unmute the bot's audio track locally (volume-based) |
NotifyAudioChunk(string messageId, float timestamp = 0f) | bool | Track an incoming audio chunk; returns false if the chunk should be discarded |
ProcessMainThreadQueue() | void | Drain queued events onto the Unity main thread (called by EstuaryManager.Update) |
PrewarmRoom() | void | Pre-create the LiveKit Room instance to save allocation time on connect |
GetRoom() | object | Get the underlying LiveKit Room (treat as opaque -- consumers should cast inside the Estuary.LiveKit assembly) |
Events
| Event | Signature | Description |
|---|---|---|
OnConnected | Action<string> | Connected to the room (room name) |
OnDisconnected | Action<string> | Disconnected from the room (reason) |
OnError | Action<string> | Connection or publishing error |
OnMuteStateChanged | Action<bool> | Microphone mute state changed (true = muted) |
OnBotAudioSourceCreated | Action<AudioSource> | Bot's AudioSource created at runtime (use for lip sync) |
Connection Flow
1. EstuaryManager calls EstuaryClient.RequestLiveKitTokenAsync()
2. Server responds with livekit_token (JWT, URL, room name)
3. EstuaryManager calls ILiveKitVoiceManager.ConnectAsync(url, token, room)
4. Manager connects to the room → OnConnected fires
5. EstuaryManager calls EstuaryClient.NotifyLiveKitJoinedAsync()
6. Server joins the bot to the room and emits livekit_ready
7. EstuaryManager.LiveKitState transitions: WaitingForBot → Ready
8. The manager subscribes to the bot's audio track
9. OnBotAudioSourceCreated fires with the runtime AudioSource
Interrupt Handling
When SignalInterruptAsync is called:
- The server is notified via
client_interrupt - Bot audio is muted locally by setting the bot
AudioSourcevolume to 0 (preserves the audio pipeline) - The interrupted
messageIdand timestamp are recorded - Subsequent audio chunks for the interrupted message (or with stale timestamps) are discarded by
NotifyAudioChunk - When a new message arrives with a different
messageId, bot audio is unmuted automatically
Optional Dependency
The LiveKit integration is optional. The Estuary SDK's text-only features work without LiveKit installed.
| Package | Version | Purpose |
|---|---|---|
io.livekit.livekit-sdk | 1.3.3+ | WebRTC voice transport |
Install via the Package Manager:
https://github.com/livekit/client-sdk-unity.git#v1.3.3
The Estuary SDK ships with an Editor-only auto-installer that detects a missing LiveKit SDK on domain reload and offers to install it via UPM. When LiveKit is not installed, EstuaryManager.IsLiveKitEnabled returns false, LiveKitManager is null, and the SDK gracefully falls back to WebSocket-only behavior.
When LiveKit is installed, Unity automatically defines the ESTUARY_LIVEKIT scripting symbol via versionDefines, which compiles the Estuary.LiveKit assembly containing the concrete LiveKitVoiceManager, microphone sources, and registrar.