Skip to main content

Crate rtcp_packet

Crate rtcp_packet 

Source
Expand description

RTCP control packets — RFC 3550 §6, spec-complete (not just a happy-path subset).

Typed, symmetric Parse/Serialize for every RTCP packet type described in the curated spec transcription at rtcp-packet/docs/rtcp.md (fetched directly from RFC 3550) — cite that file, not this doc comment, as the field-semantics oracle.

Two decode-completeness gaps are documented (not silently glossed over) in docs/rtcp.md: SR/RR profile-specific extensions and the SDES PRIV item’s internal prefix/value sub-structure are not separately typed.

RTCP carries no media — this is a standalone wire codec for the RTP control channel (a companion to the rtp-packet crate), not a hub Package/Unpackage spoke.

Depends only on broadcast-common. #![no_std] (+ alloc) when the std feature is disabled.

§Examples

Build a Sender Report with two reception report blocks and round-trip it:

use broadcast_common::{Parse, Serialize};
use rtcp_packet::{ReportBlock, SenderReport};

let sr = SenderReport {
    ssrc: 0x1122_3344,
    ntp_msw: 0xE0E1_E2E3,
    ntp_lsw: 0x1020_3040,
    rtp_timestamp: 0x0009_0000,
    packet_count: 4321,
    octet_count: 999_999,
    report_blocks: vec![ReportBlock {
        ssrc: 0xAAAA_AAAA,
        fraction_lost: 12,
        cumulative_lost: -3,
        ext_highest_seq: 0x0001_2345,
        jitter: 500,
        lsr: 0xAABB_CCDD,
        dlsr: 0x0000_1000,
    }],
};
let mut bytes = vec![0u8; sr.serialized_len()];
sr.serialize_into(&mut bytes).unwrap();
assert_eq!(SenderReport::parse(&bytes).unwrap(), sr);

§Runnable examples

Run with cargo run -p rtcp-packet --example <name>.

§build_sender_report

//! Build an RTCP Sender Report with two reception report blocks from typed
//! fields and serialize it to wire bytes — RFC 3550 §6.4.1.
//!
//! Run with `cargo run -p rtcp-packet --example build_sender_report`.

use broadcast_common::Serialize;
use rtcp_packet::{ReportBlock, SenderReport};

fn main() {
    let sr = SenderReport {
        ssrc: 0x1122_3344,
        ntp_msw: 0xE0E1_E2E3,
        ntp_lsw: 0x1020_3040,
        rtp_timestamp: 0x0009_0000,
        packet_count: 4321,
        octet_count: 999_999,
        report_blocks: vec![
            ReportBlock {
                ssrc: 0xAAAA_AAAA,
                fraction_lost: 12,
                cumulative_lost: 17,
                ext_highest_seq: 0x0001_2345,
                jitter: 500,
                lsr: 0xAABB_CCDD,
                dlsr: 0x0000_1000,
            },
            ReportBlock {
                ssrc: 0xBBBB_BBBB,
                fraction_lost: 0,
                cumulative_lost: -3, // negative: duplicates exceeded losses (§6.4.1)
                ext_highest_seq: 0x0002_0000,
                jitter: 750,
                lsr: 0,
                dlsr: 0,
            },
        ],
    };

    let mut bytes = vec![0u8; sr.serialized_len()];
    sr.serialize_into(&mut bytes).expect("serialize");

    println!("serialized {} bytes:", bytes.len());
    println!(
        "{}",
        bytes
            .iter()
            .map(|b| format!("{b:02x}"))
            .collect::<Vec<_>>()
            .join(" ")
    );
    println!(
        "V={} P={} RC={} PT={}",
        bytes[0] >> 6,
        (bytes[0] >> 5) & 1,
        bytes[0] & 0x1F,
        bytes[1]
    );
}

§parse_compound_packet

//! Build a compound RTCP packet (SR followed by an SDES CNAME chunk, the
//! canonical §6.1 "session report" shape), parse it back, and confirm a
//! byte-exact round trip — RFC 3550 §6.1.
//!
//! Run with `cargo run -p rtcp-packet --example parse_compound_packet`.

use broadcast_common::{Parse, Serialize};
use rtcp_packet::{
    CompoundPacket, ReportBlock, RtcpPacket, SdesChunk, SdesItem, SdesItemType, SenderReport,
    SourceDescription,
};

fn main() {
    let sr = SenderReport {
        ssrc: 0x1122_3344,
        ntp_msw: 0xE1E2_E3E4,
        ntp_lsw: 0x5060_7080,
        rtp_timestamp: 0x000A_0000,
        packet_count: 12345,
        octet_count: 6_789_012,
        report_blocks: vec![ReportBlock {
            ssrc: 0xAAAA_0001,
            fraction_lost: 0,
            cumulative_lost: 0,
            ext_highest_seq: 0x0000_ABCD,
            jitter: 111,
            lsr: 0x1234_5678,
            dlsr: 0x0000_0100,
        }],
    };
    let sdes = SourceDescription {
        chunks: vec![SdesChunk {
            source: 0x1122_3344, // same SSRC as the SR: one participant, two reports
            items: vec![SdesItem {
                item_type: SdesItemType::CName,
                text: "alice@example.com".to_string(),
            }],
        }],
    };

    let compound = CompoundPacket::new(vec![
        RtcpPacket::SenderReport(sr),
        RtcpPacket::SourceDescription(sdes),
    ])
    .expect("SR-first compound packet");

    let mut bytes = vec![0u8; compound.serialized_len()];
    compound.serialize_into(&mut bytes).expect("serialize");
    println!("serialized {} bytes (SR + SDES)", bytes.len());

    let parsed = CompoundPacket::parse(&bytes).expect("parse");
    for (i, pkt) in parsed.packets.iter().enumerate() {
        println!("  packet {i}: {} ({:?})", pkt.name(), pkt.packet_type());
    }

    let mut out = vec![0u8; parsed.serialized_len()];
    parsed.serialize_into(&mut out).expect("re-serialize");
    assert_eq!(out, bytes, "byte-identical round trip");
    println!("round trip byte-identical: OK ({} bytes)", out.len());
}

Structs§

App
RTCP Application-defined packet (RFC 3550 §6.7, PT 204).
Bye
RTCP Goodbye (RFC 3550 §6.6, PT 203).
CommonHeader
The 4-byte RTCP common header shared by every packet type (RFC 3550 §6.1).
CompoundPacket
A compound RTCP packet (RFC 3550 §6.1): a sequence of RTCP packets sent in a single lower-layer datagram. The first packet must be a report (SR or RR); this is validated on both parse and serialize.
ReceiverReport
RTCP Receiver Report (RFC 3550 §6.4.2, PT 201).
ReportBlock
A reception report block (RFC 3550 §6.4.1, 24 bytes). Carried by both SR and RR, one per reported source.
SdesChunk
An SDES chunk: an SSRC/CSRC plus its list of items (RFC 3550 §6.5).
SdesItem
A single SDES item: a typed, length-prefixed text field (RFC 3550 §6.5).
SenderReport
RTCP Sender Report (RFC 3550 §6.4.1, PT 200).
SourceDescription
RTCP Source Description (RFC 3550 §6.5, PT 202).

Enums§

Error
An RTCP packet parse / serialize error.
RtcpPacket
Any single RTCP packet, dispatched by its common-header PT byte (RFC 3550 §6).
RtcpPacketType
The RTCP packet type carried in the common header PT byte (RFC 3550 §6).
SdesItemType
SDES item type (RFC 3550 §6.5). Byte-valued; type 0 is the item terminator.

Constants§

APP_NAME_LEN
Length of the APP name field — 4 ASCII characters (RFC 3550 §6.7).
PT_APP
Packet type: Application-defined (RFC 3550 §6.7).
PT_BYE
Packet type: Goodbye (RFC 3550 §6.6).
PT_RECEIVER_REPORT
Packet type: Receiver Report (RFC 3550 §6.4.2).
PT_SENDER_REPORT
Packet type: Sender Report (RFC 3550 §6.4.1).
PT_SOURCE_DESCRIPTION
Packet type: Source Description (RFC 3550 §6.5).
REPORT_BLOCK_LEN
Length of a single ReportBlock on the wire (RFC 3550 §6.4.1).
SDES_CNAME
SDES item type value: CNAME (RFC 3550 §6.5.1).
SDES_EMAIL
SDES item type value: EMAIL (RFC 3550 §6.5.3).
SDES_LOC
SDES item type value: LOC (RFC 3550 §6.5.5).
SDES_NAME
SDES item type value: NAME (RFC 3550 §6.5.2).
SDES_NOTE
SDES item type value: NOTE (RFC 3550 §6.5.7).
SDES_PHONE
SDES item type value: PHONE (RFC 3550 §6.5.4).
SDES_PRIV
SDES item type value: PRIV (RFC 3550 §6.5.8).
SDES_TOOL
SDES item type value: TOOL (RFC 3550 §6.5.6).

Type Aliases§

Result
Result alias for rtcp-packet parsing/serialization.