fix(proxy-engine): fix inbound route browser ringing and provider-facing SDP advertisement while preventing RTP port exhaustion

This commit is contained in:
2026-04-11 18:40:56 +00:00
parent 21ffc1d017
commit 81441e7853
17 changed files with 208 additions and 469 deletions

View File

@@ -27,6 +27,10 @@ pub enum CallState {
}
impl CallState {
/// Wire-format string for events/dashboards. Not currently emitted —
/// call state changes flow as typed events (`call_answered`, etc.) —
/// but kept for future status-snapshot work.
#[allow(dead_code)]
pub fn as_str(&self) -> &'static str {
match self {
Self::SettingUp => "setting-up",
@@ -45,6 +49,8 @@ pub enum CallDirection {
}
impl CallDirection {
/// Wire-format string. See CallState::as_str.
#[allow(dead_code)]
pub fn as_str(&self) -> &'static str {
match self {
Self::Inbound => "inbound",
@@ -59,8 +65,13 @@ pub enum LegKind {
SipProvider,
SipDevice,
WebRtc,
Media, // voicemail playback, IVR, recording
Tool, // observer leg for recording, transcription, etc.
/// Voicemail playback, IVR prompt playback, recording — not yet wired up
/// as a distinct leg kind (those paths currently use the mixer's role
/// system instead). Kept behind allow so adding a real media leg later
/// doesn't require re-introducing the variant.
#[allow(dead_code)]
Media,
Tool, // observer leg for recording, transcription, etc.
}
impl LegKind {
@@ -107,11 +118,22 @@ pub struct LegInfo {
/// For SIP legs: the SIP Call-ID for message routing.
pub sip_call_id: Option<String>,
/// For WebRTC legs: the session ID in WebRtcEngine.
///
/// Populated at leg creation but not yet consumed by the hub —
/// WebRTC session lookup currently goes through the session registry
/// directly. Kept for introspection/debugging.
#[allow(dead_code)]
pub webrtc_session_id: Option<String>,
/// The RTP socket allocated for this leg.
pub rtp_socket: Option<Arc<UdpSocket>>,
/// The RTP port number.
pub rtp_port: u16,
/// Public IP to advertise in SDP/Record-Route when THIS leg is the
/// destination of a rewrite. Populated only for provider legs; `None`
/// for LAN SIP devices, WebRTC browsers, media, and tool legs (which
/// are reachable via `lan_ip`). See `route_passthrough_message` for
/// the per-destination advertise-IP logic.
pub public_ip: Option<String>,
/// The remote media endpoint (learned from SDP or address learning).
pub remote_media: Option<SocketAddr>,
/// SIP signaling address (provider or device).
@@ -124,14 +146,21 @@ pub struct LegInfo {
/// A multiparty call with N legs and a central mixer.
pub struct Call {
// Duplicated from the HashMap key in CallManager. Kept for future
// status-snapshot work.
#[allow(dead_code)]
pub id: String,
pub state: CallState,
// Populated at call creation but not currently consumed — dashboard
// pull snapshots are gone (push events only).
#[allow(dead_code)]
pub direction: CallDirection,
pub created_at: Instant,
// Metadata.
pub caller_number: Option<String>,
pub callee_number: Option<String>,
#[allow(dead_code)]
pub provider_id: String,
/// Original INVITE from the device (for device-originated outbound calls).
@@ -211,42 +240,4 @@ impl Call {
handle.abort();
}
}
/// Produce a JSON status snapshot for the dashboard.
pub fn to_status_json(&self) -> serde_json::Value {
let legs: Vec<serde_json::Value> = self
.legs
.values()
.filter(|l| l.state != LegState::Terminated)
.map(|l| {
let metadata: serde_json::Value = if l.metadata.is_empty() {
serde_json::json!({})
} else {
serde_json::Value::Object(
l.metadata.iter().map(|(k, v)| (k.clone(), v.clone())).collect(),
)
};
serde_json::json!({
"id": l.id,
"type": l.kind.as_str(),
"state": l.state.as_str(),
"codec": sip_proto::helpers::codec_name(l.codec_pt),
"rtpPort": l.rtp_port,
"remoteMedia": l.remote_media.map(|a| format!("{}:{}", a.ip(), a.port())),
"metadata": metadata,
})
})
.collect();
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,
"duration": self.duration_secs(),
"legs": legs,
})
}
}