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 auto_hangup: Option<crate::callrecord::CallRecordHangupReason>,
167 },
168 Interruption {
169 track_id: String,
170 timestamp: u64,
171 play_id: Option<String>,
172 subtitle: Option<String>, position: Option<u32>, total_duration: u32, current: u32, },
177 AsrFinal {
178 track_id: String,
179 timestamp: u64,
180 index: u32,
181 start_time: Option<u64>,
182 end_time: Option<u64>,
183 text: String,
184 is_filler: Option<bool>,
185 confidence: Option<f32>,
186 task_id: Option<String>,
187 refer: Option<bool>,
188 },
189 AsrDelta {
190 track_id: String,
191 index: u32,
192 timestamp: u64,
193 start_time: Option<u64>,
194 end_time: Option<u64>,
195 text: String,
196 is_filler: Option<bool>,
197 confidence: Option<f32>,
198 task_id: Option<String>,
199 refer: Option<bool>,
200 },
201 Metrics {
202 timestamp: u64,
203 key: String,
204 duration: u32,
205 data: serde_json::Value,
206 },
207 Error {
208 track_id: String,
209 timestamp: u64,
210 sender: String,
211 error: String,
212 code: Option<u32>,
213 },
214 AddHistory {
215 sender: Option<String>,
216 timestamp: u64,
217 speaker: String,
218 text: String,
219 },
220 Other {
221 track_id: String,
222 timestamp: u64,
223 sender: String,
224 extra: Option<HashMap<String, String>>,
225 },
226 Binary {
227 track_id: String,
228 timestamp: u64,
229 data: Vec<u8>,
230 },
231 Ping {
232 timestamp: u64,
233 payload: Option<String>,
234 },
235 Custom {
236 timestamp: u64,
237 sender: Option<String>,
238 data: serde_json::Value,
239 },
240 RingbackState {
241 track_id: String,
242 timestamp: u64,
243 state: String,
245 state_index: u32,
247 confidence: f32,
249 prev_state: Option<String>,
251 prev_confidence: Option<f32>,
252 refer: Option<bool>,
253 #[serde(default)]
255 is_final: bool,
256 },
257}
258
259impl Display for SessionEvent {
260 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
261 match self {
262 SessionEvent::Silence {
263 track_id, duration, ..
264 } => {
265 write!(f, "Silence(track_id={}, duration={})", track_id, duration)
266 }
267 SessionEvent::Binary { track_id, data, .. } => {
268 write!(f, "Silence(track_id={}, data_len={})", track_id, data.len())
269 }
270 _ => {
271 write!(f, "{:?}", self)
272 }
273 }
274 }
275}
276
277pub type EventSender = tokio::sync::broadcast::Sender<SessionEvent>;
278pub type EventReceiver = tokio::sync::broadcast::Receiver<SessionEvent>;
279
280pub fn create_event_sender() -> EventSender {
281 EventSender::new(128)
282}