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