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 headers: Option<HashMap<String, String>>,
40 },
41 Answer {
42 track_id: String,
43 timestamp: u64,
44 sdp: String,
45 refer: Option<bool>,
46 },
47 MediaReady {
48 track_id: String,
49 timestamp: u64,
50 },
51 Reject {
52 track_id: String,
53 timestamp: u64,
54 reason: String,
55 refer: Option<bool>,
56 code: Option<u32>,
57 },
58 Ringing {
59 track_id: String,
60 timestamp: u64,
61 early_media: bool,
62 refer: Option<bool>,
63 },
64 Hangup {
65 track_id: String,
66 timestamp: u64,
67 reason: Option<String>,
68 initiator: Option<String>,
69 start_time: String,
70 hangup_time: String,
71 answer_time: Option<String>,
72 ringing_time: Option<String>,
73 from: Option<Attendee>,
74 to: Option<Attendee>,
75 extra: Option<HashMap<String, serde_json::Value>>,
76 refer: Option<bool>,
77 },
78 AnswerMachineDetection {
79 track_id: String,
81 timestamp: u64,
82 start_time: u64,
83 end_time: u64,
84 text: String,
85 },
86 Interrupt {
87 receiver: Option<String>,
88 },
89 FunctionCall {
90 track_id: String,
91 call_id: String,
92 name: String,
93 arguments: String,
94 timestamp: u64,
95 },
96 Speaking {
97 track_id: String,
98 timestamp: u64,
99 start_time: u64,
100 is_filler: Option<bool>,
101 confidence: Option<f32>,
102 refer: Option<bool>,
103 },
104 Silence {
105 track_id: String,
106 timestamp: u64,
107 start_time: u64,
108 duration: u64,
109 refer: Option<bool>,
110 #[serde(skip)]
111 samples: Option<PcmBuf>,
112 },
113 Eou {
115 track_id: String,
116 timestamp: u64,
117 completed: bool,
118 interrupt_point: Option<String>,
119 text: Option<String>,
120 refer: Option<bool>,
121 },
122 Inactivity {
124 track_id: String,
125 timestamp: u64,
126 },
127 Dtmf {
128 track_id: String,
129 timestamp: u64,
130 digit: String,
131 refer: Option<bool>,
132 },
133 Hold {
134 track_id: String,
135 timestamp: u64,
136 on_hold: bool,
137 refer: Option<bool>,
138 },
139 TransferRequest {
140 track_id: String,
141 timestamp: u64,
142 refer_to: String,
143 referred_by: Option<String>,
144 refer: Option<bool>,
145 },
146 Message {
147 track_id: String,
148 timestamp: u64,
149 body: String,
150 content_type: Option<String>,
151 refer: Option<bool>,
152 },
153 TrackStart {
154 track_id: String,
155 timestamp: u64,
156 play_id: Option<String>,
157 },
158 TrackEnd {
159 track_id: String,
160 timestamp: u64,
161 duration: u64,
162 ssrc: u32,
163 play_id: Option<String>,
164 },
165 Interruption {
166 track_id: String,
167 timestamp: u64,
168 play_id: Option<String>,
169 subtitle: Option<String>, position: Option<u32>, total_duration: u32, current: u32, },
174 AsrFinal {
175 track_id: String,
176 timestamp: u64,
177 index: u32,
178 start_time: Option<u64>,
179 end_time: Option<u64>,
180 text: String,
181 is_filler: Option<bool>,
182 confidence: Option<f32>,
183 task_id: Option<String>,
184 refer: Option<bool>,
185 },
186 AsrDelta {
187 track_id: String,
188 index: u32,
189 timestamp: u64,
190 start_time: Option<u64>,
191 end_time: Option<u64>,
192 text: String,
193 is_filler: Option<bool>,
194 confidence: Option<f32>,
195 task_id: Option<String>,
196 refer: Option<bool>,
197 },
198 Metrics {
199 timestamp: u64,
200 key: String,
201 duration: u32,
202 data: serde_json::Value,
203 },
204 Error {
205 track_id: String,
206 timestamp: u64,
207 sender: String,
208 error: String,
209 code: Option<u32>,
210 },
211 AddHistory {
212 sender: Option<String>,
213 timestamp: u64,
214 speaker: String,
215 text: String,
216 },
217 Other {
218 track_id: String,
219 timestamp: u64,
220 sender: String,
221 extra: Option<HashMap<String, String>>,
222 },
223 Binary {
224 track_id: String,
225 timestamp: u64,
226 data: Vec<u8>,
227 },
228 Ping {
229 timestamp: u64,
230 payload: Option<String>,
231 },
232 Custom {
233 timestamp: u64,
234 sender: Option<String>,
235 data: serde_json::Value,
236 },
237 RingbackState {
238 track_id: String,
239 timestamp: u64,
240 state: String,
242 state_index: u32,
244 confidence: f32,
246 prev_state: Option<String>,
248 prev_confidence: Option<f32>,
249 refer: Option<bool>,
250 #[serde(default)]
252 is_final: bool,
253 },
254}
255
256impl Display for SessionEvent {
257 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
258 match self {
259 SessionEvent::Silence {
260 track_id, duration, ..
261 } => {
262 write!(f, "Silence(track_id={}, duration={})", track_id, duration)
263 }
264 SessionEvent::Binary { track_id, data, .. } => {
265 write!(f, "Silence(track_id={}, data_len={})", track_id, data.len())
266 }
267 _ => {
268 write!(f, "{:?}", self)
269 }
270 }
271 }
272}
273
274pub type EventSender = tokio::sync::broadcast::Sender<SessionEvent>;
275pub type EventReceiver = tokio::sync::broadcast::Receiver<SessionEvent>;
276
277pub fn create_event_sender() -> EventSender {
278 EventSender::new(128)
279}