Skip to main content

Crate wavekat_sip

Crate wavekat_sip 

Source
Expand description

SIP signaling and RTP transport for voice pipelines.

wavekat-sip is a small, focused toolkit for building softphones, voice bots, and recording bridges in Rust. It wraps rsipstack and owns the wire-level concerns — SIP registration, dialogs, SDP offer/answer, and RTP framing — while staying out of audio device I/O, codec work, and call orchestration so it remains light and embeddable.

§Scope

What this crate covers:

  • SIP signaling — REGISTER with digest auth and keepalive re-registration (Registrar), shared transport + dialog layer (SipEndpoint).
  • SDP — minimal G.711 (PCMU + PCMA) offer/answer with round-trip parsing (build_sdp, parse_sdp).
  • RTP — header parser (RtpHeader), a debug-friendly receive loop (receive_rtp) suitable for transcription, recording, or smoke-testing inbound media, and a codec-agnostic send loop (send_loop) that packetizes consumer-supplied payloads onto the wire.

Explicitly out of scope (push these to the consuming application):

  • Audio device I/O (e.g. cpal), codec encode/decode, jitter buffering, recording, WAV writing.
  • Account persistence (TOML files, system keychain).
  • Call orchestration, AI pipeline, business logic.

Inbound INVITE handling lives in Callee; outbound INVITEs are placed via Caller.

§Quick start: register against a SIP server

use std::sync::Arc;
use tokio_util::sync::CancellationToken;
use wavekat_sip::{Registrar, SipAccount, SipEndpoint, Transport};

let account = SipAccount {
    display_name: "Office".into(),
    username: "1001".into(),
    password: "secret".into(),
    domain: "sip.example.com".into(),
    auth_username: None,
    server: None,
    port: None,
    transport: Transport::Udp,
};

let cancel = CancellationToken::new();
let (endpoint, _incoming) = SipEndpoint::new(&account, cancel.clone()).await?;
let endpoint = Arc::new(endpoint);

// Expires: 60s, re-register every 50s.
let registrar = Registrar::new(account, endpoint, cancel, 60, 50)?;
registrar.register().await?;
registrar.keepalive_loop().await;

The _incoming stream returned by SipEndpoint::new yields inbound transactions (INVITE, OPTIONS, …). For INVITEs, hand the transaction to Callee::accept_transaction or Callee::reject_transaction.

§Placing an outbound call

use std::sync::Arc;
use wavekat_sip::{Caller, SipAccount, SipEndpoint};

let caller = Caller::new(account, endpoint);
let target: wavekat_sip::re_exports::Uri = "sip:bob@example.com".try_into()?;
let mut pending = caller.dial(target).await?;

// Pump pending.state_rx to render "Dialing…" / "Ringing…" in the UI.
// When you see DialogState::Confirmed, promote to AcceptedDial:
let accepted = pending.on_confirmed().await?;

// Wire RTP to your audio / AI pipeline using accepted.rtp_socket
// and accepted.remote_media. Hang up locally with:
accepted.dialog.bye().await?;

§Building SDP and parsing the answer

use std::net::{IpAddr, Ipv4Addr};
use wavekat_sip::{build_sdp, parse_sdp};

let local_ip: IpAddr = Ipv4Addr::new(192, 168, 1, 50).into();
let offer = build_sdp(local_ip, 20000);

// ... send `offer` in an INVITE, receive an SDP answer ...
let answer = offer.clone(); // simulate a loopback answer
let media = parse_sdp(&answer).expect("valid SDP");
assert_eq!(media.port, 20000);
assert_eq!(media.payload_type, 0); // PCMU

§Reading RTP headers off the wire

For real receive loops use receive_rtp; to inspect individual packets, parse directly:

use wavekat_sip::RtpHeader;

let packet = [
    0x80, 0x00, 0x04, 0xD2, // V=2, PT=0 (PCMU), seq=1234
    0x00, 0x00, 0x16, 0x2E, // timestamp
    0xDE, 0xAD, 0xBE, 0xEF, // SSRC
];
let header = RtpHeader::parse(&packet).unwrap();
assert_eq!(header.payload_type, 0);
assert_eq!(header.sequence, 1234);
assert_eq!(header.header_len(), 12);

§Module map

ModulePurpose
accountRuntime SipAccount + Transport enum.
endpointSipEndpoint — bound transport, dialog layer, RX stream.
registrarREGISTER + digest auth + keepalive re-registration.
calleeInbound INVITE accept/reject helper.
callerOutbound INVITE / dial-cancel helper.
sdpMinimal G.711 offer/answer build + parse.
rtpRTP header parser, debug receive loop, codec-agnostic send loop.

§Stability

Pre-1.0. The public API may still shift between minor versions. Pin an exact version if you need stability today.

§License

Licensed under Apache 2.0. Copyright 2026 WaveKat.

Re-exports§

pub use account::SipAccount;
pub use account::Transport;
pub use callee::AcceptedCall;
pub use callee::Callee;
pub use callee::PendingCall;
pub use caller::AcceptedDial;
pub use caller::Caller;
pub use caller::PendingDial;
pub use endpoint::DispatchOutcome;
pub use endpoint::SipEndpoint;
pub use registrar::Registrar;
pub use registrar::RegistrarDiagnostics;
pub use rtp::receive_rtp;
pub use rtp::send_loop;
pub use rtp::RtpHeader;
pub use rtp::RtpSendConfig;
pub use sdp::build_sdp;
pub use sdp::parse_sdp;
pub use sdp::RemoteMedia;

Modules§

account
Runtime SIP account configuration.
callee
Inbound INVITE handling — focused SIP-only layer.
caller
Outbound INVITE handling — symmetric to crate::callee.
endpoint
Shared SIP endpoint: UDP/TCP transport bound, dialog layer wired, incoming-transaction stream exposed.
re_exports
Re-exports of upstream types that appear in our public API. Pinning them here lets consumers depend only on wavekat-sip without taking a direct dep on rsip / rsipstack.
registrar
REGISTER + digest auth + keepalive re-registration.
rtp
RTP header parsing, a debug receive loop, and a codec-agnostic send loop.
sdp
Minimal SDP offer/answer for G.711 telephony audio.

Constants§

GIT_HASH
Short git hash this crate was built from, or "unknown" if unavailable.