feat(rust-proxy-engine): add a Rust SIP proxy engine with shared SIP and codec libraries

This commit is contained in:
2026-04-10 09:57:27 +00:00
parent f3b18a7170
commit 3132ba8cbb
28 changed files with 5042 additions and 548 deletions

View File

@@ -0,0 +1,103 @@
//! 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<String>,
pub callee_number: Option<String>,
pub provider_id: String,
// Provider side.
pub provider_addr: SocketAddr,
pub provider_media: Option<SocketAddr>,
// Device side.
pub device_addr: SocketAddr,
pub device_media: Option<SocketAddr>,
// RTP relay.
pub rtp_port: u16,
pub rtp_socket: Arc<UdpSocket>,
// 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,
})
}
}