Core Components
EstuaryManager
MonoBehaviour -- Singleton that owns the network connection and coordinates all Estuary components.
Namespace: Estuary
Accessing the Singleton
EstuaryManager.Instance
If no instance exists in the scene, accessing Instance creates a new GameObject named EstuaryManager automatically. The instance persists across scene loads (DontDestroyOnLoad).
EstuaryManager.HasInstance returns true only if an instance already exists (does not create one).
Inspector Fields
| Field | Type | Default | Description |
|---|---|---|---|
Config | EstuaryConfig | — | Reference to your configuration asset |
DebugLogging | bool | false | Enable verbose logging on the manager and underlying client |
AutoConnect lives on EstuaryCharacter, not EstuaryManager. Each character decides whether to connect when it starts.
Properties
| Property | Type | Access | Description |
|---|---|---|---|
Instance | EstuaryManager | static get | Singleton accessor (creates one if needed) |
HasInstance | bool | static get | true if an instance exists |
Config | EstuaryConfig | get/set | Configuration asset |
IsConnected | bool | get | true when Socket.IO is connected |
ConnectionState | ConnectionState | get | Current connection state |
DebugLogging | bool | get/set | Enable verbose logs (also applied to underlying client and LiveKit manager) |
LiveKitState | LiveKitConnectionState | get | Current LiveKit connection state |
IsLiveKitReady | bool | get | true when LiveKit is available and the room is ready |
IsLiveKitEnabled | bool | get | true when LiveKit mode is configured and the LiveKit assembly is present |
IsVoiceModeActive | bool | get | true when backend STT is active (after StartVoiceModeAsync) |
LiveKitManager | ILiveKitVoiceManager | get | The LiveKit voice manager (or null if the LiveKit SDK is not installed) |
ActiveCharacter | EstuaryCharacter | get | Currently active character |
Methods
| Method | Returns | Description |
|---|---|---|
Connect() | void | Fire-and-forget wrapper for ConnectAsync() |
ConnectAsync() | Task | Connect using Config and the active character |
Disconnect() | void | Fire-and-forget wrapper for DisconnectAsync() |
DisconnectAsync() | Task | Disconnect from LiveKit (if connected) and Socket.IO |
RegisterCharacter(EstuaryCharacter character) | void | Register a character (called automatically by EstuaryCharacter.Start) |
UnregisterCharacter(EstuaryCharacter character) | void | Unregister a character |
SetActiveCharacter(EstuaryCharacter character) | void | Switch the active character (reconnects if already connected) |
SendTextAsync(string text) | Task | Send a text message via the active character |
SendTextAsync(string text, bool textOnly) | Task | Send a text message; textOnly=true suppresses TTS |
SayLineAsync(string text, bool textOnly = false) | Task | Script the active character to say a specific prewritten line via TTS |
StreamAudioAsync(string audioBase64) | Task | Stream base64-encoded PCM audio for STT (WebSocket voice mode) |
NotifyAudioPlaybackCompleteAsync() | Task | Notify the server that local TTS playback has finished |
NotifyInterruptAsync(string messageId = null) | Task | Tell the server to stop streaming TTS for the given (or current) message |
StartVoiceModeAsync() | Task | Enable backend STT |
StopVoiceModeAsync() | Task | Disable backend STT |
RequestLiveKitTokenAsync() | Task | Request a LiveKit token from the server |
ConnectLiveKitAsync() | Task | Connect to LiveKit using the most recently received token |
ConnectLiveKitWithTokenAsync(LiveKitTokenResponse token) | Task | Connect to LiveKit using a specific token response |
DisconnectLiveKitAsync() | Task | Leave the LiveKit room and notify the server |
StartLiveKitPublishingAsync() | Task | Start publishing the microphone over LiveKit |
StopLiveKitPublishingAsync() | Task | Stop publishing the microphone over LiveKit |
Events
| Event | Signature | Description |
|---|---|---|
OnConnectionStateChanged | EstuaryEvents.ConnectionStateHandler (Action<ConnectionState>) | Fired when Socket.IO connection state changes |
OnError | EstuaryEvents.ErrorHandler (Action<string>) | Fired on global errors |
OnLiveKitStateChanged | Action<LiveKitConnectionState> | Fired when LiveKit connection state changes |
OnLiveKitReady | Action<string> | Fired when the LiveKit room is ready (room name) |
OnActiveCharacterChanged | Action<EstuaryCharacter, EstuaryCharacter> | Fired when the active character changes (previous, current) |
OnBotAudioSourceCreated | Action<AudioSource> | Fired when LiveKit creates the bot's AudioSource (for lip sync) |
EstuaryClient
Low-level Socket.IO v4 client used internally by EstuaryManager. You normally do not need to touch this class directly; use EstuaryManager for all application code.
Namespace: Estuary
EstuaryClient implements the Socket.IO v4 protocol over a raw ClientWebSocket. It handles packet framing, namespace connection (with auth payload), JSON event payloads, ping/pong heartbeats, and automatic reconnection (up to 5 attempts with linear backoff).
Inside EstuaryManager the EstuaryClient instance is private. The signatures below describe the underlying class for advanced/debug scenarios; reach for EstuaryManager's methods first.
Properties
| Property | Type | Description |
|---|---|---|
State | ConnectionState | Current connection state |
IsConnected | bool | true when the namespace is connected |
CurrentSession | SessionInfo | Session info after the server emits session_info (null otherwise) |
DebugLogging | bool | Toggle verbose logs |
IsVoiceModeActive | bool | true after StartVoiceModeAsync succeeds |
Methods
| Method | Returns | Description |
|---|---|---|
ConnectAsync(string serverUrl, string apiKey, string characterId, string playerId, int audioSampleRate = 48000, string token = null) | Task | Open the WebSocket and perform the Socket.IO handshake. Either apiKey or token must be supplied. |
DisconnectAsync() | Task | Close the connection gracefully |
SendTextAsync(string text) | Task | Emit a text event |
SendTextAsync(string text, bool textOnly) | Task | Emit a text event with text_only override |
SayLineAsync(string text, bool textOnly = false) | Task | Emit a say_line event for scripted lines |
StreamAudioAsync(string audioBase64) | Task | Emit a stream_audio event with base64-encoded PCM (WebSocket voice mode) |
NotifyAudioPlaybackCompleteAsync() | Task | Emit audio_playback_complete |
NotifyInterruptAsync(string messageId = null) | Task | Emit client_interrupt |
StartVoiceModeAsync() | Task | Emit start_voice |
StopVoiceModeAsync() | Task | Emit stop_voice |
RequestLiveKitTokenAsync() | Task | Emit livekit_token |
NotifyLiveKitJoinedAsync() | Task | Emit livekit_join |
NotifyLiveKitLeftAsync() | Task | Emit livekit_leave |
NotifyLiveKitMuteAsync(bool muted) | Task | Emit livekit_mute for mute-state UI sync |
EmitAsync(string eventName, object data) | Task | Emit a custom Socket.IO event |
Events (Delegates)
| Event | Signature | Description |
|---|---|---|
OnSessionConnected | EstuaryEvents.SessionConnectedHandler (Action<SessionInfo>) | session_info received |
OnDisconnected | EstuaryEvents.DisconnectedHandler (Action<string>) | Connection lost (reason) |
OnBotResponse | EstuaryEvents.BotResponseHandler (Action<BotResponse>) | bot_response chunk received |
OnBotVoice | EstuaryEvents.BotVoiceHandler (Action<BotVoice>) | bot_voice audio chunk received |
OnSttResponse | EstuaryEvents.SttResponseHandler (Action<SttResponse>) | stt_response transcription received |
OnInterrupt | EstuaryEvents.InterruptHandler (Action<InterruptData>) | interrupt confirmation received |
OnError | EstuaryEvents.ErrorHandler (Action<string>) | error or auth error received |
OnConnectionStateChanged | EstuaryEvents.ConnectionStateHandler (Action<ConnectionState>) | Connection state changed |
OnLiveKitTokenReceived | Action<LiveKitTokenResponse> | livekit_token payload received |
OnLiveKitReady | Action<string> | livekit_ready received (room name) |
OnLiveKitError | Action<string> | livekit_error received |
OnVoiceStarted | Action | voice_started received |
OnVoiceStopped | Action | voice_stopped received |
OnVoiceError | Action<string> | voice_error received |
OnQuotaExceeded | Action<QuotaExceededData> | quota_exceeded received |
EstuaryConfig
ScriptableObject -- Stores global SDK configuration. Character-specific settings (CharacterId, PlayerId) live on EstuaryCharacter.
Namespace: Estuary
Creating a Config Asset
In the Editor: Right-click in the Project window > Create > Estuary > Config.
In Code:
// API key first, then optional server URL
var config = EstuaryConfig.CreateForDevelopment("est_yourkey");
// Or with a custom server URL
var config = EstuaryConfig.CreateForDevelopment("est_yourkey", "http://localhost:4001");
Fields
| Field | Type | Default | Description |
|---|---|---|---|
ServerUrl | string | https://api.estuary-ai.com | Estuary server URL |
ApiKey | string | "" | API key for authentication (est_...). Optional when TokenProvider is set. |
VoiceMode | VoiceMode | LiveKit | Voice transport: WebSocket or LiveKit |
DebugLogging | bool | false | Enable verbose logging |
Properties
| Property | Type | Access | Description |
|---|---|---|---|
IsLiveKitEnabled | bool | get | Convenience: VoiceMode == VoiceMode.LiveKit |
TokenProvider | Func<Task<string>> | get/set | Async token provider (e.g., Firebase). When set, the SDK uses the returned Bearer token for auth instead of the API key. Not serialized. |
Methods
| Method | Returns | Description |
|---|---|---|
SetApiKeyRuntime(string key) | void | Set the API key at runtime (does not persist to disk) |
SetServerUrlRuntime(string url) | void | Set the server URL at runtime |
IsValid() | bool | true if both server URL and (API key or token provider) are set |
GetValidationError() | string | Human-readable validation error, or null when valid |
CreateDefault() | EstuaryConfig | Static: create a default in-memory config |
CreateForDevelopment(string apiKey, string serverUrl = "http://localhost:4001") | EstuaryConfig | Static: create a development config with debug logging enabled |
:::info Audio sample rate
Sample rates are not configured on EstuaryConfig. The SDK uses Unity's AudioSettings.outputSampleRate for TTS playback and forwards it during the Socket.IO handshake so the backend can match. Recording for WebSocket STT is fixed at 16 kHz.
:::