Rust实时传输控制协议(RTCP)库rtcp-types的使用,RTCP数据包类型解析与序列化工具

Rust实时传输控制协议(RTCP)库rtcp-types的使用,RTCP数据包类型解析与序列化工具

许可证

rtcp-types采用双重许可:

  • MIT许可证
  • Apache 2.0许可证

贡献

欢迎任何形式的贡献,可以通过提交pull request参与项目。

安装

在项目目录中运行以下Cargo命令:

cargo add rtcp-types

或者在Cargo.toml中添加:

rtcp-types = "0.2.0"

使用示例

以下是一个完整的RTCP数据包解析和序列化示例:

use rtcp_types::{RtcpPacket, SdesChunk, SdesItem, SdesItemType};

fn main() {
    // 创建一个SDES RTCP包
    let sdes_chunk = SdesChunk {
        ssrc: 12345678,
        items: vec![
            SdesItem {
                type_: SdesItemType::Cname,
                text: "example@test".into(),
            },
        ],
    };
    
    let sdes_packet = RtcpPacket::Sdes(vec![sdes_chunk]);
    
    // 序列化RTCP包
    let mut buf = vec![0; 1024];
    let len = sdes_packet.serialize_into(&mut buf).unwrap();
    let serialized = &buf[..len];
    
    println!("Serialized RTCP packet ({} bytes): {:?}", len, serialized);
    
    // 解析RTCP包
    let parsed = RtcpPacket::parse(serialized).unwrap();
    println!("Parsed RTCP packet: {:?}", parsed);
    
    match parsed {
        RtcpPacket::Sdes(chunks) => {
            println!("SDES packet with {} chunks", chunks.len());
            for chunk in chunks {
                println!(" SSRC: {}", chunk.ssrc);
                for item in &chunk.items {
                    println!("  {}: {:?}", item.type_, item.text);
                }
            }
        }
        _ => println!("Not an SDES packet"),
    }
}

完整示例代码

use rtcp_types::{
    App, Bye, ReportBlock, ReceiverReport, RtcpPacket, SdesChunk, SdesItem, 
    SdesItemType, SenderReport
};

fn main() {
    // 1. 创建不同类型的RTCP包
    
    // 创建发送方报告(SR)
    let sr_packet = RtcpPacket::SenderReport(SenderReport {
        ssrc: 123456789,
        ntp_timestamp: 0,
        rtp_timestamp: 0,
        packet_count: 100,
        octet_count: 5000,
        reports: vec![
            ReportBlock {
                ssrc: 987654321,
                fraction_lost: 0,
                packets_lost: 0,
                highest_sequence: 100,
                jitter: 0,
                last_sr: 0,
                delay_since_last_sr: 0,
            },
        ],
    });

    // 创建接收方报告(RR)
    let rr_packet = RtcpPacket::ReceiverReport(ReceiverReport {
        ssrc: 123456789,
        reports: vec![
            ReportBlock {
                ssrc: 987654321,
                fraction_lost: 0,
                packets_lost: 0,
                highest_sequence: 100,
                jitter: 0,
                last_sr: 0,
                delay_since_last_sr: 0,
            },
        ],
    });

    // 创建源描述(SDES)
    let sdes_packet = RtcpPacket::Sdes(vec![
        SdesChunk {
            ssrc: 123456789,
            items: vec![
                SdesItem {
                    type_: SdesItemType::Cname,
                    text: "example@test".into(),
                },
                SdesItem {
                    type_: SdesItemType::Name,
                    text: "Test Stream".into(),
                },
            ],
        },
    ]);

    // 创建再见(BYE)包
    let bye_packet = RtcpPacket::Bye(Bye {
        sources: vec![123456789],
        reason: Some("Stream ended".into()),
    });

    // 创建应用定义(APP)包
    let app_packet = RtcpPacket::App(App {
        ssrc: 123456789,
        name: [b'T', b'E', b'S', b'T'],
        data: b"Application data".to_vec(),
    });

    // 2. 序列化并解析各种RTCP包
    let packets = vec![sr_packet, rr_packet, sdes_packet, bye_packet, app_packet];
    
    for packet in packets {
        println!("\nProcessing packet: {:?}", packet);
        
        // 序列化
        let mut buf = vec![0; 1024];
        let len = packet.serialize_into(&mut buf).unwrap();
        let serialized = &buf[..len];
        println!("Serialized ({} bytes): {:02X?}", len, serialized);
        
        // 解析
        let parsed = RtcpPacket::parse(serialized).unwrap();
        println!("Parsed: {:?}", parsed);
        
        // 打印详细信息
        match &parsed {
            RtcpPacket::SenderReport(sr) => {
                println!("Sender Report:");
                println!(" SSRC: {}", sr.ssrc);
                println!(" Packet count: {}", sr.packet_count);
            },
            RtcpPacket::ReceiverReport(rr) => {
                println!("Receiver Report:");
                println!(" SSRC: {}", rr.ssrc);
                println!(" Reports count: {}", rr.reports.len());
            },
            RtcpPacket::Sdes(chunks) => {
                println!("SDES:");
                for chunk in chunks {
                    println!(" Chunk SSRC: {}", chunk.ssrc);
                    for item in &chunk.items {
                        println!("  {:?}: {}", item.type_, item.text);
                    }
                }
            },
            RtcpPacket::Bye(bye) => {
                println!("BYE:");
                println!(" Sources: {:?}", bye.sources);
                if let Some(reason) = &bye.reason {
                    println!(" Reason: {}", reason);
                }
            },
            RtcpPacket::App(app) => {
                println!("APP:");
                println!(" SSRC: {}", app.ssrc);
                println!(" Name: {:?}", std::str::from_utf8(&app.name).unwrap());
                println!(" Data length: {}", app.data.len());
            },
            _ => println!("Unknown packet type"),
        }
    }
}

功能说明

  1. 支持RFC 3550定义的RTCP协议
  2. 提供RTCP数据包的解析和写入功能
  3. 支持多种RTCP包类型:
    • 发送方报告(SR)
    • 接收方报告(RR)
    • 源描述(SDES)
    • 再见(BYE)
    • 应用定义(APP)

1 回复

Rust RTCP库 rtcp-types 使用指南

rtcp-types 是一个用于处理实时传输控制协议(RTCP)数据包的Rust库,提供了RTCP数据包的类型定义、解析和序列化功能。

主要功能

  • 支持多种RTCP包类型的解析和构造
  • 类型安全的RTCP数据包处理
  • 符合RFC 3550和RFC 5506标准

安装

在Cargo.toml中添加依赖:

[dependencies]
rtcp-types = "0.2"

基本用法

解析RTCP数据包

use rtcp_types::*;
use std::convert::TryInto;

fn main() -> Result<(), RtcpParseError> {
    // 示例RTCP SR数据
    let data: &[u8] = &[
        0x80, 0xc8, 0x00, 0x06, // 头部
        0x12, 0x34, 0x56, 0x78, // SSRC
        0x90, 0x12, 0x34, 0x56, // NTP时间戳高位
        0x78, 0x90, 0x12, 0x34, // NTP时间戳低位
        0x56, 0x78, 0x90, 0x12, // RTP时间戳
        0x00, 0x01, 0x02, 0x03, // 发送者包计数
        0x04, 0x5, 0x06, 0x07, // 发送者字节计数
    ];

    let packet = RtcpPacket::try_from(data)?;
    
    match packet {
        RtcpPacket::SenderReport(sr) => {
            println!("SR包来自SSRC: {}", sr.ssrc);
            println!("NTP时间戳: {:?}", sr.ntp_timestamp);
            println!("RTP时间戳: {}", sr.rtp_timestamp);
        }
        _ => println!("不是SR包"),
    }
    
    Ok(())
}

构造RTCP数据包

use rtcp_types::*;
use std::convert::TryInto;

fn main() -> Result<(), RtcpWriteError> {
    // 构造一个RR包
    let rr = ReceiverReport {
        ssrc: 0x12345678,
        reports: vec![
            ReceptionReport {
                ssrc: 0x87654321,
                fraction_lost: 0,
                packets_lost: 0,
                highest_sequence: 0x1234,
                jitter: 0,
                last_sr: 0,
                delay_since_last_sr: 0,
            }
        ],
    };
    
    // 序列化为字节
    let mut buf = vec![0u8; rr.buffer_len()];
    rr.write_into(&mut buf)?;
    
    println!("构造的RR包: {:?}", buf);
    
    Ok(())
}

完整示例demo

下面是一个完整的RTCP处理示例,展示如何解析和构造不同类型的RTCP包:

use rtcp_types::*;
use std::convert::{TryFrom, TryInto};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 1. 解析复合RTCP包
    let compound_data = vec![
        // SR包
        0x80, 0xc8, 0x00, 0x06,
        0x12, 0x34, 0x56, 0x78,
        0x90, 0x12, 0x34, 0x56,
        0x78, 0x90, 0x12, 0x34,
        0x56, 0x78, 0x90, 0x12,
        0x00, 0x01, 0x02, 0x03,
        0x04, 0x05, 0x06, 0x07,
        // SDES包
        0x81, 0xca, 0x00, 0x03,
        0x12, 0x34, 0x56, 0x78,
        0x01, 0x0f, 0x65, 0x78,
        0x61, 0x6d, 0x70, 0x6c,
        0x65, 0x40, 0x74, 0x65,
        0x73, 0x74, 0x00, 0x00,
    ];
    
    println!("解析复合RTCP包:");
    handle_compound_packet(&compound_data)?;
    
    // 2. 构造一个复合RTCP包
    let mut compound_packet = Vec::new();
    
    // 添加SR包
    let sr = SenderReport {
        ssrc: 0x12345678,
        ntp_timestamp: NtpTimestamp { seconds: 0x90123456, fraction: 0x78901234 },
        rtp_timestamp: 0x56789012,
        sender_packet_count: 0x00010203,
        sender_octet_count: 0x04050607,
    };
    
    let mut buf = vec![0u8; sr.buffer_len()];
    sr.write_into(&mut buf)?;
    compound_packet.extend_from_slice(&buf);
    
    // 添加SDES包
    let sdes = create_custom_sdes();
    buf = vec![0u8; sdes.buffer_len()];
    sdes.write_into(&mut buf)?;
    compound_packet.extend_from_slice(&buf);
    
    println!("\n构造的复合RTCP包: {:02X?}", compound_packet);
    
    Ok(())
}

fn handle_compound_packet(data: &[u8]) -> Result<(), RtcpParseError> {
    let mut offset = 0;
    
    while offset < data.len() {
        let packet = RtcpPacket::try_from(&data[offset..])?;
        
        match packet {
            RtcpPacket::SenderReport(sr) => {
                println!("发现SR包: SSRC={}, RTP时间戳={}", sr.ssrc, sr.rtp_timestamp);
            }
            RtcpPacket::ReceiverReport(rr) => {
                println!("发现RR包: SSRC={}", rr.ssrc);
            }
            RtcpPacket::SourceDescription(sdes) => {
                println!("发现SDES包: 包含{}个源描述", sdes.chunks.len());
                for chunk in &sdes.chunks {
                    for item in &chunk.items {
                        match item {
                            SdesItem::Cname(cname) => println!("  CNAME: {}", cname),
                            SdesItem::Name(name) => println!("  NAME: {}", name),
                            _ => {}
                        }
                    }
                }
            }
            _ => println!("发现其他类型RTCP包"),
        }
        
        offset += packet.buffer_len();
    }
    
    Ok(())
}

fn create_custom_sdes() -> SourceDescription {
    SourceDescription {
        chunks: vec![
            SourceDescriptionChunk {
                ssrc: 0x12345678,
                items: vec![
                    SdesItem::Cname("example@test".to_string()),
                    SdesItem::Name("Test Stream".to_string()),
                    SdesItem::Tool("rtcp-types demo".to_string()),
                ],
            }
        ],
    }
}

这个完整示例展示了:

  1. 如何解析复合RTCP包(包含SR和SDES包)
  2. 如何构造复合RTCP包
  3. 如何处理不同类型的RTCP包
  4. 如何创建自定义的SDES信息

输出将显示解析的RTCP包内容和构造的RTCP包字节数据。

回到顶部