1mod error;
63
64pub mod packet;
66pub mod session;
67pub mod transport;
68pub mod srtp;
69pub mod stats;
70pub mod time;
71pub mod traits;
72pub mod payload;
73pub mod buffer;
74pub mod csrc;
75pub mod rtcp;
76pub mod dtls;
77pub mod sync;
78pub mod api;
79pub mod security;
80pub mod feedback;
81
82pub const DEFAULT_MAX_PACKET_SIZE: usize = 1500;
84
85pub type RtpTimestamp = u32;
87
88pub type RtpSequenceNumber = u16;
90
91pub type RtpSsrc = u32;
93
94pub type RtpCsrc = u32;
96
97pub type Result<T> = std::result::Result<T, Error>;
99
100pub use error::Error;
102
103pub use packet::rtp::RtpPacket;
105pub use packet::header::RtpHeader;
106pub use packet::rtcp::{
107 RtcpPacket, RtcpSenderReport, RtcpReceiverReport,
108 RtcpReportBlock, NtpTimestamp, RtcpSourceDescription,
109 RtcpGoodbye, RtcpApplicationDefined, RtcpExtendedReport,
110 RtcpCompoundPacket, RtcpXrBlock, VoipMetricsBlock
111};
112pub use packet::extension::{
113 ExtensionElement, RtpHeaderExtensions,
114 ids::AUDIO_LEVEL, ids::VIDEO_ORIENTATION,
115 ids::TRANSPORT_CC,
116 ids::FRAME_MARKING, ids::SDES,
117 uris::ABS_SEND_TIME, uris::MID, uris::STREAM_ID, uris::REPAIR_RTP_STREAM_ID,
118 uris::VIDEO_CONTENT_TYPE
119};
120
121pub use session::{RtpSession, RtpSessionConfig, RtpSessionEvent, RtpSessionStats, RtpStream, RtpStreamStats};
123
124pub use transport::{RtpTransport, RtpTransportConfig, UdpRtpTransport};
126
127pub use traits::{MediaTransport, RtpEvent};
129pub use traits::media_transport::RtpMediaTransport;
130
131pub use payload::{
133 PayloadType, PayloadFormat, PayloadFormatFactory, create_payload_format,
134 G711UPayloadFormat, G711APayloadFormat, G722PayloadFormat,
135 OpusPayloadFormat, OpusBandwidth, Vp8PayloadFormat, Vp9PayloadFormat
136};
137
138pub use csrc::{CsrcMapping, CsrcManager, MAX_CSRC_COUNT};
139
140pub use sync::{MediaSync};
142pub use sync::mapping::TimestampMapper;
143pub use sync::clock::MediaClock;
144
145pub use feedback::{
147 FeedbackContext, FeedbackConfig, FeedbackDecision, FeedbackPriority,
148 QualityDegradation, CongestionState, FeedbackGenerator, FeedbackGeneratorFactory
149};
150pub use feedback::packets::{
151 FeedbackPacket, PliPacket, FirPacket, SliPacket, TstoPacket,
152 RembPacket, TransportCcPacket, RTCP_HEADER_SIZE
153};
154pub use feedback::generators::{
155 LossFeedbackGenerator, CongestionFeedbackGenerator, QualityFeedbackGenerator,
156 ComprehensiveFeedbackGenerator
157};
158pub use feedback::algorithms::{
159 GoogleCongestionControl, SimpleBandwidthEstimator, QualityAssessment,
160 QualityMetrics, PacketFeedback
161};
162
163pub use api::client::{MediaTransportClient, ClientFactory, ClientConfig, ClientConfigBuilder};
165pub use api::server::{MediaTransportServer, ServerFactory, ServerConfig, ServerConfigBuilder, ClientInfo};
166pub use api::common::frame::{MediaFrame, MediaFrameType};
167pub use api::common::events::{MediaTransportEvent, MediaEventCallback};
168pub use api::common::stats::{MediaStats, QualityLevel};
169pub use api::common::config::{SecurityMode, SrtpProfile, SecurityInfo, NetworkPreset, BaseTransportConfig};
170pub use api::common::error::{MediaTransportError, SecurityError, BufferError, StatsError};
171pub use api::common::buffer::{MediaBuffer, MediaBufferConfig, BufferStats};
172
173pub mod prelude {
175 pub use crate::{
176 RtpPacket, RtpHeader, RtpSession, RtpSessionConfig,
177 RtpTimestamp, RtpSequenceNumber, RtpSsrc, RtpCsrc,
178 Error, Result,
179 };
180
181 pub use crate::packet::rtcp::{
182 RtcpPacket, RtcpSenderReport, RtcpReceiverReport,
183 RtcpReportBlock, NtpTimestamp
184 };
185
186 pub use crate::traits::{MediaTransport, RtpMediaTransport};
187
188 pub use crate::api::client::{MediaTransportClient, ClientFactory, ClientConfig};
190 pub use crate::api::server::{MediaTransportServer, ServerFactory, ServerConfig, ClientInfo};
191 pub use crate::api::common::frame::{MediaFrame, MediaFrameType};
192 pub use crate::api::common::events::{MediaTransportEvent, MediaEventCallback};
193}
194
195#[cfg(test)]
196mod tests {
197 use super::*;
198 use bytes::Bytes;
199 use packet::{RtpHeader, hex_dump};
200 use tracing::{debug, info};
201
202 fn init_test_logging() {
204 let _ = tracing_subscriber::fmt()
205 .with_max_level(tracing::Level::DEBUG)
206 .try_init();
207 }
208
209 #[test]
210 fn test_rtp_header_serialize_parse() {
211 init_test_logging();
212
213 let original_header = RtpHeader::new(96, 1000, 0x12345678, 0xabcdef01);
215 debug!("Original header: PT={}", original_header.payload_type);
216
217 let mut buf = bytes::BytesMut::with_capacity(12);
219 original_header.serialize(&mut buf).unwrap();
220
221 debug!("Serialized header bytes: [{}]", hex_dump(&buf));
223
224 let buf = buf.freeze();
226
227 let mut reader = buf.clone();
229 let parsed_header = RtpHeader::parse(&mut reader).unwrap();
230 debug!("Parsed header: PT={}", parsed_header.payload_type);
231
232 assert_eq!(parsed_header.version, 2);
234 assert_eq!(parsed_header.payload_type, 96, "Payload type mismatch: expected 96, got {}", parsed_header.payload_type);
235 assert_eq!(parsed_header.sequence_number, 1000);
236 assert_eq!(parsed_header.timestamp, 0x12345678);
237 assert_eq!(parsed_header.ssrc, 0xabcdef01);
238 assert_eq!(parsed_header.padding, false);
239 assert_eq!(parsed_header.extension, false);
240 assert_eq!(parsed_header.cc, 0);
241 assert_eq!(parsed_header.marker, false);
242 }
243
244 #[test]
245 fn test_rtp_packet_serialize_parse() {
246 let payload_data = b"test payload data";
248 let payload = Bytes::copy_from_slice(payload_data);
249
250 let original_packet = RtpPacket::new_with_payload(
252 96, 1000, 0x12345678, 0xabcdef01, payload.clone(),
257 );
258
259 let serialized = original_packet.serialize().unwrap();
261
262 let parsed_packet = RtpPacket::parse(&serialized).unwrap();
264
265 assert_eq!(parsed_packet.header.version, 2);
267 assert_eq!(parsed_packet.header.payload_type, 96);
268 assert_eq!(parsed_packet.header.sequence_number, 1000);
269 assert_eq!(parsed_packet.header.timestamp, 0x12345678);
270 assert_eq!(parsed_packet.header.ssrc, 0xabcdef01);
271 assert_eq!(parsed_packet.payload, payload);
272 }
273
274 #[test]
275 fn test_rtp_header_with_csrc() {
276 let mut header = RtpHeader::new(96, 1000, 0x12345678, 0xabcdef01);
278 header.csrc = vec![0x11111111, 0x22222222];
279 header.cc = 2;
280
281 let mut buf = bytes::BytesMut::with_capacity(20);
283 header.serialize(&mut buf).unwrap();
284
285 let mut reader = buf.freeze();
287 let parsed_header = RtpHeader::parse(&mut reader).unwrap();
288
289 assert_eq!(parsed_header.cc, 2);
291 assert_eq!(parsed_header.csrc.len(), 2);
292 assert_eq!(parsed_header.csrc[0], 0x11111111);
293 assert_eq!(parsed_header.csrc[1], 0x22222222);
294 }
295
296 #[test]
297 fn test_rtp_header_with_extension() {
298 init_test_logging();
299
300 let mut header = RtpHeader::new(96, 1000, 0x12345678, 0xabcdef01);
302 header.extension = true;
303
304 let mut ext = RtpHeaderExtensions::new_legacy(0x1234);
306 ext.elements.push(ExtensionElement {
308 id: 1, data: Bytes::from_static(b"extension data"),
310 });
311 header.extensions = Some(ext);
312
313 debug!("Original header with extension: ext={}, format={:?}, data_len={:?}",
314 header.extension, header.extensions.as_ref().map(|e| e.format),
315 header.extensions.as_ref().map(|e| e.elements.iter().map(|el| el.data.len()).sum::<usize>()));
316
317 let mut buf = bytes::BytesMut::with_capacity(40);
319 header.serialize(&mut buf).unwrap();
320 debug!("Serialized extension header (size={}): [{}]", buf.len(), hex_dump(&buf));
321
322 let first_byte = buf[0];
324 debug!("First byte: 0x{:02x}, extension bit set: {}",
325 first_byte, ((first_byte >> 4) & 0x01) == 1);
326
327 let version = (first_byte >> 6) & 0x03;
329 let padding = ((first_byte >> 5) & 0x01) == 1;
330 let extension = ((first_byte >> 4) & 0x01) == 1;
331 let cc = first_byte & 0x0F;
332 debug!("Manual parse of first byte 0x{:02x}: V={}, P={}, X={}, CC={}",
333 first_byte, version, padding, extension, cc);
334
335 let mut reader = buf.freeze();
337 debug!("Buffer size for parsing: {}", reader.len());
338
339 let parse_result = RtpHeader::parse(&mut reader);
340 if let Err(ref e) = parse_result {
341 debug!("Parse error: {:?}", e);
342 }
343
344 let parsed_header = parse_result.unwrap();
345 debug!("Remaining bytes after parse: {}", reader.len());
346
347 assert_eq!(parsed_header.extension, true);
349 assert!(parsed_header.extensions.is_some());
350
351 let parsed_extensions = parsed_header.extensions.unwrap();
352 assert_eq!(parsed_extensions.profile_id, 0x1234);
353 assert!(!parsed_extensions.elements.is_empty());
354
355 let parsed_data = &parsed_extensions.elements[0].data;
357 let original_data = b"extension data";
358
359 assert!(parsed_data.starts_with(original_data),
361 "Extension data doesn't match. Expected to start with: {:?}, got: {:?}",
362 original_data, parsed_data);
363 }
364
365 #[test]
366 fn test_parse_real_world_packet() {
367 init_test_logging();
368
369 let packet_data = [
373 0x80, 0x00, 0xfd, 0x70, 0x00, 0x00, 0x00, 0x00,
374 0x00, 0x00, 0x00, 0x00, 0x54, 0x65, 0x73, 0x74
375 ];
376
377 debug!("Test packet data: [{}]", hex_dump(&packet_data));
378
379 let mut buf = Bytes::copy_from_slice(&packet_data);
381 let header_result = packet::RtpHeader::parse(&mut buf);
382
383 if let Err(ref e) = header_result {
384 debug!("RTP header parse failed: {:?}", e);
385 } else {
386 debug!("RTP header parse succeeded, remaining bytes: {}", buf.len());
387 }
388
389 assert!(header_result.is_ok(), "Failed to parse RTP header: {:?}", header_result.err());
390
391 let packet_result = RtpPacket::parse(&packet_data);
393
394 if let Err(ref e) = packet_result {
395 debug!("RTP packet parse failed: {:?}", e);
396 } else {
397 debug!("RTP packet parse succeeded");
398 }
399
400 assert!(packet_result.is_ok(), "Failed to parse RTP packet: {:?}", packet_result.err());
401
402 let parsed = packet_result.unwrap();
403
404 assert_eq!(parsed.header.version, 2); assert_eq!(parsed.header.payload_type, 0); assert_eq!(parsed.header.cc, 0); assert_eq!(parsed.header.sequence_number, 0xfd70); assert_eq!(parsed.header.timestamp, 0); assert_eq!(parsed.header.ssrc, 0); assert_eq!(parsed.payload.len(), 4);
414 assert_eq!(parsed.payload.as_ref(), &b"Test"[..]);
415 }
416
417 #[test]
418 fn test_serialize_rtp_packet_with_extension() {
419 let mut header = RtpHeader::new(96, 1000, 12345, 0xABCDEF01);
421 header.extension = true;
422
423 let mut ext = RtpHeaderExtensions::new_legacy(0x1234);
425 ext.elements.push(ExtensionElement {
427 id: 1, data: Bytes::from_static(b"extension data"),
429 });
430 header.extensions = Some(ext);
431
432 println!("Extension: {}, profile ID: {}, Data length: {}",
433 header.extension,
434 header.extensions.as_ref().map(|e| e.profile_id).unwrap_or(0),
435 header.extensions.as_ref().map(|e| e.elements.iter().map(|el| el.data.len()).sum::<usize>()).unwrap_or(0));
436
437 let payload = Bytes::from_static(b"test payload");
439 let packet = RtpPacket::new(header, payload);
440
441 let bytes = packet.serialize().unwrap();
443
444 assert_eq!(bytes[0] & 0x10, 0x10);
446
447 let ext_header_offset = 12;
449
450 let ext_id = ((bytes[ext_header_offset] as u16) << 8) | (bytes[ext_header_offset + 1] as u16);
452 let ext_len_words = ((bytes[ext_header_offset + 2] as u16) << 8) | (bytes[ext_header_offset + 3] as u16);
453
454 assert_eq!(ext_id, 0x1234);
455
456 assert_eq!(ext_len_words * 4, 16); let ext_data_offset = ext_header_offset + 4;
461 let ext_data = &bytes[ext_data_offset..ext_data_offset + 14];
462
463 let expected_data = b"extension data";
465 for i in 0..expected_data.len() {
466 assert_eq!(ext_data[i], expected_data[i]);
467 }
468 }
469
470 #[test]
471 fn test_parse_rtp_packet_with_extension() {
472 let mut header = RtpHeader::new(96, 1000, 12345, 0xABCDEF01);
474 header.extension = true;
475
476 let mut ext = RtpHeaderExtensions::new_legacy(0x1234);
478 ext.elements.push(ExtensionElement {
480 id: 1, data: Bytes::from_static(b"extension data"),
482 });
483 header.extensions = Some(ext);
484
485 let payload = Bytes::from_static(b"test payload");
487 let packet = RtpPacket::new(header, payload);
488
489 let bytes = packet.serialize().unwrap();
491
492 let parsed_packet = RtpPacket::parse(&bytes).unwrap();
494 let parsed_header = parsed_packet.header;
495
496 assert_eq!(parsed_header.extension, true);
498 assert!(parsed_header.extensions.is_some());
499
500 let parsed_extensions = parsed_header.extensions.unwrap();
501 assert_eq!(parsed_extensions.profile_id, 0x1234);
502 assert!(!parsed_extensions.elements.is_empty());
503
504 let parsed_data = &parsed_extensions.elements[0].data;
506
507 let original_data = b"extension data";
509 assert!(parsed_data.starts_with(original_data),
510 "Extension data doesn't match original. Expected to start with: {:?}, got: {:?}",
511 original_data, parsed_data);
512
513 assert_eq!(parsed_packet.payload.as_ref(), b"test payload" as &[u8]);
515 }
516}