Skip to main content

vox_rtc_server/
types.rs

1use serde::{Deserialize, Serialize};
2use serde_json::{Map, Value};
3
4pub const EVENT_CLIENT_EVENT: &str = "client.event";
5pub const EVENT_BROWSER_EVENT: &str = "browser.event";
6pub const EVENT_RTC_CLIENT_DISCONNECTED: &str = "rtc.client.disconnected";
7pub const EVENT_ERROR: &str = "error";
8pub const EVENT_INTERRUPTION_DETECTED: &str = "interruption.detected";
9pub const EVENT_INTERRUPTION_FALSE_POSITIVE: &str = "interruption.false_positive";
10pub const EVENT_RESPONSE_AUDIO_CLEAR: &str = "response.audio.clear";
11pub const EVENT_RESPONSE_CANCELLED: &str = "response.cancelled";
12pub const EVENT_RESPONSE_COMMITTED: &str = "response.committed";
13pub const EVENT_RESPONSE_CREATED: &str = "response.created";
14pub const EVENT_RESPONSE_DONE: &str = "response.done";
15pub const EVENT_RTC_SESSION_ATTACHED: &str = "rtc.session.attached";
16pub const EVENT_SESSION_CREATED: &str = "session.created";
17pub const EVENT_TRANSCRIPT_COMPLETED: &str =
18    "conversation.item.input_audio_transcription.completed";
19pub const EVENT_TURN_STATE_CHANGED: &str = "turn.state_changed";
20pub const EVENT_SPEECH_STARTED: &str = "input_audio_buffer.speech_started";
21pub const EVENT_SPEECH_STOPPED: &str = "input_audio_buffer.speech_stopped";
22pub const EVENT_TRANSCRIPT_DELTA: &str = "conversation.item.input_audio_transcription.delta";
23pub const EVENT_TURN_EOU_PREDICTED: &str = "turn.eou.predicted";
24
25pub type EventData = Map<String, Value>;
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
28pub enum ConnectionState {
29    Disconnected,
30    Connecting,
31    Connected,
32}
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35pub enum ChannelState {
36    Idle,
37    Joining,
38    Joined,
39    Closed,
40    Declined,
41}
42
43#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
44pub struct RtcIceServer {
45    pub urls: Value,
46    #[serde(default, skip_serializing_if = "Option::is_none")]
47    pub username: Option<String>,
48    #[serde(default, skip_serializing_if = "Option::is_none")]
49    pub credential: Option<String>,
50}
51
52#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
53pub struct SessionBootstrap {
54    pub session_id: String,
55    pub expires_at: String,
56    #[serde(default)]
57    pub attach_ttl_seconds: u64,
58    #[serde(default)]
59    pub ice_servers: Vec<RtcIceServer>,
60}
61
62#[derive(Debug, Clone, PartialEq, Eq)]
63pub struct RtcSessionDescription {
64    pub r#type: String,
65    pub sdp: String,
66}
67
68#[derive(Debug, Clone, PartialEq, Eq)]
69pub struct RtcIceCandidate {
70    pub candidate: String,
71    pub sdp_mid: Option<String>,
72    pub sdp_m_line_index: Option<u32>,
73    pub username_fragment: Option<String>,
74}
75
76#[derive(Debug, Clone, Default)]
77pub struct SessionConfig {
78    pub stt_model: Option<String>,
79    pub tts_model: Option<String>,
80    pub voice: Option<String>,
81    pub turn_profile: Option<String>,
82    pub vad_backend: Option<String>,
83    pub turn_detector: Option<String>,
84    pub extra: EventData,
85}
86
87#[derive(Debug, Clone, Default)]
88pub struct ResponseOptions {
89    pub allow_interruptions: Option<bool>,
90}
91
92#[derive(Debug, Clone)]
93pub struct ClientEventEnvelope {
94    pub event: String,
95    pub payload: Value,
96}
97
98#[derive(Debug, Clone)]
99pub struct WireEvent {
100    pub r#type: String,
101    pub data: EventData,
102    pub session_id: String,
103    pub channel_name: String,
104}
105
106#[derive(Debug, Clone)]
107pub struct SessionAttachedEvent {
108    pub session_id: String,
109    pub channel_name: String,
110    pub data: EventData,
111}
112
113#[derive(Debug, Clone)]
114pub struct SessionCreatedEvent {
115    pub session_id: String,
116    pub channel_name: String,
117    pub data: EventData,
118    pub session: Option<EventData>,
119}
120
121#[derive(Debug, Clone)]
122pub struct TranscriptEvent {
123    pub session_id: String,
124    pub channel_name: String,
125    pub data: EventData,
126    pub transcript: String,
127    pub language: Option<String>,
128    pub start_ms: Option<f64>,
129    pub end_ms: Option<f64>,
130    pub eou_probability: Option<f64>,
131    pub topics: Option<Vec<String>>,
132}
133
134#[derive(Debug, Clone)]
135pub struct TurnStateEvent {
136    pub session_id: String,
137    pub channel_name: String,
138    pub data: EventData,
139    pub state: String,
140    pub previous_state: Option<String>,
141}
142
143#[derive(Debug, Clone)]
144pub struct SpeechStartedEvent {
145    pub session_id: String,
146    pub channel_name: String,
147    pub data: EventData,
148    pub timestamp_ms: Option<f64>,
149}
150
151#[derive(Debug, Clone)]
152pub struct SpeechStoppedEvent {
153    pub session_id: String,
154    pub channel_name: String,
155    pub data: EventData,
156    pub timestamp_ms: Option<f64>,
157}
158
159#[derive(Debug, Clone)]
160pub struct TranscriptDeltaEvent {
161    pub session_id: String,
162    pub channel_name: String,
163    pub data: EventData,
164    pub delta: String,
165    pub start_ms: Option<f64>,
166    pub end_ms: Option<f64>,
167}
168
169#[derive(Debug, Clone)]
170pub struct TurnEouPredictedEvent {
171    pub session_id: String,
172    pub channel_name: String,
173    pub data: EventData,
174    pub probability: Option<f64>,
175    pub threshold: Option<f64>,
176    pub delay_ms: Option<f64>,
177    pub start_ms: Option<f64>,
178    pub end_ms: Option<f64>,
179    pub decision: Option<String>,
180    pub action: Option<String>,
181    pub turn_detector: Option<String>,
182}
183
184#[derive(Debug, Clone)]
185pub struct ResponseEvent {
186    pub session_id: String,
187    pub channel_name: String,
188    pub data: EventData,
189    pub response_id: Option<String>,
190}
191
192#[derive(Debug, Clone)]
193pub struct InterruptionEvent {
194    pub response: ResponseEvent,
195    pub vad_active_ms: Option<f64>,
196    pub partial_transcript: Option<String>,
197}
198
199#[derive(Debug, Clone)]
200pub struct BrowserEvent {
201    pub session_id: String,
202    pub channel_name: String,
203    pub data: EventData,
204    pub event: String,
205    pub payload: Value,
206}
207
208#[derive(Debug, Clone)]
209pub struct CloseEvent {
210    pub session_id: String,
211    pub channel_name: String,
212    pub data: EventData,
213    pub reason: String,
214    pub connection_state: Option<String>,
215    pub ice_connection_state: Option<String>,
216    pub data_channel_state: Option<String>,
217}
218
219#[derive(Debug, Clone)]
220pub struct ErrorEvent {
221    pub session_id: String,
222    pub channel_name: String,
223    pub data: EventData,
224    pub message: Option<String>,
225    pub code: Option<String>,
226}
227
228pub(crate) fn optional_string(data: &EventData, key: &str) -> Option<String> {
229    data.get(key).and_then(Value::as_str).map(ToOwned::to_owned)
230}
231
232pub(crate) fn required_string(data: &EventData, key: &str, fallback: &str) -> String {
233    optional_string(data, key)
234        .filter(|s| !s.is_empty())
235        .unwrap_or_else(|| fallback.to_owned())
236}
237
238pub(crate) fn optional_number(data: &EventData, key: &str) -> Option<f64> {
239    data.get(key).and_then(Value::as_f64)
240}
241
242pub(crate) fn optional_string_vec(data: &EventData, key: &str) -> Option<Vec<String>> {
243    data.get(key).and_then(Value::as_array).and_then(|items| {
244        items
245            .iter()
246            .map(|item| item.as_str().map(ToOwned::to_owned))
247            .collect()
248    })
249}