Skip to main content

Crate rtsp_runtime

Crate rtsp_runtime 

Source
Expand description

§rtsp-runtime

crates.io docs.rs

Sans-IO RTSP 1.0 (RFC 2326) session engine: a driveable client and a server state machine, Transport negotiation, interleaved RTP/RTCP framing and authenticated requests. An optional tokio adapter (and tls for rtsps://) puts it on real sockets.

[dependencies]
rtsp-runtime = "0.10"                                       # sans-IO core
rtsp-runtime = { version = "0.10", features = ["tokio"] }   # + real sockets
rtsp-runtime = { version = "0.10", features = ["tls"] }     # + rtsps:// (TLS)

§What it does / what it does not

Does: run the RFC 2326 Appendix A session state machines (Init, Ready, Playing, Recording) on both sides; build outbound requests (OPTIONS, DESCRIBE, SETUP, PLAY, PAUSE, TEARDOWN, ANNOUNCE, RECORD, GET_PARAMETER) with an incrementing CSeq and match responses back to them; parse and serialize the Transport (§12.39) and Session (§12.37) headers; frame and de-frame $-channel interleaved RTP/RTCP (§10.12); answer 401 challenges with Basic, Digest or Bearer credentials, including stale=true nonce refresh; and manage the keepalive timeout. The server rejects a method that is illegal in the current state with 455, allocates a Session id on SETUP (from a caller-supplied CSPRNG), and echoes the first offered transport.

Does not: open sockets in the core (feed bytes in, get bytes and events out), parse RTP or RTCP payloads (use rtp-packet, which also holds the rtcp module), parse SDP (use sdp-types), generate DESCRIBE SDP or challenge clients on the server side (the server session has no authentication; put a broadcast-auth Verifier in your own layer), or speak RTSP 2.0 (RFC 7826 is vendored but not implemented). The client has no SET_PARAMETER builder, and server-initiated REDIRECT is not modelled.

Typical users: IP-camera ingest (multimux’s RTSP input), RTSP push to a media server, test servers, and tools that need to drive a camera session deterministically.

§Standards supported

StandardEditionScopeStatusNotes
IETF RFC 2326 “Real Time Streaming Protocol”RFC 2326 (private repo: private/specs-verified/ietf/specs/rfc2326_rtsp.txt, transcribed in private/specs-verified/rtp/rtsp-runtime/rfc2326.md)Appendix A state machines, §10 methods listed above, §10.12 interleaved framing, §12.37 Session, §12.39 Transport, §14 authentication, CSeq (§12.17)PartialSee the methods table below
IETF RFC 7826 “RTSP 2.0”RFC 7826 (vendored, not implemented)n/aNot implemented
IETF RFC 7617 / RFC 7616 / RFC 6750 (Basic, Digest, Bearer)not vendored, unverified hereClient side via broadcast-authFullServer side has no authentication
IETF RFC 8866 (SDP)RFC 8866 (vendored)Bodies carried opaqueTyped-opaqueParse with sdp-types
IETF RFC 3550 (RTP/RTCP)RFC 3550Interleaved payload is carried as bytesTyped-opaqueDecode with rtp-packet (rtp_packet::rtcp for RTCP)
rtsps:// (RTSP over TLS, default port 322)n/aClient connect_tls, server accept_tlsFull, behind tlswebpki-roots trust by default or a custom rustls::ClientConfig
MethodClient buildsServer session handlesState effect
OPTIONS, DESCRIBE, GET_PARAMETER, ANNOUNCEyesaccepted, empty 200none
SET_PARAMETERno builderaccepted as state-neutral, empty 200none
SETUPyesallocates Session, echoes transportInit to Ready
PLAY, PAUSE, RECORD, TEARDOWNyesaccepted, requires SessionReady/Playing/Recording per Appendix A
REDIRECTnonot modelled (a client resets to Init on a 3xx)n/a

§Features

FeatureDefaultDescription
serdenoSerialize on the public wire and event types.
tokionoAsyncRtspClient / AsyncRtspServer (tokio_util Framed adapters; 64 KiB header and 2 MiB message caps; RtspTimeouts; keepalive at half the session timeout).
tlsnoImplies tokio; adds rtsps:// via tokio-rustls.

The core is std and uses no async runtime. The crate has #![forbid(unsafe_code)].

§Quick start

A client talking to a server entirely in memory (no socket):

use rtsp_runtime::{
    ClientEvent, ClientSession, InterleavedFrame, ServerSession, SessionState, Transport,
    TransportSpec,
};

let url = "rtsp://127.0.0.1/stream";
let track = "rtsp://127.0.0.1/stream/trackID=0";

// A fixed id is fine here; a real server must draw ids from a CSPRNG.
let mut server = ServerSession::new(|| 0x0123_4567_89ab_cdef);
let mut client = ClientSession::new();

let req = client.options(url).unwrap();
let (resp, _) = server.handle_request(&req).unwrap();
client.handle_data_strict(&resp).unwrap();

let transport = Transport::single(TransportSpec::rtp_avp_tcp_interleaved(0, 1));
let req = client.setup(track, &transport).unwrap();
let (resp, _) = server.handle_request(&req).unwrap();
client.handle_data_strict(&resp).unwrap();
assert_eq!(client.state(), SessionState::Ready);
assert!(client.session_id().is_some());

let req = client.play(url).unwrap();
let (resp, _) = server.handle_request(&req).unwrap();
client.handle_data_strict(&resp).unwrap();
assert_eq!(client.state(), SessionState::Playing);

// While playing, RTP is tunnelled on interleaved channel 0 over the same connection.
let rtp = [0x80, 0x60, 0x00, 0x01, 0, 0, 0, 0, 0, 0, 0, 1, 0xde, 0xad];
let wire = InterleavedFrame::slice_to_bytes(0, &rtp).unwrap();
let events = client.handle_data_strict(&wire).unwrap();
assert!(matches!(&events[0], ClientEvent::MediaData { channel: 0, data } if data == &rtp));

let req = client.teardown(url).unwrap();
let (resp, _) = server.handle_request(&req).unwrap();
client.handle_data_strict(&resp).unwrap();
assert_eq!(client.state(), SessionState::Init);

Runnable programs: client_server_loopback and transport_and_framing (cargo run -p rtsp-runtime --example <name>).

§What is implemented

  • ClientSession: request builders, handle_data (returns HandleOutcome { events, error } so frames decoded before a terminal error are never lost) and handle_data_strict; with_credentials; AuthRetry events for 401; poll_timeout/handle_timeout keepalive.
  • ServerSession: handle_request returning response bytes plus ServerEvents (RequestAccepted, MethodNotValid, SessionSetup, MediaData), with_session_timeout.
  • Transport, TransportSpec, LowerTransport, Delivery, TransportMode: UDP unicast and multicast, TCP interleaved. SessionHeader: Session id and timeout. Both are parsed by this crate over one RFC 2326 §15.1 lexer, because rtsp-types 0.1 is exact-case and drops case-variant parameters (a documented, owner-approved exception to the no-hand-roll rule; probe table in private/specs-verified/rtp/rtsp-runtime/transport-header.md).
  • InterleavedFrame and a streaming demultiplexer (complete frames plus a partial tail).
  • Credentials and Authenticator, re-exported from broadcast-auth.
  • io (feature tokio): AsyncRtspClient, AsyncRtspServer, RtspTimeouts, RTSP_DEFAULT_PORT (554), RTSPS_DEFAULT_PORT (322).

§Design notes

Sans-IO: the core never reads a clock or a socket (the caller passes Instant for timeouts and supplies the session-id source). Error is #[non_exhaustive]. The Session id comparison is constant time. Message framing is bounded (header and message size caps). Tests include golden wire transcripts and real-loopback integration tests (OPTIONS to TEARDOWN, fragmented interleaved media, Digest, a TLS handshake with a self-signed certificate). A lexical no_handroll_guard test enforces the allowlist.

Builds on rtsp-types and sdp-types (codecs) and broadcast-auth. Pair with rtp-packet (RTP and RTCP) for the interleaved payloads. multimux uses it for RTSP input and push, and transmux for RTP depacketising.

§MSRV and licence

MSRV 1.95.0. Licensed under MIT OR Apache-2.0.

Re-exports§

pub use client::ClientEvent;
pub use client::ClientSession;
pub use client::HandleOutcome;
pub use client::RtpInfoEntry;
pub use error::Error;
pub use error::IoContext;
pub use error::MessageKind;
pub use error::Result;
pub use interleaved::InterleavedFrame;
pub use io::AsyncRtspClient;tokio
pub use io::AsyncRtspServer;tokio
pub use io::RTSP_DEFAULT_PORT;tokio
pub use io::RTSPS_DEFAULT_PORT;tokio
pub use io::RtspTimeouts;tokio
pub use server::ServerEvent;
pub use server::ServerSession;
pub use session_header::SessionHeader;
pub use state::SessionState;
pub use transport::Delivery;
pub use transport::LowerTransport;
pub use transport::Transport;
pub use transport::TransportMode;
pub use transport::TransportSpec;

Modules§

auth
Authentication wiring — RFC 2326 §16 (RTSP reuses HTTP auth).
client
Client-side RTSP session engine — RFC 2326 Appendix A.1.
error
Error types for the RTSP session engine.
interleaved
Interleaved ($-framed) binary data — RFC 2326 §10.12.
iotokio
Async real-socket IO adapter over the sans-IO engine — RFC 2326 transport.
server
Server-side RTSP session engine — RFC 2326 Appendix A.2.
session_header
Typed Session header — RFC 2326 §12.37 (private/specs-verified/rtp/rtsp-runtime/rfc2326.md, private/specs-verified/rtp/rtsp-runtime/session-header.md).
state
RTSP session state machine — RFC 2326 Appendix A.
transport
Typed Transport header — RFC 2326 §12.39 (private/specs-verified/rtp/rtsp-runtime/rfc2326.md, private/specs-verified/rtp/rtsp-runtime/transport-header.md).

Structs§

Authenticator
Negotiates a challenge once, then answers every subsequent request in the session (RFC 7235 WWW-Authenticate/Authorization; RFC 2326 §16 for RTSP; RFC 6750 for Bearer).

Enums§

Credentials
Credentials for one of the supported auth schemes.
Method
RTSP method.
StatusCode
RTSP response status codes.

Constants§

RFC
The RFC this engine implements.