//! Call hub — owns legs and bridges media. //! //! Each Call has a unique ID and tracks its state, direction, and associated //! SIP Call-IDs for message routing. use std::net::SocketAddr; use std::sync::Arc; use std::time::Instant; use tokio::net::UdpSocket; /// Call state machine. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum CallState { SettingUp, Ringing, Connected, Voicemail, Ivr, Terminating, Terminated, } impl CallState { pub fn as_str(&self) -> &'static str { match self { Self::SettingUp => "setting-up", Self::Ringing => "ringing", Self::Connected => "connected", Self::Voicemail => "voicemail", Self::Ivr => "ivr", Self::Terminating => "terminating", Self::Terminated => "terminated", } } } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum CallDirection { Inbound, Outbound, } impl CallDirection { pub fn as_str(&self) -> &'static str { match self { Self::Inbound => "inbound", Self::Outbound => "outbound", } } } /// A passthrough call — both sides share the same SIP Call-ID. /// The proxy rewrites SDP/Contact/Request-URI and relays RTP. pub struct PassthroughCall { pub id: String, pub sip_call_id: String, pub state: CallState, pub direction: CallDirection, pub created_at: Instant, // Call metadata. pub caller_number: Option, pub callee_number: Option, pub provider_id: String, // Provider side. pub provider_addr: SocketAddr, pub provider_media: Option, // Device side. pub device_addr: SocketAddr, pub device_media: Option, // RTP relay. pub rtp_port: u16, pub rtp_socket: Arc, // Packet counters. pub pkt_from_device: u64, pub pkt_from_provider: u64, } impl PassthroughCall { pub fn duration_secs(&self) -> u64 { self.created_at.elapsed().as_secs() } pub fn to_status_json(&self) -> serde_json::Value { serde_json::json!({ "id": self.id, "state": self.state.as_str(), "direction": self.direction.as_str(), "callerNumber": self.caller_number, "calleeNumber": self.callee_number, "providerUsed": self.provider_id, "createdAt": self.created_at.elapsed().as_millis(), "duration": self.duration_secs(), "rtpPort": self.rtp_port, "pktFromDevice": self.pkt_from_device, "pktFromProvider": self.pkt_from_provider, }) } }