Character Components
EstuaryCharacter
MonoBehaviour -- Represents a single AI character. Attach one per character in your scene.
Namespace: Estuary
Inspector Fields
| Field | Type | Default | Description |
|---|---|---|---|
CharacterId | string | "" | The character's ID from the Estuary Dashboard |
PlayerId | string | "" | Player identifier. If blank, defaults to player_<device ID> |
AutoConnect | bool | true | Connect automatically on Start() |
AutoStartVoiceSession | bool | false | Start voice session after connecting |
StripActionsFromText | bool | true | Remove <action> tags from CurrentPartialResponse |
Properties
| Property | Type | Access | Description |
|---|---|---|---|
CharacterId | string | get/set | Character ID |
PlayerId | string | get/set | Player ID |
CurrentSession | SessionInfo | get | Session info after connecting (null before) |
CurrentPartialResponse | string | get | Accumulated streaming response text |
IsConnected | bool | get | true when this character's session is active |
IsVoiceSessionActive | bool | get | true when a voice session is running |
StripActionsFromText | bool | get/set | Whether to strip action tags from display text |
Methods
| Method | Returns | Description |
|---|---|---|
Connect() | void | Connect synchronously (fire-and-forget wrapper) |
ConnectAsync() | Task | Connect to the server |
Disconnect() | void | Disconnect synchronously |
DisconnectAsync() | Task | Disconnect from the server |
SendText(string text, bool? textOnly = null) | void | Send a text message. textOnly defaults to true when no voice session is active |
SendTextAsync(string text, bool? textOnly = null) | Task | Send a text message asynchronously |
StartVoiceSession() | void | Start voice mode (WebSocket: sends start_voice; LiveKit: requests token) |
EndVoiceSession() | void | End voice mode |
C# Events
| Event | Signature | Description |
|---|---|---|
OnConnected | Action<SessionInfo> | Connection established |
OnDisconnected | Action<string> | Connection lost (reason) |
OnBotResponse | Action<BotResponse> | Streaming text chunk received |
OnBotResponseComplete | Action<string> | Full response text when IsFinal is true |
OnTranscript | Action<SttResponse> | Speech-to-text result |
OnActionReceived | Action<AgentAction> | Action tag parsed from response |
OnError | Action<string> | Error message |
UnityEvents (Inspector)
These events appear in the Inspector and can be wired to any method without code:
| Event | Parameter | Description |
|---|---|---|
OnConnectedEvent | — | Fires after connection |
OnDisconnectedEvent | — | Fires on disconnect |
OnBotResponseEvent | string | Fires with each response chunk's text |
OnBotResponseCompleteEvent | string | Fires with the full final response |
OnTranscriptEvent | string | Fires with transcript text |
OnErrorEvent | string | Fires with error messages |
Default Player ID
When PlayerId is left blank, the SDK generates a default:
player_<first 8 characters of SystemInfo.deviceUniqueIdentifier>
This provides basic persistence across app sessions on the same device without requiring any setup.
EstuaryAudioSource
MonoBehaviour -- Plays streaming TTS audio from bot responses using a ring buffer for smooth, gap-free playback.
Namespace: Estuary
Inspector Fields
| Field | Type | Default | Description |
|---|---|---|---|
AutoInterruptOnUserSpeech | bool | false | Stop playback when the user starts speaking |
MicrophoneRef | EstuaryMicrophone | — | Required if AutoInterruptOnUserSpeech is enabled |
BufferLengthSeconds | float | 5.0 | Ring buffer length in seconds |
Properties
| Property | Type | Access | Description |
|---|---|---|---|
IsPlaying | bool | get | true while audio is playing |
CurrentMessageId | string | get | Message ID of the audio currently playing |
Methods
| Method | Returns | Description |
|---|---|---|
EnqueueAudio(float[] samples, int sampleRate, string messageId) | void | Write PCM float samples into the ring buffer |
EnqueueAudio(byte[] pcm16, int sampleRate, string messageId) | void | Write PCM16 bytes into the ring buffer (auto-converted to float) |
StopPlayback() | void | Stop playback and clear the buffer |
Events
| Event | Signature | Description |
|---|---|---|
OnPlaybackStarted | Action | Audio playback began |
OnPlaybackComplete | Action | Audio playback finished (buffer drained) |
OnPlaybackInterrupted | Action | Playback was stopped by an interrupt |
How It Works
WebSocket mode: Bot audio arrives as base64-encoded PCM16 chunks in bot_voice events. EstuaryManager decodes the audio and calls EnqueueAudio. The component:
- Converts PCM16 bytes to float samples
- Resamples if the server sample rate differs from Unity's output rate
- Writes to a circular ring buffer
- Feeds samples to a streaming
AudioClipvia a PCM reader callback (OnAudioRead)
The ring buffer ensures smooth playback even when network jitter causes irregular chunk delivery.
LiveKit mode: Audio playback is handled by LiveKit's AudioStream, which creates its own AudioSource at runtime. EstuaryAudioSource still tracks the current message_id for interrupt handling but defers actual playback to LiveKit.
Auto-Interrupt
When AutoInterruptOnUserSpeech is enabled and the referenced EstuaryMicrophone detects speech while the bot is talking:
- Playback stops and the buffer is cleared
OnPlaybackInterruptedfires- A
client_interruptevent is sent to the server with the currentmessage_id - The server stops generating audio for that message