Skip to main content

rvoip_sip/
lib.rs

1//! # rvoip-sip
2//!
3//! Application-facing SIP session orchestration for Rust VoIP applications.
4//!
5//! `rvoip-sip` sits above the lower-level SIP dialog and media crates. It
6//! owns call/session state, registration state, SIP feature orchestration, and
7//! the public control surfaces that applications use to build softphones,
8//! test clients, IVRs, B2BUA legs, routing servers, and PBX/SBC interop tools.
9//!
10//! ## Where it fits in the workspace
11//!
12//! - [`rvoip_sip_dialog`] — RFC 3261 dialog/transaction layer
13//!   ([`Dialog`](rvoip_sip_dialog::Dialog),
14//!   [`DialogId`](rvoip_sip_dialog::DialogId),
15//!   [`DialogManager`](rvoip_sip_dialog::DialogManager))
16//! - [`rvoip_sip_core`] — SIP message parser and builder
17//!   ([`Message`](rvoip_sip_core::Message),
18//!   [`Request`](rvoip_sip_core::Request),
19//!   [`Response`](rvoip_sip_core::Response),
20//!   [`Uri`](rvoip_sip_core::Uri))
21//! - [`rvoip_sip_registrar`] — registrar/location service
22//!   ([`Registrar`](rvoip_sip_registrar::Registrar),
23//!   [`RegistrarService`](rvoip_sip_registrar::RegistrarService))
24//! - [`rvoip_media_core`] — codecs, media sessions, audio processing
25//!   ([`MediaSession`](rvoip_media_core::MediaSession),
26//!   [`MediaEngine`](rvoip_media_core::MediaEngine))
27//! - [`rvoip_rtp_core`] — RTP/SRTP transport
28//!   ([`RtpSession`](rvoip_rtp_core::RtpSession),
29//!   [`RtpPacket`](rvoip_rtp_core::RtpPacket))
30//! - [`rvoip_core`] — transport-agnostic orchestrator
31//!   ([`Orchestrator`](rvoip_core::Orchestrator),
32//!   [`ConnectionAdapter`](rvoip_core::ConnectionAdapter))
33//!
34//! This crate is the application seam; the layers above resolve into one of
35//! [`Endpoint`], [`StreamPeer`], [`CallbackPeer`], or [`UnifiedCoordinator`]
36//! depending on how much orchestration the caller wants to own.
37//!
38//! ## Choosing an API Surface
39//!
40//! | Surface | Best for | Programming model |
41//! | --- | --- | --- |
42//! | [`Endpoint`] | Softphones, PBX accounts, demos, simple IVR legs | Account/profile builder plus call helpers |
43//! | [`StreamPeer`] | Clients, scripts, softphones, integration tests | Sequential calls plus an event stream |
44//! | [`CallbackPeer`] | Servers, IVR, routing apps, reactive endpoints | Implement [`CallHandler`] hooks |
45//! | [`UnifiedCoordinator`] | B2BUAs, gateways, custom frameworks | Lower-level call/session orchestration |
46//! | [`SessionHandle`] | Per-call control from any surface | Hold/resume, DTMF, transfer, audio, teardown |
47//!
48//! Most applications should start with [`Endpoint`]. Move to [`StreamPeer`]
49//! when you want to own the event stream, [`CallbackPeer`] when you want the
50//! library to dispatch events into hooks, and [`UnifiedCoordinator`] when you
51//! need to compose multiple call legs, bridge media, subscribe to filtered
52//! event streams, inspect registration lifecycle metadata, or build your own
53//! peer abstraction.
54//!
55//! **[`Endpoint`] transfer ceiling.** `Endpoint` does **blind transfer only**
56//! ([`EndpointCall::transfer`]) and surfaces no inbound-REFER events. For
57//! **attended transfer** or **inbound REFER** control, use [`StreamPeer`] /
58//! [`SessionHandle`] — `transfer_attended`, `accept_refer`/`reject_refer`, and
59//! the REFER/transfer events on the coordinator event stream live there. A
60//! project that starts on `Endpoint` for simplicity should switch surfaces
61//! before building attended transfer.
62//!
63//! ## Authentication
64//!
65//! SIP access authentication is negotiated in SIP headers, not in SDP. A UAS
66//! challenges a request with `401 WWW-Authenticate`; the UAC retries with
67//! `Authorization`. A proxy challenges with `407 Proxy-Authenticate`; the UAC
68//! retries with `Proxy-Authorization`. SDP only affects authentication for
69//! Digest `qop=auth-int`, where the request body is included in the Digest
70//! response hash.
71//!
72//! The main entry points are:
73//!
74//! | Need | API |
75//! | --- | --- |
76//! | PBX-style Digest account | [`SipAccount`] with [`EndpointBuilder::sip_account`] |
77//! | UAC auth for challenged outbound requests | [`SipClientAuth`], [`Config::auth`], or per-request `.with_auth(...)` |
78//! | UAS challenge and validation | [`SipAuthService`] plus inbound `authenticate_with(...)` helpers |
79//! | Digest-only compatibility | [`SipDigestAuthService`] |
80//!
81//! [`SipClientAuth::any`] negotiates among configured compatible schemes and
82//! prefers AKA, then Bearer, then Digest, then Basic. Digest supports
83//! MD5/MD5-sess/SHA-256/SHA-256-sess/SHA-512-256/SHA-512-256-sess with
84//! `qop=auth` and `qop=auth-int` where the request body is available. Bearer
85//! validation is delegated to `rvoip-auth-core` validators. Basic is legacy
86//! compatibility and is rejected on cleartext SIP unless explicitly enabled.
87//! IMS AKA is provider-backed; applications supply the client/vector provider.
88//!
89//! See [`auth`] for the full scheme, side, and algorithm guide.
90//!
91//! ## Endpoint: PBX Account or Softphone
92//!
93//! [`Endpoint`] wraps [`StreamPeer`] with account/profile setup and bare
94//! extension dialing:
95//!
96//! ```rust,no_run
97//! use std::time::Duration;
98//! use rvoip_sip::{Endpoint, EndpointProfile, Result};
99//!
100//! # async fn example() -> Result<()> {
101//! let mut endpoint = Endpoint::builder()
102//!     .name("alice")
103//!     .account("1001")
104//!     .password("secret")
105//!     .registrar("sips:pbx.example.com:5061")
106//!     .profile(EndpointProfile::AsteriskTlsSrtpRegisteredFlow)
107//!     .build()
108//!     .await?;
109//!
110//! endpoint.register().await?;
111//! let call = endpoint.call_and_wait("1002", Some(Duration::from_secs(30))).await?;
112//! call.hangup().await?;
113//! endpoint.shutdown().await?;
114//! # Ok(())
115//! # }
116//! ```
117//!
118//! Runnable example: `cargo run -p rvoip-sip --example endpoint_local_call`
119//! (`examples/endpoint/01_local_call/main.rs`).
120//!
121//! ## StreamPeer: Sequential Client or Test Code
122//!
123//! [`StreamPeer`] owns a coordinator plus a typed event receiver. Its helpers
124//! block until the next matching event, which keeps simple clients and tests
125//! direct:
126//!
127//! ```rust,no_run
128//! use rvoip_sip::{Result, StreamPeer};
129//!
130//! # async fn example() -> Result<()> {
131//! let mut alice = StreamPeer::new("alice").await?;
132//! let call_id = alice.invite("sip:bob@192.168.1.50:5060").send().await?;
133//! let call = alice.coordinator().session(&call_id);
134//! let call = call.wait_for_answered(Some(std::time::Duration::from_secs(30))).await?;
135//!
136//! call.send_dtmf('1').await?;
137//! call.hold().await?;
138//! call.resume().await?;
139//! call.hangup_and_wait(Some(std::time::Duration::from_secs(5))).await?;
140//! # Ok(())
141//! # }
142//! ```
143//!
144//! For concurrent code, split it into [`PeerControl`] and [`EventReceiver`].
145//! Runnable example: `cargo run -p rvoip-sip --example stream_peer_basic_call`
146//! (`examples/stream_peer/01_basic_call/main.rs`).
147//!
148//! ## CallbackPeer: Reactive Server Code
149//!
150//! [`CallbackPeer`] dispatches typed events to a [`CallHandler`]. Return a
151//! [`CallHandlerDecision`] for incoming calls, and implement only the hooks
152//! your app needs:
153//!
154//! ```rust,no_run
155//! use async_trait::async_trait;
156//! use rvoip_sip::{
157//!     CallHandler, CallHandlerDecision, CallbackPeer, Config, IncomingCall, Result,
158//! };
159//!
160//! struct App;
161//!
162//! #[async_trait]
163//! impl CallHandler for App {
164//!     async fn on_incoming_call(&self, call: IncomingCall) -> CallHandlerDecision {
165//!         if call.to.contains("support") {
166//!             CallHandlerDecision::Accept
167//!         } else {
168//!             CallHandlerDecision::Reject {
169//!                 status: 404,
170//!                 reason: "Not Found".into(),
171//!             }
172//!         }
173//!     }
174//! }
175//!
176//! # async fn example() -> Result<()> {
177//! let peer = CallbackPeer::new(App, Config::default()).await?;
178//! peer.run().await?;
179//! # Ok(())
180//! # }
181//! ```
182//!
183//! Runnable example:
184//! `cargo run -p rvoip-sip --example callback_peer_auto_answer_server`
185//! (`examples/callback_peer/01_auto_answer/server.rs`). Built-in handlers
186//! ([`AutoAnswerHandler`], [`RoutingHandler`], [`QueueHandler`]) each have
187//! their own numbered scenario under `examples/callback_peer/`.
188//!
189//! ## UnifiedCoordinator: Custom Orchestration
190//!
191//! [`UnifiedCoordinator`] exposes the same session machinery without imposing
192//! a peer style. It is useful when an application needs to manage several
193//! calls at once, subscribe to raw event streams, bridge two active RTP
194//! sessions, drive registrations, or construct a B2BUA on top:
195//!
196//! ```rust,no_run
197//! use rvoip_sip::{Config, Event, Result, UnifiedCoordinator};
198//!
199//! # async fn example() -> Result<()> {
200//! let coordinator = UnifiedCoordinator::new(Config::local("bridge", 5060)).await?;
201//! let mut events = coordinator.events().await?;
202//!
203//! let outbound = coordinator
204//!     .invite(Some("sip:bridge@127.0.0.1:5060".to_string()), "sip:bob@127.0.0.1:5070")
205//!     .send()
206//!     .await?;
207//!
208//! while let Some(event) = events.next().await {
209//!     if matches!(event, Event::CallAnswered { .. }) {
210//!         coordinator.hangup(&outbound).await?;
211//!         break;
212//!     }
213//! }
214//! # Ok(())
215//! # }
216//! ```
217//!
218//! When you build directly on the coordinator, call-control methods generally
219//! take a [`SessionId`]. The peer surfaces wrap those IDs in [`SessionHandle`]
220//! for ergonomic per-call control.
221//!
222//! Runnable example: `cargo run -p rvoip-sip --example unified_basic_call`
223//! (`examples/unified/01_basic_call/main.rs`). The
224//! `examples/unified/04_b2bua_bridge/` scenario demonstrates a three-party
225//! bridge built directly on the coordinator.
226//!
227//! ## Features Exposed Through SessionHandle
228//!
229//! [`SessionHandle`] is the per-call control object shared by all three
230//! surfaces. It currently exposes:
231//!
232//! - call teardown with [`SessionHandle::hangup`] or deterministic
233//!   [`SessionHandle::hangup_and_wait`]
234//! - provisional progress with [`SessionHandle::wait_for_progress`]
235//! - answered-call waits with [`SessionHandle::wait_for_answered`]
236//! - local hold/resume with [`SessionHandle::hold`] and [`SessionHandle::resume`]
237//! - RFC 4733 DTMF send with [`SessionHandle::send_dtmf`]
238//! - blind transfer with [`SessionHandle::transfer_blind`] or
239//!   [`SessionHandle::transfer_blind_and_wait_for_outcome`]
240//! - typed transfer lifecycle events that distinguish REFER completion from
241//!   target-leg evidence
242//! - attended-transfer primitives with [`SessionHandle::dialog_identity`] and
243//!   [`SessionHandle::transfer_attended`]
244//! - inbound REFER accept/reject with [`SessionHandle::accept_refer`] and
245//!   [`SessionHandle::reject_refer`]
246//! - typed SRTP negotiation state with [`SessionHandle::media_security`] or
247//!   [`SessionHandle::wait_for_media_security`]
248//! - typed per-call events with [`SessionHandle::events`]
249//! - decoded/encoded audio frames with [`SessionHandle::audio`]
250//!
251//! ## B2BUA via `server::*`
252//!
253//! [`server`] adds B2BUA / gateway helpers on top of [`UnifiedCoordinator`] —
254//! coordination glue, not a parallel access path to dialog/media. Three entry
255//! points: [`server::SipBridgeStrategy`] for SIP↔SIP same-codec fast-path
256//! bridges, [`server::ContactResolver`] for AOR → live Contact lookups
257//! against `rvoip-sip-registrar`, and [`server::transfer`] for blind/
258//! attended/external REFER orchestration. The optional [`server::b2bua`]
259//! convenience wires the canonical inbound→originate→bridge pattern in one
260//! call.
261//!
262//! ```rust,no_run
263//! use rvoip_sip::api::events::Event;
264//! use rvoip_sip::api::unified::{Config, UnifiedCoordinator};
265//! use rvoip_sip::server::b2bua::SipB2bua;
266//!
267//! # async fn example() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
268//! let coordinator = UnifiedCoordinator::new(Config::local("b2bua", 5070)).await?;
269//! let b2bua = SipB2bua::new(coordinator.clone());
270//! let mut events = coordinator.events().await?;
271//! while let Some(Event::IncomingCall { call_id, .. }) = events.next().await {
272//!     let _bridge = b2bua
273//!         .handle_inbound("sip:b2bua@127.0.0.1", &call_id, "sip:upstream@example.com")
274//!         .await?;
275//!     // Drop the BridgeHandle to tear the bridge down.
276//! }
277//! # Ok(())
278//! # }
279//! ```
280//!
281//! See `examples/sip_b2bua.rs` for a complete CLI-driven runner.
282//!
283//! ## Cross-transport via [`rvoip_core::Orchestrator`] + [`SipAdapter`]
284//!
285//! [`SipAdapter`] implements [`rvoip_core::ConnectionAdapter`], so SIP plugs
286//! into the cross-transport [`rvoip_core::Orchestrator`] alongside future
287//! `rvoip-webrtc` / `rvoip-quic` adapters. Consumers that plan to add other
288//! transports later use this surface today; the single SIP adapter
289//! demonstrates the seam.
290//!
291//! ```rust,no_run
292//! use rvoip_core::{Config as CoreConfig, Orchestrator};
293//! use rvoip_sip::api::unified::{Config as SipConfig, UnifiedCoordinator};
294//! use rvoip_sip::SipAdapter;
295//!
296//! # async fn example() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
297//! let coordinator = UnifiedCoordinator::new(SipConfig::local("sip-leg", 5072)).await?;
298//! let adapter = SipAdapter::new(coordinator).await?;
299//! let orchestrator = Orchestrator::new(CoreConfig::default());
300//! orchestrator.register(adapter)?;
301//!
302//! let mut events = orchestrator.subscribe_events();
303//! // events.recv() yields normalized rvoip-core Events (translated from api::Event).
304//! # let _ = events;
305//! # Ok(())
306//! # }
307//! ```
308//!
309//! See `crates/foundation/rvoip-core/examples/sip_only_orchestrator.rs` for a complete
310//! runner. When `rvoip-webrtc` and `rvoip-quic` ship, they register against
311//! the same `Orchestrator` handle without reshaping consumer code.
312//!
313//! ## Custom INVITE headers
314//!
315//! All API surfaces share one builder: call `invite(from, to)` (or the
316//! peer-scoped `invite(to)`), then attach `.with_extra_headers(...)` to
317//! ship a `Vec<`[`TypedHeader`]`>` with the outgoing INVITE. Use this for
318//! headers RFC 3261 leaves outside the request line — `Diversion`,
319//! `History-Info`, `Call-Info`, `User-to-User`, or vendor `X-*` headers
320//! required by a specific PBX or SBC. The extras append after any
321//! synthesized `P-Asserted-Identity` and before the outbound-proxy Route,
322//! so the on-wire ordering is deterministic. [`HeaderName`] and [`TypedHeader`] are re-exported at the
323//! crate root for ergonomic authoring without pulling in `rvoip-sip-core`
324//! directly.
325//!
326//! ## Configuration and Interop
327//!
328//! [`Config`] controls SIP binding, advertised addresses, TLS, registration
329//! contact behavior, registration auto-refresh and graceful unregister,
330//! SRTP, session timers, 100rel, P-Asserted-Identity, outbound proxy routing
331//! for INVITEs and REGISTERs, STUN/static media address overrides, and codec
332//! matching policy. Deployment profile constructors cover local labs, LAN PBX
333//! use, Asterisk TLS registered-flow, FreeSWITCH internal profile, and
334//! carrier/SBC starting points.
335//!
336//! PBX interop examples live under `examples/pbx`. That unified runner drives
337//! the same Asterisk and FreeSWITCH scenarios through `Endpoint`, `StreamPeer`,
338//! and `CallbackPeer::builder`.
339//!
340//! See the [`api`] module docs for the complete module map and additional
341//! quick-start examples.
342//!
343//! ## Gateway / B2BUA / SBC Authoring
344//!
345//! For applications that need to inspect every inbound SIP field, author
346//! arbitrary outbound headers, and compose inbound/outbound legs across
347//! trust boundaries (B2BUAs, SBCs, gateways, call-center frontends),
348//! `rvoip-sip` provides a uniform builder-shaped request/response API
349//! introduced by `SIP_API_DESIGN_2.md`. The four cornerstones:
350//!
351//! - [`api::headers::SipHeaderView`] — inbound-header inspection,
352//!   implemented by every `IncomingCall` / `IncomingRequest` /
353//!   [`api::incoming::IncomingResponse`] / `IncomingRegister`. Generic
354//!   over the wrapper so carry-through code can write
355//!   `with_headers_from(&inbound, &[...])` once.
356//! - [`api::headers::SipRequestOptions`] — outbound and response
357//!   builder shape. Every builder (`coord.invite(..).send()`,
358//!   `coord.refer(..).send()`, `coord.accept(..).send()`, …)
359//!   implements it. In-dialog builders are also reachable directly
360//!   on [`api::handle::SessionHandle`] —
361//!   `session.bye().send()`, `session.refer(target).send()`, etc. —
362//!   so application code that already holds a session doesn't need
363//!   to reach back through the coordinator.
364//! - [`api::headers::policy`] — layer-boundary enforcement that
365//!   classifies every header for every method into
366//!   `StackManaged` / `MethodShaped` / `ApplicationControlled` so the
367//!   dialog state machine remains authoritative.
368//! - [`api::headers::convenience`] — typed constructors for headers
369//!   without a first-class `TypedHeader` variant in sip-core
370//!   (`Diversion`, `History-Info`, `Replaces`, `Target-Dialog`,
371//!   `Session-Expires`, `Min-SE`, `P-Charging-Vector`,
372//!   `P-Called-Party-ID`) plus body factories (`sdp`, `dtmf_relay`,
373//!   `pidf_xml`, multipart construction/parsing).
374//!
375//! ### Decision chart
376//!
377//! | If you say… | Use | Example |
378//! |---|---|---|
379//! | "I just want to make a call, library handles SIP" | Pure Config | `coord.invite(None, target).send()` |
380//! | "I need outbound auth" | One builder | `coord.invite(from, to).with_auth(auth).send()` |
381//! | "I need to attach one custom X-* header" | One builder | `coord.invite(from, to).with_raw_header("X-Foo", "bar")?.send()` |
382//! | "I'm building a B2BUA — carry headers across legs" | Builder + carry-through | `coord.invite(...).with_headers_from(&inbound, &[...])?.send()` |
383//! | "I need lenient validation for messy upstream" | `with_strictness(Lenient)` | `coord.invite(...).with_strictness(BuilderStrictness::Lenient).send()` |
384//! | "I need to inspect every inbound header" | [`api::headers::SipHeaderView`] | `incoming.header(&HeaderName::Diversion)` |
385//! | "I'm authoring custom 4xx with Retry-After" | `RejectBuilder` | `incoming.reject_builder().with_status(503).with_retry_after(120).send()` |
386//! | "I'm a registrar with Service-Route on 200 OK" | `RegisterResponseBuilder` | `incoming.accept_builder().with_service_route(routes).with_path_echo().send()` |
387//!
388//! ### B2BUA composition (the litmus test)
389//!
390//! ```rust,no_run
391//! # use std::sync::Arc;
392//! # use rvoip_sip::{UnifiedCoordinator, IncomingCall};
393//! # use rvoip_sip_core::types::headers::HeaderName;
394//! # async fn example(coord: Arc<UnifiedCoordinator>, incoming: IncomingCall) -> rvoip_sip::Result<()> {
395//! use rvoip_sip::api::headers::{SipHeaderView, SipRequestOptions};
396//!
397//! // Inspect inbound
398//! let _original_pai = incoming.header(&HeaderName::Other("P-Asserted-Identity".into()));
399//! let _history = incoming.headers_named(&HeaderName::Other("History-Info".into()));
400//!
401//! // Build outbound leg — every with_* returns Result; `?` chains cleanly
402//! let upstream_target = "sip:bob@upstream.example";
403//! let (outbound, _report) = coord
404//!     .invite(None, upstream_target)
405//!     .with_headers_from(&incoming, &[
406//!         HeaderName::Other("History-Info".into()),
407//!         HeaderName::Other("Diversion".into()),
408//!     ])?;
409//! let outbound = outbound
410//!     .strip_header(&HeaderName::Other("Privacy".into()))
411//!     .with_raw_header(
412//!         HeaderName::Other("P-Asserted-Identity".into()),
413//!         "sip:+15551234@gw.local",
414//!     )?;
415//!
416//! let _session = outbound.send().await?;
417//! # Ok(()) }
418//! ```
419//!
420//! ### Trust-boundary patterns
421//!
422//! Three canonical postures cover most B2BUA / SBC use cases:
423//!
424//! 1. **Trusted → untrusted egress.** Strip identity headers, keep
425//!    routing breadcrumbs only when regulator-mandated.
426//! 2. **Untrusted → trusted ingress.** Assert identity from local
427//!    AAA, ignore inbound PAI entirely.
428//! 3. **Trusted-to-trusted (intra-domain).** Carry through verbatim
429//!    so the downstream peer sees the upstream's headers.
430//!
431//! All three are illustrated in `SIP_API_DESIGN_2.md` §11.3; the
432//! [`api::headers::policy::forbidden_for_carry_through`] guard
433//! ensures none of them can accidentally leak `Via` / `Call-ID` /
434//! `CSeq` / `Max-Forwards` to the downstream wire — topology hiding
435//! is automatic.
436//!
437//! ### Header classification reference
438//!
439//! - **StackManaged**: `Call-ID`, `CSeq`, `Via`, `Max-Forwards`,
440//!   `Content-Length`, `Record-Route`, `Route`. Hard-rejected at
441//!   `with_header()` time regardless of `BuilderStrictness`.
442//! - **MethodShaped**: `Contact` (initial INVITE/REGISTER/SUBSCRIBE),
443//!   `Authorization` (UAC requests with `with_credentials` / `with_auth`),
444//!   `Expires` (REGISTER/SUBSCRIBE), `Refer-To` (REFER), `Event` /
445//!   `Subscription-State` (SUBSCRIBE/NOTIFY). Rejected under
446//!   `BuilderStrictness::Strict`; downgraded to a `tracing::warn!`
447//!   under `Lenient`.
448//! - **ApplicationControlled**: `Diversion`, `History-Info`,
449//!   `Referred-By`, `Replaces`, `P-Asserted-Identity`,
450//!   `P-Preferred-Identity`, `Privacy`, `Reason`, `Retry-After`,
451//!   `Warning`, `Subject`, `Date`, `User-Agent`, `Server`, `Accept`,
452//!   `Allow`, `Supported`, `Require`, `Path`, `Service-Route`,
453//!   `Reply-To`, `Target-Dialog`, `Session-Expires`, `Min-SE`, all
454//!   `X-*`, and every `Other(_)` not listed above. Free to stage.
455//!
456//! See [`api::headers::policy::classify`] for the per-method matrix.
457
458#![deny(rustdoc::bare_urls)]
459#![deny(rustdoc::broken_intra_doc_links)]
460// Public-API documentation is mandatory. `missing_docs` automatically exempts
461// `#[doc(hidden)]` items, so the crate's hidden internal modules (adapters,
462// state_machine, session_store, types, …) are not in scope — only the
463// user-facing surface (api/, server/, adapter, errors, media_stream).
464#![deny(missing_docs)]
465
466// ── Internal modules (pub for doc visibility, use the re-exports below) ─────
467
468pub mod adapter;
469pub mod api;
470pub mod errors;
471/// D4 — `MediaStream` wrapper that bridges a SIP audio session into
472/// `rvoip_core::ConnectionAdapter::streams`. See module docs.
473pub mod media_stream;
474pub mod server;
475
476// These modules remain public for existing internal-style integrations, but
477// most are hidden from generated docs. Application code should use the
478// UnifiedCoordinator, StreamPeer, CallbackPeer, SessionHandle, and auth
479// surfaces documented at the crate root.
480#[doc(hidden)]
481pub mod adapters;
482#[cfg(feature = "perf-tests")]
483#[doc(hidden)]
484pub mod admission_diag;
485pub mod auth;
486#[cfg(feature = "perf-call-setup-diagnostics")]
487#[doc(hidden)]
488pub mod call_setup_diag;
489#[doc(hidden)]
490pub mod cleanup_diag;
491#[doc(hidden)]
492pub mod session_registry;
493#[doc(hidden)]
494pub mod session_store;
495#[doc(hidden)]
496pub mod state_machine;
497#[doc(hidden)]
498pub mod state_table;
499#[doc(hidden)]
500pub mod types;
501
502// ── Primary public API ──────────────────────────────────────────────────────
503
504// Peer types
505pub use adapter::SipAdapter;
506
507pub use api::callback_peer::{
508    CallHandler, CallHandlerDecision, CallbackPeer, CallbackPeerBuilder, CallbackPeerControl,
509    ClosureHandler, EndReason, ShutdownHandle,
510};
511pub use api::endpoint::{
512    Endpoint, EndpointAccount, EndpointAccountConfig, EndpointAudio, EndpointAudioFrame,
513    EndpointAudioReceiver, EndpointAudioSender, EndpointBuilder, EndpointCall, EndpointCallId,
514    EndpointConfig, EndpointControl, EndpointEvent, EndpointEvents, EndpointIncomingCall,
515    EndpointMediaConfig, EndpointNetworkConfig, EndpointProfile, EndpointProfileName,
516    EndpointRegistrationInfo, EndpointRegistrationStatus, EndpointSipTrace, EndpointSrtpMode,
517    EndpointTransport, SipAccount,
518};
519pub use api::performance::{PerformanceConfig, PerformanceRecipe, PerformanceRecipeBook};
520pub use api::stream_peer::{EventReceiver, PeerControl, StreamPeer, StreamPeerBuilder};
521
522// Built-in handlers
523pub use api::handlers::{
524    AutoAnswerHandler, QueueHandler, RejectAllHandler, RoutingAction, RoutingHandler, RoutingRule,
525};
526
527// Call control
528pub use api::audio::{AudioReceiver, AudioSender, AudioStream};
529// The PCM frame type carried by `AudioStream` (`SessionHandle::audio()`).
530// Re-exported so clients can construct frames (mic -> RTP) without taking a
531// direct dependency on `rvoip-media-core`.
532pub use api::handle::{
533    CallId, SessionHandle, SipReason, TransferDialogMatcher, TransferLifecycleOptions,
534    TransferOutcome, TransferWaitMode,
535};
536pub use api::headers::options::{
537    BuilderHeaderState, BuilderStrictness, HeaderCarryThroughReport, HeaderPolicyViolation,
538    SipRequestOptions, ViolationReason,
539};
540pub use api::headers::view::SipHeaderView;
541pub use api::incoming::{
542    IncomingCall, IncomingCallGuard, IncomingRegister, IncomingRequest, IncomingResponse,
543};
544pub use api::trace_redactor::{PassthroughRedactor, RedactionDecision, TraceRedactor};
545pub use auth::{
546    AAuthValidator, AkaClientConfig, AkaClientProvider, AkaVectorProvider, ApiKeyVerifier,
547    AuditFailurePolicy, AuthAuditEvent, AuthAuditOutcome, AuthAuditScheme, AuthAuditSink,
548    AuthDecision, AuthFailureReason, AuthIdentity, AuthRateLimitKey, AuthRateLimitKind,
549    AuthRateLimitVerdict, AuthRateLimiter, BearerAuthError, BearerValidator, ClientAuthHeader,
550    CredentialAuthError, DigestAlgorithm, DigestAuth, DigestAuthenticator, DigestChallenge,
551    DigestChallengeDetails, DigestComputed, DigestNonceStatus, DigestReplayStore, DigestResponse,
552    DigestSecret, DigestSecretProvider, JwksJwtValidator, JwtValidator,
553    OAuth2IntrospectionValidator, PasswordVerifier, SipAuthChallenge, SipAuthContext,
554    SipAuthDecision, SipAuthPolicy, SipAuthScheme, SipAuthService, SipAuthSource, SipClientAuth,
555    SipDigestAuthService, SipIncomingAuthenticator, SipTransportSecurityContext,
556    TokenRevocationChecker, TokenRevocationContext, TokenRevocationStatus,
557};
558pub use rvoip_media_core::performance::pool::PoolConfig as MediaPoolConfig;
559pub use rvoip_media_core::types::AudioFrame;
560
561/// SIP_API_DESIGN_2 §3.6 — convenience body constructors. Each
562/// helper returns `(content_type, Bytes)` for attachment to a SIP
563/// body via the new outbound builders. The §10 #24 `multipart_mixed`
564/// / `multipart_parse` helpers live in
565/// [`crate::api::headers::convenience`] and
566/// are re-exported here for surface symmetry.
567pub mod bodies {
568    pub use crate::api::bodies::*;
569    pub use crate::api::headers::convenience::{
570        multipart_mixed, multipart_parse, MultipartParseError, MultipartPart,
571    };
572}
573pub use api::lifecycle::{
574    CallAnsweredInfo, CallLifecycleSnapshot, CallProgressInfo, CallTerminalInfo,
575};
576
577// Configuration & registration
578pub use api::unified::{
579    AudioSource, BridgeError, BridgeHandle, MediaSessionControllerConfig, Registration, RelUsage,
580    RtpSessionBufferConfig, RtpTransportBufferConfig,
581};
582pub use api::{
583    Config, MediaMode, RegistrationHandle, RegistrationInfo, RegistrationStatus, SipContactMode,
584    SipTlsMode, SrtpSuitePolicy, UnifiedCoordinator,
585};
586
587// Events
588pub use api::dialog_package::{
589    DialogInfo, DialogInfoDocument, DialogPackageEvent, DialogPackageState,
590};
591pub use api::dialog_subscription::DialogSubscriptionHandle;
592pub use api::events::{
593    Event, MediaSecurityKeying, MediaSecurityProfile, MediaSecurityState, SipTrace, SipTraceConfig,
594    SipTraceDirection, SubscriptionState, TransferKind, TransferTargetEvidence,
595};
596
597// Errors
598pub use errors::{Result, SessionError};
599
600// State / identity types
601pub use state_table::types::SessionId;
602pub use types::CallState;
603
604// SIP header authoring (re-exported from rvoip-sip-core so callers using
605// the `_with_headers` outbound-INVITE variants can construct typed headers
606// without importing the lower-level crate directly).
607pub use rvoip_sip_core::types::{HeaderName, TypedHeader};
608
609// ── Prelude ─────────────────────────────────────────────────────────────────
610
611/// Common imports for most use cases.
612///
613/// ```
614/// use rvoip_sip::prelude::*;
615/// ```
616pub mod prelude {
617    pub use crate::{
618        AudioFrame, AudioReceiver, AudioSender, AudioStream, CallAnsweredInfo, CallHandler,
619        CallHandlerDecision, CallId, CallLifecycleSnapshot, CallProgressInfo, CallState,
620        CallTerminalInfo, CallbackPeer, CallbackPeerBuilder, CallbackPeerControl, Config,
621        DialogInfo, DialogInfoDocument, DialogPackageEvent, DialogPackageState,
622        DialogSubscriptionHandle, EndReason, Endpoint, EndpointAccount, EndpointAccountConfig,
623        EndpointAudio, EndpointAudioFrame, EndpointAudioReceiver, EndpointAudioSender,
624        EndpointBuilder, EndpointCall, EndpointCallId, EndpointConfig, EndpointControl,
625        EndpointEvent, EndpointEvents, EndpointIncomingCall, EndpointMediaConfig,
626        EndpointNetworkConfig, EndpointProfile, EndpointProfileName, EndpointRegistrationInfo,
627        EndpointRegistrationStatus, EndpointSipTrace, EndpointSrtpMode, EndpointTransport, Event,
628        EventReceiver, HeaderName, IncomingCall, IncomingCallGuard, MediaMode, MediaPoolConfig,
629        MediaSecurityKeying, MediaSecurityProfile, MediaSecurityState,
630        MediaSessionControllerConfig, PeerControl, PerformanceConfig, PerformanceRecipeBook,
631        Registration, RegistrationHandle, RegistrationInfo, RegistrationStatus, Result,
632        RtpSessionBufferConfig, RtpTransportBufferConfig, SessionError, SessionHandle, SipAccount,
633        SipAuthDecision, SipAuthScheme, SipAuthService, SipAuthSource, SipClientAuth,
634        SipContactMode, SipDigestAuthService, SipReason, SipTlsMode, SipTrace, SipTraceConfig,
635        SipTraceDirection, SrtpSuitePolicy, StreamPeer, StreamPeerBuilder, SubscriptionState,
636        TransferDialogMatcher, TransferKind, TransferLifecycleOptions, TransferOutcome,
637        TransferTargetEvidence, TransferWaitMode, TypedHeader,
638    };
639}
640
641// ── Internals (for power users / testing) ───────────────────────────────────
642
643/// Advanced types for power users who need direct access to the state machine,
644/// session store, or adapters. Most users should not need these.
645pub mod internals {
646    pub use crate::adapters::{DialogAdapter, MediaAdapter};
647    pub use crate::api::builder::SessionBuilder;
648    pub use crate::api::types::{
649        parse_sdp_connection, AudioStreamConfig, CallDecision, CallSession, MediaInfo, SdpInfo,
650        SessionStats,
651    };
652    pub use crate::session_store::{
653        ActionRecord, GuardResult, HistoryConfig, NegotiatedConfig, SessionHistory, SessionState,
654        SessionStore, TransitionRecord,
655    };
656    pub use crate::state_machine::StateMachine;
657    pub use crate::state_table::types::{EventType, Role, SessionId};
658    pub use crate::state_table::{Action, Guard};
659}