1use crate::media::PcmBuf;
2use serde::{Deserialize, Serialize};
3use serde_with::skip_serializing_none;
4use std::{collections::HashMap, fmt::Display};
5
6#[derive(Debug, Clone, Serialize, Deserialize)]
7#[serde(rename_all = "camelCase")]
8pub struct Attendee {
9 pub username: String,
10 pub realm: String,
11 pub source: String,
12}
13
14impl From<&String> for Attendee {
15 fn from(source: &String) -> Self {
16 let uri = rsipstack::rsip::Uri::try_from(source.as_str()).unwrap_or_default();
17 Self {
18 username: uri.user().unwrap_or_default().to_string(),
19 realm: uri.host().to_string(),
20 source: source.to_string(),
21 }
22 }
23}
24
25#[skip_serializing_none]
26#[derive(Debug, Clone, Serialize, Deserialize)]
27#[serde(
28 tag = "event",
29 rename_all = "camelCase",
30 rename_all_fields = "camelCase"
31)]
32pub enum SessionEvent {
33 Incoming {
34 track_id: String,
35 timestamp: u64,
36 caller: String,
37 callee: String,
38 sdp: String,
39 },
40 Answer {
41 track_id: String,
42 timestamp: u64,
43 sdp: String,
44 refer: Option<bool>,
45 },
46 MediaReady {
47 track_id: String,
48 timestamp: u64,
49 },
50 Reject {
51 track_id: String,
52 timestamp: u64,
53 reason: String,
54 refer: Option<bool>,
55 code: Option<u32>,
56 },
57 Ringing {
58 track_id: String,
59 timestamp: u64,
60 early_media: bool,
61 refer: Option<bool>,
62 },
63 Hangup {
64 track_id: String,
65 timestamp: u64,
66 reason: Option<String>,
67 initiator: Option<String>,
68 start_time: String,
69 hangup_time: String,
70 answer_time: Option<String>,
71 ringing_time: Option<String>,
72 from: Option<Attendee>,
73 to: Option<Attendee>,
74 extra: Option<HashMap<String, serde_json::Value>>,
75 refer: Option<bool>,
76 },
77 AnswerMachineDetection {
78 track_id: String,
80 timestamp: u64,
81 start_time: u64,
82 end_time: u64,
83 text: String,
84 },
85 Interrupt {
86 receiver: Option<String>,
87 },
88 FunctionCall {
89 track_id: String,
90 call_id: String,
91 name: String,
92 arguments: String,
93 timestamp: u64,
94 },
95 Speaking {
96 track_id: String,
97 timestamp: u64,
98 start_time: u64,
99 is_filler: Option<bool>,
100 confidence: Option<f32>,
101 refer: Option<bool>,
102 },
103 Silence {
104 track_id: String,
105 timestamp: u64,
106 start_time: u64,
107 duration: u64,
108 refer: Option<bool>,
109 #[serde(skip)]
110 samples: Option<PcmBuf>,
111 },
112 Eou {
114 track_id: String,
115 timestamp: u64,
116 completed: bool,
117 interrupt_point: Option<String>,
118 text: Option<String>,
119 refer: Option<bool>,
120 },
121 Inactivity {
123 track_id: String,
124 timestamp: u64,
125 },
126 Dtmf {
127 track_id: String,
128 timestamp: u64,
129 digit: String,
130 refer: Option<bool>,
131 },
132 Hold {
133 track_id: String,
134 timestamp: u64,
135 on_hold: bool,
136 refer: Option<bool>,
137 },
138 TransferRequest {
139 track_id: String,
140 timestamp: u64,
141 refer_to: String,
142 referred_by: Option<String>,
143 refer: Option<bool>,
144 },
145 Message {
146 track_id: String,
147 timestamp: u64,
148 body: String,
149 content_type: Option<String>,
150 refer: Option<bool>,
151 },
152 TrackStart {
153 track_id: String,
154 timestamp: u64,
155 play_id: Option<String>,
156 },
157 TrackEnd {
158 track_id: String,
159 timestamp: u64,
160 duration: u64,
161 ssrc: u32,
162 play_id: Option<String>,
163 },
164 Interruption {
165 track_id: String,
166 timestamp: u64,
167 play_id: Option<String>,
168 subtitle: Option<String>, position: Option<u32>, total_duration: u32, current: u32, },
173 AsrFinal {
174 track_id: String,
175 timestamp: u64,
176 index: u32,
177 start_time: Option<u64>,
178 end_time: Option<u64>,
179 text: String,
180 is_filler: Option<bool>,
181 confidence: Option<f32>,
182 task_id: Option<String>,
183 refer: Option<bool>,
184 },
185 AsrDelta {
186 track_id: String,
187 index: u32,
188 timestamp: u64,
189 start_time: Option<u64>,
190 end_time: Option<u64>,
191 text: String,
192 is_filler: Option<bool>,
193 confidence: Option<f32>,
194 task_id: Option<String>,
195 refer: Option<bool>,
196 },
197 Metrics {
198 timestamp: u64,
199 key: String,
200 duration: u32,
201 data: serde_json::Value,
202 },
203 Error {
204 track_id: String,
205 timestamp: u64,
206 sender: String,
207 error: String,
208 code: Option<u32>,
209 },
210 AddHistory {
211 sender: Option<String>,
212 timestamp: u64,
213 speaker: String,
214 text: String,
215 },
216 Other {
217 track_id: String,
218 timestamp: u64,
219 sender: String,
220 extra: Option<HashMap<String, String>>,
221 },
222 Binary {
223 track_id: String,
224 timestamp: u64,
225 data: Vec<u8>,
226 },
227 Ping {
228 timestamp: u64,
229 payload: Option<String>,
230 },
231 Custom {
232 timestamp: u64,
233 sender: Option<String>,
234 data: serde_json::Value,
235 },
236 RingbackState {
237 track_id: String,
238 timestamp: u64,
239 state: String,
241 state_index: u32,
243 confidence: f32,
245 prev_state: Option<String>,
247 prev_confidence: Option<f32>,
248 refer: Option<bool>,
249 #[serde(default)]
251 is_final: bool,
252 },
253}
254
255impl Display for SessionEvent {
256 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
257 match self {
258 SessionEvent::Silence {
259 track_id, duration, ..
260 } => {
261 write!(f, "Silence(track_id={}, duration={})", track_id, duration)
262 }
263 SessionEvent::Binary { track_id, data, .. } => {
264 write!(f, "Silence(track_id={}, data_len={})", track_id, data.len())
265 }
266 _ => {
267 write!(f, "{:?}", self)
268 }
269 }
270 }
271}
272
273pub type EventSender = tokio::sync::broadcast::Sender<SessionEvent>;
274pub type EventReceiver = tokio::sync::broadcast::Receiver<SessionEvent>;
275
276pub fn create_event_sender() -> EventSender {
277 EventSender::new(128)
278}