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"),
}
}
}
功能说明
- 支持RFC 3550定义的RTCP协议
- 提供RTCP数据包的解析和写入功能
- 支持多种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()),
],
}
],
}
}
这个完整示例展示了:
- 如何解析复合RTCP包(包含SR和SDES包)
- 如何构造复合RTCP包
- 如何处理不同类型的RTCP包
- 如何创建自定义的SDES信息
输出将显示解析的RTCP包内容和构造的RTCP包字节数据。