Skip to main content

wavekat_sip/
lib.rs

1//! SIP signaling and RTP transport for voice pipelines.
2//!
3//! `wavekat-sip` is a small, focused toolkit for building softphones, voice
4//! bots, and recording bridges in Rust. It wraps [`rsipstack`] and owns the
5//! wire-level concerns — SIP registration, dialogs, SDP offer/answer, and
6//! RTP framing — while staying out of audio device I/O, codec work, and
7//! call orchestration so it remains light and embeddable.
8//!
9//! [`rsipstack`]: https://crates.io/crates/rsipstack
10//!
11//! # Scope
12//!
13//! What this crate covers:
14//!
15//! - **SIP signaling** — REGISTER with digest auth and keepalive
16//!   re-registration ([`Registrar`]), shared transport + dialog layer
17//!   ([`SipEndpoint`]).
18//! - **SDP** — minimal G.711 (PCMU + PCMA) offer/answer with round-trip
19//!   parsing ([`build_sdp`], [`parse_sdp`]).
20//! - **RTP** — header parser ([`RtpHeader`]) and a debug-friendly receive
21//!   loop ([`receive_rtp`]) suitable for transcription, recording, or
22//!   smoke-testing inbound media.
23//!
24//! Explicitly out of scope (push these to the consuming application):
25//!
26//! - Audio device I/O (e.g. `cpal`), codec encode/decode, jitter buffering,
27//!   recording, WAV writing.
28//! - Account persistence (TOML files, system keychain).
29//! - Call orchestration, AI pipeline, business logic.
30//!
31//! See the [roadmap](https://github.com/wavekat/wavekat-sip/blob/main/docs/01-port-plan.md)
32//! for the planned `caller` / `callee` INVITE wrappers and RTP send helper.
33//!
34//! # Quick start: register against a SIP server
35//!
36//! ```no_run
37//! use std::sync::Arc;
38//! use tokio_util::sync::CancellationToken;
39//! use wavekat_sip::{Registrar, SipAccount, SipEndpoint, Transport};
40//!
41//! # async fn run() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
42//! let account = SipAccount {
43//!     display_name: "Office".into(),
44//!     username: "1001".into(),
45//!     password: "secret".into(),
46//!     domain: "sip.example.com".into(),
47//!     auth_username: None,
48//!     server: None,
49//!     port: None,
50//!     transport: Transport::Udp,
51//! };
52//!
53//! let cancel = CancellationToken::new();
54//! let (endpoint, _incoming) = SipEndpoint::new(&account, cancel.clone()).await?;
55//! let endpoint = Arc::new(endpoint);
56//!
57//! // Expires: 60s, re-register every 50s.
58//! let registrar = Registrar::new(account, endpoint, cancel, 60, 50)?;
59//! registrar.register().await?;
60//! registrar.keepalive_loop().await;
61//! # Ok(())
62//! # }
63//! ```
64//!
65//! The `_incoming` stream returned by [`SipEndpoint::new`] yields inbound
66//! transactions (INVITE, OPTIONS, …). Until the `callee` helper lands,
67//! consume it by driving [`SipEndpoint::dialog_layer`] directly.
68//!
69//! # Building SDP and parsing the answer
70//!
71//! ```
72//! use std::net::{IpAddr, Ipv4Addr};
73//! use wavekat_sip::{build_sdp, parse_sdp};
74//!
75//! let local_ip: IpAddr = Ipv4Addr::new(192, 168, 1, 50).into();
76//! let offer = build_sdp(local_ip, 20000);
77//!
78//! // ... send `offer` in an INVITE, receive an SDP answer ...
79//! let answer = offer.clone(); // simulate a loopback answer
80//! let media = parse_sdp(&answer).expect("valid SDP");
81//! assert_eq!(media.port, 20000);
82//! assert_eq!(media.payload_type, 0); // PCMU
83//! ```
84//!
85//! # Reading RTP headers off the wire
86//!
87//! For real receive loops use [`receive_rtp`]; to inspect individual
88//! packets, parse directly:
89//!
90//! ```
91//! use wavekat_sip::RtpHeader;
92//!
93//! let packet = [
94//!     0x80, 0x00, 0x04, 0xD2, // V=2, PT=0 (PCMU), seq=1234
95//!     0x00, 0x00, 0x16, 0x2E, // timestamp
96//!     0xDE, 0xAD, 0xBE, 0xEF, // SSRC
97//! ];
98//! let header = RtpHeader::parse(&packet).unwrap();
99//! assert_eq!(header.payload_type, 0);
100//! assert_eq!(header.sequence, 1234);
101//! assert_eq!(header.header_len(), 12);
102//! ```
103//!
104//! # Module map
105//!
106//! | Module          | Purpose                                                        |
107//! |-----------------|----------------------------------------------------------------|
108//! | [`account`]     | Runtime [`SipAccount`] + [`Transport`] enum.                   |
109//! | [`endpoint`]    | [`SipEndpoint`] — bound transport, dialog layer, RX stream.    |
110//! | [`registrar`]   | REGISTER + digest auth + keepalive re-registration.            |
111//! | [`sdp`]         | Minimal G.711 offer/answer build + parse.                      |
112//! | [`rtp`]         | RTP header parser and async receive loop.                      |
113//!
114//! # Stability
115//!
116//! Pre-1.0. The public API will shift between minor versions while the
117//! `caller` / `callee` helpers land. Pin an exact version if you need
118//! stability today.
119//!
120//! # License
121//!
122//! Licensed under Apache 2.0. Copyright 2026 WaveKat.
123
124#![cfg_attr(docsrs, feature(doc_cfg))]
125
126pub mod account;
127pub mod endpoint;
128pub mod registrar;
129pub mod rtp;
130pub mod sdp;
131
132pub use account::{SipAccount, Transport};
133pub use endpoint::SipEndpoint;
134pub use registrar::Registrar;
135pub use rtp::{receive_rtp, RtpHeader};
136pub use sdp::{build_sdp, parse_sdp, RemoteMedia};
137
138/// Short git hash this crate was built from, or `"unknown"` if unavailable.
139pub const GIT_HASH: &str = env!("WAVEKAT_SIP_GIT_HASH");