rvoip_rtp_core/
lib.rs

1//! RTP Core library for the RVOIP project
2//! 
3//! This crate provides RTP packet encoding/decoding, RTCP support,
4//! and other utilities for handling real-time media transport.
5//!
6//! The library is organized into several modules:
7//!
8//! - `packet`: RTP and RTCP packet definitions and processing
9//! - `session`: RTP session management including SSRC demultiplexing
10//! - `transport`: Network transport for RTP/RTCP
11//! - `srtp`: Secure RTP implementation
12//! - `stats`: RTP statistics collection
13//! - `time`: Timing and clock utilities
14//! - `sync`: Media synchronization for multiple streams
15//! - `traits`: Public traits for integration with other crates
16//! - `payload`: RTP payload format handlers
17//! - `buffer`: High-performance buffer management for receiving and transmitting packets
18//! - `csrc`: CSRC management
19//! - `error`: Error handling
20//! - `rtcp`: RTCP packet definitions and processing
21//! - `dtls`: DTLS support
22//! - `api`: New API module with client/server separation
23//! - `feedback`: Advanced RTCP feedback mechanisms for real-time adaptation
24//!
25//! ## New API Structure
26//!
27//! The `api` module provides a higher-level interface with clear client/server separation:
28//!
29//! - `api::client`: Client-side media transport for sending/receiving media frames
30//! - `api::server`: Server-side media transport for handling multiple clients
31//! - `api::common`: Shared types and utilities used by both client and server
32//!
33//! This structure makes the library easier to use for higher-level components like media-core.
34//!
35//! ## Advanced RTCP Feedback
36//!
37//! The `feedback` module provides intelligent RTCP feedback generation for optimal media quality:
38//!
39//! - Picture Loss Indication (PLI) and Full Intra Request (FIR) for video recovery
40//! - Receiver Estimated Max Bitrate (REMB) for bandwidth adaptation
41//! - Transport-wide Congestion Control feedback for network optimization
42//! - Google Congestion Control (GCC) algorithm implementation
43//! - Quality-based feedback decisions using multiple network metrics
44//! - Configurable feedback generation with rate limiting and priority handling
45//!
46//! This enables WebRTC-compatible adaptive streaming with automatic quality optimization.
47//!
48//! ## Buffer Management
49//!
50//! The `buffer` module provides optimized memory and packet management
51//! for high-scale deployments:
52//!
53//! - Memory pooling to reduce allocations
54//! - Adaptive jitter buffer for handling network variation
55//! - Priority-based transmit buffering
56//! - Congestion control for network adaptation
57//! - Global memory limits to prevent OOM conditions
58//! - Efficient packet ordering and scheduling
59//!
60//! This is ideal for deployments handling tens of thousands of concurrent streams.
61
62mod error;
63
64// Main modules
65pub 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
82/// The default maximum size for RTP packets in bytes
83pub const DEFAULT_MAX_PACKET_SIZE: usize = 1500;
84
85/// Typedef for RTP timestamp values
86pub type RtpTimestamp = u32;
87
88/// Typedef for RTP sequence numbers
89pub type RtpSequenceNumber = u16;
90
91/// Typedef for RTP synchronization source identifier
92pub type RtpSsrc = u32;
93
94/// Typedef for RTP contributing source identifier
95pub type RtpCsrc = u32;
96
97/// Result type for RTP operations
98pub type Result<T> = std::result::Result<T, Error>;
99
100// Re-export core types
101pub use error::Error;
102
103// Re-export common types from packet module
104pub 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
121// Re-export session types
122pub use session::{RtpSession, RtpSessionConfig, RtpSessionEvent, RtpSessionStats, RtpStream, RtpStreamStats};
123
124// Re-export transport types
125pub use transport::{RtpTransport, RtpTransportConfig, UdpRtpTransport};
126
127// Re-export traits for media-core integration
128pub use traits::{MediaTransport, RtpEvent};
129pub use traits::media_transport::RtpMediaTransport;
130
131// Re-export payload format types
132pub 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
140// Re-export sync utilities
141pub use sync::{MediaSync};
142pub use sync::mapping::TimestampMapper;
143pub use sync::clock::MediaClock;
144
145// Re-export feedback types for RTCP feedback mechanisms
146pub 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
163// Re-export the new API components for easier access
164pub 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
173/// Prelude module with commonly used types
174pub 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    // Add new API types to prelude for easy access
189    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    // Set up a simple test logger
203    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        // Create a simple RTP header
214        let original_header = RtpHeader::new(96, 1000, 0x12345678, 0xabcdef01);
215        debug!("Original header: PT={}", original_header.payload_type);
216        
217        // Serialize the header
218        let mut buf = bytes::BytesMut::with_capacity(12);
219        original_header.serialize(&mut buf).unwrap();
220        
221        // Debug serialized buffer
222        debug!("Serialized header bytes: [{}]", hex_dump(&buf));
223        
224        // Convert to bytes
225        let buf = buf.freeze();
226        
227        // Parse the header back
228        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        // Verify fields
233        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        // Create payload
247        let payload_data = b"test payload data";
248        let payload = Bytes::copy_from_slice(payload_data);
249        
250        // Create a packet
251        let original_packet = RtpPacket::new_with_payload(
252            96,                  // Payload type
253            1000,                // Sequence number
254            0x12345678,          // Timestamp
255            0xabcdef01,          // SSRC
256            payload.clone(),
257        );
258        
259        // Serialize the packet
260        let serialized = original_packet.serialize().unwrap();
261        
262        // Parse it back
263        let parsed_packet = RtpPacket::parse(&serialized).unwrap();
264        
265        // Verify fields
266        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        // Create header with CSRC list
277        let mut header = RtpHeader::new(96, 1000, 0x12345678, 0xabcdef01);
278        header.csrc = vec![0x11111111, 0x22222222];
279        header.cc = 2;
280        
281        // Serialize the header
282        let mut buf = bytes::BytesMut::with_capacity(20);
283        header.serialize(&mut buf).unwrap();
284        
285        // Parse it back
286        let mut reader = buf.freeze();
287        let parsed_header = RtpHeader::parse(&mut reader).unwrap();
288        
289        // Verify fields
290        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        // Create header with extension
301        let mut header = RtpHeader::new(96, 1000, 0x12345678, 0xabcdef01);
302        header.extension = true;
303        
304        // Create extensions with legacy format (0x1234 profile ID)
305        let mut ext = RtpHeaderExtensions::new_legacy(0x1234);
306        // Add a single extension element with the extension data
307        ext.elements.push(ExtensionElement {
308            id: 1, // Any ID for legacy format
309            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        // Serialize the header
318        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        // Directly check if extension bit is correctly set in serialized data
323        let first_byte = buf[0];
324        debug!("First byte: 0x{:02x}, extension bit set: {}", 
325               first_byte, ((first_byte >> 4) & 0x01) == 1);
326        
327        // Manually parse first byte to make sure our bit positions are correct
328        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        // Parse it back with our parser
336        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        // Verify fields
348        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        // Get the parsed extension data
356        let parsed_data = &parsed_extensions.elements[0].data;
357        let original_data = b"extension data";
358        
359        // Verify that the parsed data contains the original data
360        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        // This is the hex data from a typical RTP packet:
370        // First byte: 0x80 = Version 2, no padding, no extension, 0 CSRCs
371        // Second byte: 0x00 = No marker, PT 0 (PCMU/G.711)
372        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        // Try to parse the RTP header directly first
380        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        // Now try to parse the full packet
392        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        // Verify header fields based on the hex data
405        assert_eq!(parsed.header.version, 2); // 0x80 -> version 2
406        assert_eq!(parsed.header.payload_type, 0); // 0x00 -> PT 0
407        assert_eq!(parsed.header.cc, 0); // 0x80 -> 0 CSRCs
408        assert_eq!(parsed.header.sequence_number, 0xfd70); // Sequence from bytes 2-3
409        assert_eq!(parsed.header.timestamp, 0); // Timestamp from bytes 4-7
410        assert_eq!(parsed.header.ssrc, 0); // SSRC from bytes 8-11
411        
412        // The payload should be "Test"
413        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        // Create a header with extension
420        let mut header = RtpHeader::new(96, 1000, 12345, 0xABCDEF01);
421        header.extension = true;
422        
423        // Create extensions with legacy format (0x1234 profile ID)
424        let mut ext = RtpHeaderExtensions::new_legacy(0x1234);
425        // Add a single extension element with the extension data
426        ext.elements.push(ExtensionElement {
427            id: 1, // Any ID for legacy format
428            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        // Create packet
438        let payload = Bytes::from_static(b"test payload");
439        let packet = RtpPacket::new(header, payload);
440        
441        // Serialize
442        let bytes = packet.serialize().unwrap();
443        
444        // Should have extension flag set in header
445        assert_eq!(bytes[0] & 0x10, 0x10);
446        
447        // Extension header offset: 12 (fixed header) + 0 (no CSRCs)
448        let ext_header_offset = 12;
449        
450        // Extension header: defined ID (16 bits) + length in 32-bit words (16 bits)
451        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        // Length in 32-bit words, so multiply by 4 to get bytes
457        assert_eq!(ext_len_words * 4, 16); // 16 bytes (rounded up to multiple of 4)
458        
459        // Extension data starts after extension header
460        let ext_data_offset = ext_header_offset + 4;
461        let ext_data = &bytes[ext_data_offset..ext_data_offset + 14];
462        
463        // Check that the first bytes match our extension
464        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        // Create a header with extension
473        let mut header = RtpHeader::new(96, 1000, 12345, 0xABCDEF01);
474        header.extension = true;
475        
476        // Create extensions with legacy format (0x1234 profile ID)
477        let mut ext = RtpHeaderExtensions::new_legacy(0x1234);
478        // Add a single extension element with the extension data
479        ext.elements.push(ExtensionElement {
480            id: 1, // Any ID for legacy format
481            data: Bytes::from_static(b"extension data"),
482        });
483        header.extensions = Some(ext);
484        
485        // Create packet
486        let payload = Bytes::from_static(b"test payload");
487        let packet = RtpPacket::new(header, payload);
488        
489        // Serialize
490        let bytes = packet.serialize().unwrap();
491        
492        // Parse back
493        let parsed_packet = RtpPacket::parse(&bytes).unwrap();
494        let parsed_header = parsed_packet.header;
495        
496        // Check extension fields
497        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        // Get the parsed extension data
505        let parsed_data = &parsed_extensions.elements[0].data;
506        
507        // Compare the content, accounting for possible padding bytes
508        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        // Check that the payload is correctly parsed
514        assert_eq!(parsed_packet.payload.as_ref(), b"test payload" as &[u8]);
515    }
516}