use crate::media::PcmBuf;
use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
use std::{collections::HashMap, fmt::Display};
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Attendee {
pub username: String,
pub realm: String,
pub source: String,
}
impl From<&String> for Attendee {
fn from(source: &String) -> Self {
let uri = rsipstack::rsip::Uri::try_from(source.as_str()).unwrap_or_default();
Self {
username: uri.user().unwrap_or_default().to_string(),
realm: uri.host().to_string(),
source: source.to_string(),
}
}
}
#[skip_serializing_none]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(
tag = "event",
rename_all = "camelCase",
rename_all_fields = "camelCase"
)]
pub enum SessionEvent {
Incoming {
track_id: String,
timestamp: u64,
caller: String,
callee: String,
sdp: String,
headers: Option<HashMap<String, String>>,
},
Answer {
track_id: String,
timestamp: u64,
sdp: String,
refer: Option<bool>,
},
MediaReady {
track_id: String,
timestamp: u64,
},
Reject {
track_id: String,
timestamp: u64,
reason: String,
refer: Option<bool>,
code: Option<u32>,
},
Ringing {
track_id: String,
timestamp: u64,
early_media: bool,
refer: Option<bool>,
},
Hangup {
track_id: String,
timestamp: u64,
reason: Option<String>,
initiator: Option<String>,
start_time: String,
hangup_time: String,
answer_time: Option<String>,
ringing_time: Option<String>,
from: Option<Attendee>,
to: Option<Attendee>,
extra: Option<HashMap<String, serde_json::Value>>,
refer: Option<bool>,
},
AnswerMachineDetection {
track_id: String,
timestamp: u64,
start_time: u64,
end_time: u64,
text: String,
},
Interrupt {
receiver: Option<String>,
},
FunctionCall {
track_id: String,
call_id: String,
name: String,
arguments: String,
timestamp: u64,
},
Speaking {
track_id: String,
timestamp: u64,
start_time: u64,
is_filler: Option<bool>,
confidence: Option<f32>,
refer: Option<bool>,
},
Silence {
track_id: String,
timestamp: u64,
start_time: u64,
duration: u64,
refer: Option<bool>,
#[serde(skip)]
samples: Option<PcmBuf>,
},
Eou {
track_id: String,
timestamp: u64,
completed: bool,
interrupt_point: Option<String>,
text: Option<String>,
refer: Option<bool>,
},
Inactivity {
track_id: String,
timestamp: u64,
},
Dtmf {
track_id: String,
timestamp: u64,
digit: String,
refer: Option<bool>,
},
Hold {
track_id: String,
timestamp: u64,
on_hold: bool,
refer: Option<bool>,
},
TransferRequest {
track_id: String,
timestamp: u64,
refer_to: String,
referred_by: Option<String>,
refer: Option<bool>,
},
Message {
track_id: String,
timestamp: u64,
body: String,
content_type: Option<String>,
refer: Option<bool>,
},
TrackStart {
track_id: String,
timestamp: u64,
play_id: Option<String>,
},
TrackEnd {
track_id: String,
timestamp: u64,
duration: u64,
ssrc: u32,
play_id: Option<String>,
},
Interruption {
track_id: String,
timestamp: u64,
play_id: Option<String>,
subtitle: Option<String>, position: Option<u32>, total_duration: u32, current: u32, },
AsrFinal {
track_id: String,
timestamp: u64,
index: u32,
start_time: Option<u64>,
end_time: Option<u64>,
text: String,
is_filler: Option<bool>,
confidence: Option<f32>,
task_id: Option<String>,
refer: Option<bool>,
},
AsrDelta {
track_id: String,
index: u32,
timestamp: u64,
start_time: Option<u64>,
end_time: Option<u64>,
text: String,
is_filler: Option<bool>,
confidence: Option<f32>,
task_id: Option<String>,
refer: Option<bool>,
},
Metrics {
timestamp: u64,
key: String,
duration: u32,
data: serde_json::Value,
},
Error {
track_id: String,
timestamp: u64,
sender: String,
error: String,
code: Option<u32>,
},
AddHistory {
sender: Option<String>,
timestamp: u64,
speaker: String,
text: String,
},
Other {
track_id: String,
timestamp: u64,
sender: String,
extra: Option<HashMap<String, String>>,
},
Binary {
track_id: String,
timestamp: u64,
data: Vec<u8>,
},
Ping {
timestamp: u64,
payload: Option<String>,
},
Custom {
timestamp: u64,
sender: Option<String>,
data: serde_json::Value,
},
RingbackState {
track_id: String,
timestamp: u64,
state: String,
state_index: u32,
confidence: f32,
prev_state: Option<String>,
prev_confidence: Option<f32>,
refer: Option<bool>,
#[serde(default)]
is_final: bool,
},
}
impl Display for SessionEvent {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
SessionEvent::Silence {
track_id, duration, ..
} => {
write!(f, "Silence(track_id={}, duration={})", track_id, duration)
}
SessionEvent::Binary { track_id, data, .. } => {
write!(f, "Silence(track_id={}, data_len={})", track_id, data.len())
}
_ => {
write!(f, "{:?}", self)
}
}
}
}
pub type EventSender = tokio::sync::broadcast::Sender<SessionEvent>;
pub type EventReceiver = tokio::sync::broadcast::Receiver<SessionEvent>;
pub fn create_event_sender() -> EventSender {
EventSender::new(128)
}