### Start Direct RTP Setup Source: https://docs.rs/rustrtc/0.3.51/rustrtc/transports/ice/struct.IceTransport.html Asynchronously sets up a direct UDP socket for RTP mode to a specified remote address without ICE gathering. Binds a socket, registers it, and marks the transport as connected. ```rust pub async fn start_direct(&self, remote_addr: SocketAddr) -> Result<()> ``` -------------------------------- ### Simulcast Setup Source: https://docs.rs/rustrtc/0.3.51/src/rustrtc/peer_connection.rs.html Initializes a PeerConnection and prepares for creating an SDP with Simulcast, requiring extension maps for RIDs. ```rust #[tokio::test] async fn test_simulcast_setup() { use crate::{SdpType, SessionDescription}; let pc = PeerConnection::new(RtcConfiguration::default()); // Create SDP with Simulcast // We need to include extmap for RID ``` -------------------------------- ### Start Ice Gathering Source: https://docs.rs/rustrtc/0.3.51/rustrtc/transports/ice/struct.IceTransport.html Initiates the ICE candidate gathering process. Returns an error if gathering cannot be started. ```rust pub fn start_gathering(&self) -> Result<()> ``` -------------------------------- ### Create New RtcConfigurationBuilder Source: https://docs.rs/rustrtc/0.3.51/rustrtc/config/struct.RtcConfigurationBuilder.html Initializes a new RtcConfigurationBuilder instance. This is the starting point for configuring an RtcConfiguration. ```rust pub fn new() -> Self ``` -------------------------------- ### Start Direct ICE for SRTP Source: https://docs.rs/rustrtc/0.3.51/src/rustrtc/peer_connection.rs.html Initiates a direct ICE connection for SRTP mode using the provided remote address. This is an alternative to direct RTP setup. ```rust } else if let Some(addr) = remote_addr { // SRTP mode: use ICE start_direct self.inner .ice_transport .start_direct(addr) .await .map_err(|e| crate::RtcError::Internal(format!("ICE direct error: {}", e)))?; } ``` -------------------------------- ### Create PeerConnection and Handle SDP Offer/Answer Source: https://docs.rs/rustrtc/0.3.51/src/rustrtc/peer_connection.rs.html This snippet shows how to initialize an RtcConfiguration, create a PeerConnection, add audio and video transceivers, set a remote offer, and generate an answer. It verifies that the answer does not contain BUNDLE or MID attributes when the offer does not. ```rust // No a=group:BUNDLE in this remote offer (traditional SIP style) let remote_sdp = "v=0\r\n\ o=- 1 1 IN IP4 192.168.1.100\r\n\ s=-\r\n\ t=0 0\r\n\ c=IN IP4 192.168.1.100\r\n\ m=audio 5000 RTP/AVP 8\r\n\ a=mid:as\r\n\ a=sendrecv\r\n\ a=rtpmap:8 PCMA/8000\r\n\ m=video 5002 RTP/AVP 96\r\n\ a=mid:vs\r\n\ a=sendrecv\r\n\ a=rtpmap:96 H264/90000\r\n\ a=fmtp:96 packetization-mode=0;profile-level-id=42801F\r\n"; let mut config = RtcConfiguration::default(); config.transport_mode = TransportMode::Rtp; config.media_capabilities = Some(MediaCapabilities { audio: vec![AudioCapability::pcma()], video: vec![crate::config::VideoCapability::h264()], application: None, }); let pc = PeerConnection::new(config); pc.add_transceiver(MediaKind::Audio, TransceiverDirection::SendRecv); pc.add_transceiver(MediaKind::Video, TransceiverDirection::SendRecv); let remote = SessionDescription::parse(SdpType::Offer, remote_sdp).unwrap(); pc.set_remote_description(remote).await.unwrap(); let answer = pc.create_answer().await.unwrap(); let sdp = answer.to_sdp_string(); assert!( !sdp.contains("a=group:BUNDLE"), "answer to non-BUNDLE offer must not have a=group:BUNDLE, got:\n{sdp}" ); // Neither section should have a=mid since there is no BUNDLE group assert!( !sdp.contains("a=mid:"), "answer to non-BUNDLE offer must not have a=mid in any section, got:\n{sdp}" ); ``` -------------------------------- ### Handling File Metadata Operations with Result Source: https://docs.rs/rustrtc/0.3.51/rustrtc/errors/type.SrtpResult.html Demonstrates using `and_then` to chain fallible operations like getting file metadata. This example shows how to handle potential errors, such as a file not being found. ```rust use std::{io::ErrorKind, path::Path}; // Note: on Windows "/" maps to "C:\" let root_modified_time = Path::new("/").metadata().and_then(|md| md.modified()); assert!(root_modified_time.is_ok()); let should_fail = Path::new("/bad/path").metadata().and_then(|md| md.modified()); assert!(should_fail.is_err()); assert_eq!(should_fail.unwrap_err().kind(), ErrorKind::NotFound); ``` -------------------------------- ### Create Offer and Set Local Description Source: https://docs.rs/rustrtc/0.3.51/src/rustrtc/peer_connection.rs.html Creates an SDP offer, sets it as the local description, and asserts the signaling state. This is a common first step in establishing a WebRTC connection. ```rust let offer = pc.create_offer().await.unwrap(); let mid = offer.media_sections[0].mid.clone(); pc.set_local_description(offer).unwrap(); assert_eq!(pc.signaling_state(), SignalingState::HaveLocalOffer); ``` -------------------------------- ### Set remote description and verify audio clock rate Source: https://docs.rs/rustrtc/0.3.51/src/rustrtc/peer_connection.rs.html This example demonstrates setting a remote SDP description and verifying that the audio codec's clock rate is correctly parsed and applied. It includes a mock depacketizer factory for custom handling. ```rust use crate::media::MediaStreamTrack; use crate::media::depacketizer::{ Depacketizer, DepacketizerFactory, PassThroughDepacketizer, }; #[derive(Debug)] struct MockFactory; impl DepacketizerFactory for MockFactory { fn create(&self, _kind: crate::media::frame::MediaKind) -> Box { Box::new(PassThroughDepacketizer) } } let mut config = RtcConfiguration::default(); config.transport_mode = TransportMode::Rtp; config.depacketizer_strategy.factory = Arc::new(MockFactory); let pc = PeerConnection::new(config); let transceiver = pc.add_transceiver(MediaKind::Audio, TransceiverDirection::RecvOnly); let remote_sdp = "\ v=0 o=- 12345 12345 IN IP4 192.168.1.100 s=- c=IN IP4 192.168.1.100 t=0 0 m=audio 9000 RTP/AVP 8 a=rtpmap:8 PCMA/8000 a=sendonly a=mid:0 "; let remote_offer = SessionDescription::parse(SdpType::Offer, remote_sdp).unwrap(); pc.set_remote_description(remote_offer).await.unwrap(); let payload_map = transceiver.get_payload_map(); let codec = payload_map.get(&8).unwrap(); assert_eq!(codec.clock_rate, 8000); assert_eq!(codec.channels, 0); let receiver = transceiver.receiver().unwrap(); let (_socket_tx, socket_rx) = tokio::sync::watch::channel::>(None); let ice_conn = crate::transports::ice::conn::IceConn::new(socket_rx, "127.0.0.1:0".parse().unwrap()); let transport = Arc::new(crate::transports::rtp::RtpTransport::new(ice_conn, false)); receiver.set_transport(transport, None, None); tokio::task::yield_now().await; let packet_tx = receiver.packet_tx().unwrap(); let packet = RtpPacket::new( crate::rtp::RtpHeader::new(8, 7, 320, 0x2233_4455), vec![0x11, 0x22, 0x33], ); packet_tx .send((packet, "127.0.0.1:5004".parse().unwrap())) .await .unwrap(); let sample = tokio::time::timeout(std::time::Duration::from_secs(1), receiver.track().recv()) .await .unwrap() .unwrap(); match sample { crate::media::MediaSample::Audio(frame) => { assert_eq!(frame.clock_rate, 8000); assert_eq!(frame.payload_type, Some(8)); assert_eq!(frame.rtp_timestamp, 320); } other => panic!("expected audio sample, got {:?}", other), } ``` -------------------------------- ### Apply SACK - Remove Gaps and Track RTT Source: https://docs.rs/rustrtc/0.3.51/src/rustrtc/transports/sctp.rs.html Processes received SACK information to remove acknowledged packets from the sent list and update RTT measurements. This example focuses on the initial setup for tracking RTT. ```rust let mut sent: BTreeMap = BTreeMap::new(); let base = Instant::now() - Duration::from_millis(100); sent.insert( 10, ChunkRecord { payload: Bytes::from_static(b"a"), sent_time: base, transmit_count: 1, missing_reports: 0, abandoned: false, fast_retransmit: false, fast_retransmit_time: None, needs_retransmit: false, in_flight: true, acked: false, stream_id: 0, ssn: 0, }, ); ``` -------------------------------- ### Start Ice Transport with Remote Parameters Source: https://docs.rs/rustrtc/0.3.51/rustrtc/transports/ice/struct.IceTransport.html Starts the ICE transport using the provided remote ICE parameters. Returns an error if the transport cannot be started. ```rust pub fn start(&self, remote: IceParameters) -> Result<()> ``` -------------------------------- ### Create RtpSender and Verify SDP Source: https://docs.rs/rustrtc/0.3.51/src/rustrtc/peer_connection.rs.html Demonstrates creating an RtpSender and verifying that the generated SDP string contains the expected connection (c=) and origin lines with the external IP address. ```rust let sender = RtpSender::builder(track, 12345) .stream_id("s".to_string()) .params(params) .build(); transceiver.set_sender(Some(sender)); let offer = pc.create_offer().await.unwrap(); let sdp_text = offer.to_sdp_string(); // Connection line must contain the external IP assert!( sdp_text.contains("c=IN IP4 203.0.113.5"), "SDP c= line should use external_ip, got:\n{}", sdp_text ); // Origin should also use external IP assert!( sdp_text.contains("203.0.113.5"), "SDP origin should reference external_ip" ); ``` -------------------------------- ### SRTP Context Initialization Source: https://docs.rs/rustrtc/0.3.51/src/rustrtc/srtp.rs.html Demonstrates how to create a new SRTP context with specified parameters. ```APIDOC ## POST /srtp/context ### Description Initializes a new SRTP context for encrypting and decrypting RTP and RTCP packets. ### Method POST ### Endpoint /srtp/context ### Parameters #### Request Body - **ssrc** (u32) - Required - The Synchronization Source (SSRC) identifier. - **profile** (SrtpProfile) - Required - The SRTP profile to use (e.g., SrtpProfile::AeadAes128Gcm). - **keying** (SrtpKeyingMaterial) - Required - The master key and salt for key derivation. - **master_key** (Vec) - Required - The master encryption key. - **master_salt** (Vec) - Required - The master salt. - **direction** (SrtpDirection) - Required - The direction of the SRTP stream (e.g., SrtpDirection::Send, SrtpDirection::Recv). ### Request Example ```json { "ssrc": 12345, "profile": "AeadAes128Gcm", "keying": { "master_key": "...", "master_salt": "..." }, "direction": "Send" } ``` ### Response #### Success Response (200) - **SrtpContext** (object) - The initialized SRTP context. - **ssrc** (u32) - The SSRC. - **_profile** (SrtpProfile) - The SRTP profile used. - **rtp_keys** (SessionKeys) - Keys for RTP stream. - **rtcp_keys** (SessionKeys) - Keys for RTCP stream. - **rtp_gcm_cipher** (Option) - RTP GCM cipher if applicable. - **rtcp_gcm_cipher** (Option) - RTCP GCM cipher if applicable. - **rtp_auth_prototype** (Option) - RTP authentication prototype if applicable. - **direction** (SrtpDirection) - The SRTP stream direction. - **rollover_counter** (u32) - The rollover counter. - **last_sequence** (Option) - The last sequence number. - **rtcp_index** (u32) - The RTCP index. #### Response Example ```json { "ssrc": 12345, "_profile": "AeadAes128Gcm", "rtp_keys": { "cipher_key": "...", "auth_key": "...", "salt": "..." }, "rtcp_keys": { "cipher_key": "...", "auth_key": "...", "salt": "..." }, "rtp_gcm_cipher": { "..." }, "rtcp_gcm_cipher": { "..." }, "rtp_auth_prototype": { "..." }, "direction": "Send", "rollover_counter": 0, "last_sequence": null, "rtcp_index": 0 } ``` ``` -------------------------------- ### Create Offer Source: https://docs.rs/rustrtc/0.3.51/rustrtc/peer_connection/struct.PeerConnection.html Asynchronously creates an SDP offer for the PeerConnection. ```rust pub async fn create_offer(&self) -> RtcResult ``` -------------------------------- ### Add DTLS Fingerprint and Setup Attributes Source: https://docs.rs/rustrtc/0.3.51/src/rustrtc/sdp.rs.html Adds DTLS fingerprint (sha-256) and setup attributes to the SDP. ```rust pub fn add_dtls_attributes(&mut self, fingerprint_hash: &str, setup: &str) { self.attributes.push(Attribute::new( "fingerprint", Some(format!("sha-256 {}", fingerprint_hash)), )); self.attributes .push(Attribute::new("setup", Some(setup.to_string()))); } ``` -------------------------------- ### Start SRTP Session Source: https://docs.rs/rustrtc/0.3.51/src/rustrtc/transports/rtp.rs.html Starts an SRTP session by setting the SrtpSession. This is typically called after the ICE connection is established. ```rust pub fn start_srtp(&self, srtp_session: SrtpSession) { let mut session = self.srtp_session.lock(); *session = Some(Arc::new(Mutex::new(srtp_session))); } ``` -------------------------------- ### Start SRTP Session and Configure Transceivers Source: https://docs.rs/rustrtc/0.3.51/src/rustrtc/peer_connection.rs.html Starts an SRTP session and configures senders and receivers for each transceiver with the provided RTP transport. ```rust Ok(session) => { rtp_transport.start_srtp(session); let transceivers = self.inner.transceivers.lock(); for t in transceivers.iter() { let sender_arc = t.sender.lock().clone(); let receiver_arc = t.receiver.lock().clone(); if let Some(sender) = &sender_arc { let mid_opt = t.mid(); trace!( "start_dtls: transceiver kind={:?} mid={:?}", t.kind(), mid_opt ); sender.set_transport(rtp_transport.clone()); } if let Some(receiver) = &receiver_arc { receiver.set_transport( rtp_transport.clone(), Some(self.inner.event_tx.clone()), Some(Arc::downgrade(&t)), ); if let Some(sender) = &sender_arc { receiver.set_feedback_ssrc(sender.ssrc()); } } } // Update the inner transport to ensure future transceivers get the correct one *self.inner.rtp_transport.lock() = Some(rtp_transport.clone()); } Err(e) => { debug!("Failed to create SRTP session: {}", e); } } ``` -------------------------------- ### SDP Offer String Source: https://docs.rs/rustrtc/0.3.51/src/rustrtc/peer_connection.rs.html A sample SDP offer string used for initial negotiation. ```rust let remote_offer = "v=0\r\n\ o=- 1 1 IN IP4 10.0.0.1\r\n\ s=-\r\n\ t=0 0\r\n\ c=IN IP4 10.0.0.1\r\n\ m=audio 8000 RTP/AVP 9 101\r\n\ a=rtpmap:9 G722/8000\r\n\ a=rtpmap:101 telephone-event/8000\r\n\ a=fmtp:101 0-16\r\n\ a=sendrecv\r\n"; ``` -------------------------------- ### RustRTC Slow Start Congestion Control Source: https://docs.rs/rustrtc/0.3.51/src/rustrtc/transports/sctp.rs.html Implements the Slow Start phase of congestion control. Increases the congestion window (cwnd) by the minimum of bytes sent and MTU, up to the maximum cwnd. Use when the current window size is less than or equal to the slow start threshold (ssthresh). ```rust let increase = done_bytes.min(MAX_SCTP_PACKET_SIZE); let new_cwnd = (cwnd + increase).min(self.max_cwnd); let actual_increase = new_cwnd - cwnd; if actual_increase > 0 { self.cwnd_tx.fetch_add(actual_increase, Ordering::SeqCst); } debug!( "Congestion Control: Slow Start cwnd_tx {} -> {} (ssthresh={}, increase={})", cwnd, new_cwnd, ssthresh, actual_increase ); ``` -------------------------------- ### Create Application Offer Source: https://docs.rs/rustrtc/0.3.51/src/rustrtc/peer_connection.rs.html Adds an application transceiver and creates an SDP offer, verifying SCTP port and protocol details. ```rust #[tokio::test] async fn offer_includes_application_capabilities() { let pc = PeerConnection::new(RtcConfiguration::default()); pc.add_transceiver(MediaKind::Application, TransceiverDirection::SendRecv); let offer = pc.create_offer().await.unwrap(); let section = &offer.media_sections[0]; assert_eq!(section.kind, MediaKind::Application); assert_eq!(section.protocol, "UDP/DTLS/SCTP"); assert_eq!(section.formats, vec![SCTP_FORMAT.to_string()]); let attrs = §ion.attributes; let expected_port = SCTP_PORT.to_string(); assert!(attrs.iter().any(|attr| { attr.key == "sctp-port" && attr .value .as_deref() .map(|v| v == expected_port) .unwrap_or(false) })); } ``` -------------------------------- ### Create a new RtpSenderBuilder Source: https://docs.rs/rustrtc/0.3.51/rustrtc/peer_connection/struct.RtpSenderBuilder.html Initializes a new RtpSenderBuilder with a media stream track and an SSRC. This is the starting point for configuring an RtpSender. ```rust pub fn new(track: Arc, ssrc: u32) -> Self ``` -------------------------------- ### Set SSRC Start Value Source: https://docs.rs/rustrtc/0.3.51/rustrtc/config/struct.RtcConfigurationBuilder.html Sets the starting value for SSRC (Synchronization Source) identifiers. SSRCs are used to uniquely identify media streams. ```rust pub fn ssrc_start(self, start: u32) -> Self ``` -------------------------------- ### Start ICE Transport Source: https://docs.rs/rustrtc/0.3.51/src/rustrtc/transports/ice/mod.rs.html Starts the ICE transport process by initiating candidate gathering and setting remote parameters. This is the primary method to begin the ICE connection establishment. ```rust pub fn start(&self, remote: IceParameters) -> Result<()> { self.start_gathering()?; // Note: The original code snippet was truncated here. // Typically, setting remote parameters would follow or be part of this call. // For example: self.set_remote_parameters(remote); Ok(()) } ``` -------------------------------- ### Create ChannelMediaSource and SampleQueueSender Source: https://docs.rs/rustrtc/0.3.51/src/rustrtc/media/pipeline.rs.html Creates a new `ChannelMediaSource` and its corresponding `SampleQueueSender` for a given media kind and capacity. This is used to receive media samples from a channel. ```rust pub fn channel(kind: MediaKind, capacity: usize) -> (SampleQueueSender, Self) { let (sender, receiver) = sample_queue_channel(capacity); let id = next_channel_source_id(); (sender, Self::new(id, kind, receiver)) } ``` -------------------------------- ### Test ssthresh Auto-Raise Enables Slow Start Source: https://docs.rs/rustrtc/0.3.51/src/rustrtc/transports/sctp.rs.html Verifies that the ssthresh auto-raise mechanism correctly sets a value above the current congestion window (cwnd) to re-enter slow start. ```rust let cwnd = 8000usize; // cwnd approaching ssthresh after recovery let ssthresh = SSTHRESH_MIN; // 4800 // New fixed logic: new_ssthresh = max(cwnd * 2, CWND_INITIAL * 2) let new_new_ssthresh = (cwnd * 2).max(CWND_INITIAL * 2); assert!( new_new_ssthresh > cwnd, "FIX: new ssthresh {} > cwnd {}, enabling slow start (exponential growth)", new_new_ssthresh, cwnd ); // Verify the condition: cwnd <= ssthresh means slow start assert!( cwnd <= new_new_ssthresh, "After fix, cwnd {} <= ssthresh {}, so slow start will be used", cwnd, new_new_ssthresh ); // Also verify the trigger condition works assert!( cwnd >= ssthresh * 4 / 5, "Trigger condition: cwnd {} >= ssthresh*4/5 {} should fire", cwnd, ssthresh * 4 / 5 ); ``` -------------------------------- ### Create Video Offer Source: https://docs.rs/rustrtc/0.3.51/src/rustrtc/peer_connection.rs.html Adds a video transceiver and creates an SDP offer, verifying video-specific capabilities in the offer. ```rust #[tokio::test] async fn offer_includes_video_capabilities() { let pc = PeerConnection::new(RtcConfiguration::default()); pc.add_transceiver(MediaKind::Video, TransceiverDirection::SendRecv); let offer = pc.create_offer().await.unwrap(); let section = &offer.media_sections[0]; assert_eq!(section.kind, MediaKind::Video); assert_eq!(section.formats, vec![VIDEO_PAYLOAD_TYPE.to_string()]); let attrs = §ion.attributes; assert!(attrs.iter().any(|attr| attr.key == "rtcp-fb")); assert!(attrs.iter().any(|attr| { attr.key == "rtpmap" && attr .value .as_deref() .map(|v| v.contains("VP8")) .unwrap_or(false) })); } ``` -------------------------------- ### Create a Sample Media Track Source: https://docs.rs/rustrtc/0.3.51/rustrtc/media/track/fn.sample_track.html Use this function to create a new sample media track. It requires the media kind and a capacity for the track. ```rust pub fn sample_track( kind: MediaKind, capacity: usize, ) -> (SampleStreamSource, Arc, Receiver) ``` -------------------------------- ### Start T1 Timer in SCTP Source: https://docs.rs/rustrtc/0.3.51/src/rustrtc/transports/sctp.rs.html Initializes and starts the T1 retransmission timer for SCTP. It stores the chunk to be sent, resets failure count, and sets the initial sent time. ```rust fn t1_start(&self, chunk_type: u8, chunk_body: Bytes, vtag: u32) { *self.t1_chunk.lock() = Some((chunk_type, chunk_body, vtag)); self.t1_failures.store(0, Ordering::SeqCst); *self.t1_sent_time.lock() = Some(Instant::now()); self.t1_active.store(true, Ordering::SeqCst); } ``` -------------------------------- ### Start Relay Stream Track Processing Source: https://docs.rs/rustrtc/0.3.51/src/rustrtc/media/track.rs.html Ensures the relay stream track processing is started. This is typically called once to set up the tokio task for handling media samples and feedback events. ```rust fn ensure_started(self: &Arc) { if self .started .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst) .is_ok() { let this = Arc::clone(self); let mut rx_guard = self.feedback_rx.lock(); let mut feedback_rx = rx_guard.take().unwrap(); tokio::spawn(async move { loop { tokio::select! { res = this.track.recv() => { match res { Ok(sample) => { let _ = this.sender.send(RelayEvent::Sample(sample)); } Err(MediaError::Lagged) => { debug!(target: "rustrtc::media", track = %this.base_id, "source track lagged; dropping sample"); continue; } Err(MediaError::KindMismatch { .. }) => { warn!(target: "rustrtc::media", track = %this.base_id, "source track returned mismatched sample kind"); this.ended.store(true, Ordering::SeqCst); let _ = this.sender.send(RelayEvent::End); break; } Err(MediaError::WouldBlock) => { // This shouldn't happen in recv path, but handle it gracefully debug!(target: "rustrtc::media", track = %this.base_id, "unexpected WouldBlock in recv"); continue; } Err(MediaError::Closed) | Err(MediaError::EndOfStream) => { this.ended.store(true, Ordering::SeqCst); let _ = this.sender.send(RelayEvent::End); break; } } } Some(event) = feedback_rx.recv() => { match event { FeedbackEvent::RequestKeyFrame => { if let Err(e) = this.track.request_key_frame().await { debug!(target: "rustrtc::media", track = %this.base_id, "failed to forward key frame request: {}", e); } } } } } } }); } } } ``` -------------------------------- ### Create a new ICE Server Source: https://docs.rs/rustrtc/0.3.51/src/rustrtc/config.rs.html Constructor for IceServer, initializing with a list of URLs. Other fields default to None or default values. ```rust pub fn new>>(urls: T) -> Self { Self { urls: urls.into(), username: None, credential: None, credential_type: IceCredentialType::default(), } } ``` -------------------------------- ### Congestion Window and Slow Start Threshold Update Source: https://docs.rs/rustrtc/0.3.51/src/rustrtc/transports/sctp.rs.html Updates the congestion window (cwnd) and slow start threshold (ssthresh) after an RTO event. The new ssthresh is half the current cwnd, with a minimum of 4 * MAX_SCTP_PACKET_SIZE. The cwnd is reset to CWND_MIN_AFTER_RTO. ```rust let cwnd = self.cwnd_tx.load(Ordering::SeqCst); let new_ssthresh = (cwnd / 2).max(4 * MAX_SCTP_PACKET_SIZE); self.ssthresh.store(new_ssthresh, Ordering::SeqCst); self.cwnd_tx.store(CWND_MIN_AFTER_RTO, Ordering::SeqCst); ``` -------------------------------- ### Try Send Media Sample Source: https://docs.rs/rustrtc/0.3.51/rustrtc/media/pipeline/struct.SampleQueueSender.html Attempts to send a MediaSample without blocking. Returns the sample if it could not be sent. ```rust pub fn try_send(&self, sample: MediaSample) -> Result<(), MediaSample> ``` -------------------------------- ### Get RtpReceiver Source: https://docs.rs/rustrtc/0.3.51/rustrtc/peer_connection/struct.RtpTransceiver.html Returns the RtpReceiver associated with this transceiver, if any. ```rust pub fn receiver(&self) -> Option> ``` -------------------------------- ### RtpSenderBuilder Initialization and Configuration Source: https://docs.rs/rustrtc/0.3.51/rustrtc/peer_connection/struct.RtpSenderBuilder.html This section covers the creation and configuration of an RtpSenderBuilder. It includes methods for setting the track, SSRC, stream ID, codec parameters, NACK buffer size, bitrate controller, and interceptors. ```APIDOC ## RtpSenderBuilder ### Description The `RtpSenderBuilder` is used to construct an `RtpSender` with various configurations. ### Methods #### `new(track: Arc, ssrc: u32) -> Self` Creates a new `RtpSenderBuilder` with the specified media track and SSRC. #### `stream_id(self, id: String) -> Self` Sets the stream ID for the RtpSender. #### `params(self, params: RtpCodecParameters) -> Self` Sets the RtpCodecParameters for the RtpSender. #### `nack(self, buffer_size: usize) -> Self` Configures the NACK (Negative Acknowledgement) buffer size for the RtpSender. #### `bitrate_controller(self) -> Self` Enables the bitrate controller for the RtpSender. #### `interceptor(self, interceptor: Arc) -> Self` Adds a custom RtpSenderInterceptor to the RtpSender. #### `build(self) -> Arc` Builds and returns the configured `RtpSender`. ### Request Example ```rust use std::sync::Arc; use rustrtc::{peer_connection::rtp_sender::RtpSenderBuilder, track::MediaStreamTrack, codec::RtpCodecParameters}; // Assuming you have a MediaStreamTrack and RtpCodecParameters // let track: Arc = ...; // let ssrc: u32 = 12345; // let codec_params: RtpCodecParameters = ...; // let sender = RtpSenderBuilder::new(track, ssrc) // .stream_id("stream-1".to_string()) // .params(codec_params) // .nack(1024) // .build(); ``` ### Response #### Success Response (200) - **sender** (Arc) - The constructed RtpSender instance. ``` -------------------------------- ### Get RtpSender Source: https://docs.rs/rustrtc/0.3.51/rustrtc/peer_connection/struct.RtpTransceiver.html Returns the RtpSender associated with this transceiver, if any. ```rust pub fn sender(&self) -> Option> ``` -------------------------------- ### Setup Direct RTP for Offer Side Source: https://docs.rs/rustrtc/0.3.51/rustrtc/transports/ice/struct.IceTransport.html Asynchronously sets up a direct UDP socket for RTP mode on the offer side. Binds a socket and registers the local candidate, but does not set the selected pair or transition to Connected. ```rust pub async fn setup_direct_rtp_offer(&self) -> Result ``` -------------------------------- ### Start SRTP Session Source: https://docs.rs/rustrtc/0.3.51/rustrtc/transports/rtp/struct.RtpTransport.html Initializes the SRTP session for the RtpTransport. ```rust pub fn start_srtp(&self, srtp_session: SrtpSession) ``` -------------------------------- ### recv Method Source: https://docs.rs/rustrtc/0.3.51/rustrtc/media/pipeline/struct.SampleQueueReceiver.html Asynchronously receives the next available media sample. ```APIDOC ## pub async fn recv(&mut self) -> Option ### Description This method asynchronously waits for and retrieves the next `MediaSample` from the queue. It returns `Some(MediaSample)` if a sample is available, and `None` if the receiver has been closed or no more samples will be sent. ``` -------------------------------- ### Create a new MediaSection Source: https://docs.rs/rustrtc/0.3.51/src/rustrtc/sdp.rs.html Initializes a new MediaSection with default values for port, protocol, and direction. Requires a MediaKind and a media identifier. ```rust impl MediaSection { pub fn new(kind: MediaKind, mid: impl Into) -> Self { Self { kind, mid: mid.into(), port: 9, protocol: "UDP/TLS/RTP/SAVPF".into(), formats: Vec::new(), direction: Direction::default(), attributes: Vec::new(), connection: None, } } // ... ``` -------------------------------- ### Get Disconnect Reason Source: https://docs.rs/rustrtc/0.3.51/src/rustrtc/peer_connection.rs.html Retrieves the current disconnect reason, if any. ```APIDOC ## GET /disconnect_reason ### Description Returns the current disconnect reason, if any. This can be used to check the status without subscribing to updates. ### Method GET ### Endpoint /disconnect_reason ### Parameters None ### Response #### Success Response (200) - **Option** - The current disconnect reason, or `None` if not disconnected. #### Response Example ```rust let reason = peer_connection.disconnect_reason(); match reason { Some(r) => println!("Disconnected with reason: {:?}", r), None => println!("Connection is active."), } ``` ``` -------------------------------- ### Get IceTransport State Source: https://docs.rs/rustrtc/0.3.51/rustrtc/transports/ice/struct.IceTransport.html Retrieves the current state of the IceTransport. ```rust pub fn state(&self) -> IceTransportState ``` -------------------------------- ### RTP Mode Offerer Connects After Answer Source: https://docs.rs/rustrtc/0.3.51/src/rustrtc/peer_connection.rs.html Sets up a PeerConnection in RTP mode, adds an audio transceiver, and prepares codec parameters, likely as a precursor to creating an offer and connecting. ```rust use crate::TransportMode; let mut config = RtcConfiguration::default(); config.transport_mode = TransportMode::Rtp; let pc = PeerConnection::new(config); let transceiver = pc.add_transceiver(MediaKind::Audio, TransceiverDirection::SendRecv); let (_, track, _) = sample_track(crate::media::frame::MediaKind::Audio, 48000); let params = RtpCodecParameters { payload_type: 8, clock_rate: 8000, channels: 1, }; ``` -------------------------------- ### Create ChannelMediaSink and SampleQueueReceiver Source: https://docs.rs/rustrtc/0.3.51/src/rustrtc/media/pipeline.rs.html Creates a new `ChannelMediaSink` and its corresponding `SampleQueueReceiver` for a given media kind and capacity. This is used to send media samples to a channel. ```rust pub fn channel(kind: MediaKind, capacity: usize) -> (Self, SampleQueueReceiver) { let (sender, receiver) = sample_queue_channel(capacity); (Self::new(kind, sender), receiver) } ``` -------------------------------- ### Get Direction Source: https://docs.rs/rustrtc/0.3.51/rustrtc/srtp/struct.SrtpContext.html Returns the SrtpDirection (send or receive) of the SrtpContext. ```rust pub fn direction(&self) -> SrtpDirection ``` -------------------------------- ### Get Disconnect Reason Source: https://docs.rs/rustrtc/0.3.51/rustrtc/peer_connection/struct.PeerConnection.html Returns the current disconnect reason, if any. ```rust pub fn disconnect_reason(&self) -> Option ``` -------------------------------- ### Create Media Section for WebRTC Source: https://docs.rs/rustrtc/0.3.51/src/rustrtc/peer_connection.rs.html Initializes a media section for WebRTC, setting the protocol, connection details, and ICE attributes. ```rust let mut section = MediaSection::new(transceiver.kind(), mid); section.direction = direction.into(); if mode == TransportMode::Rtp { section.protocol = "RTP/AVP".to_string(); } if mode == TransportMode::WebRtc { section.connection = Some("IN IP4 0.0.0.0".to_string()); section .attributes .push(Attribute::new("ice-ufrag", Some(ice_username.clone()))); section .attributes .push(Attribute::new("ice-pwd", Some(ice_password.clone()))); section .attributes .push(Attribute::new("ice-options", Some("trickle".into()))); for candidate in &candidate_lines { section .attributes .push(Attribute::new("candidate", Some(candidate.clone()))); } ``` -------------------------------- ### Get Transceivers Source: https://docs.rs/rustrtc/0.3.51/rustrtc/peer_connection/struct.PeerConnection.html Retrieves a list of all active RtpTransceivers in the PeerConnection. ```rust pub fn get_transceivers(&self) -> Vec> ``` -------------------------------- ### Handle Empty Capabilities for Wrong Media Kind Source: https://docs.rs/rustrtc/0.3.51/src/rustrtc/sdp.rs.html Tests that calling `to_video_capabilities` on an audio-only SDP section correctly returns an empty list, while `to_audio_capabilities` functions as expected. ```rust let sdp = "v=0\r\n\ o=- 1 1 IN IP4 127.0.0.1\r\n\ s=-\r\n\ t=0 0\r\n\ m=audio 9 UDP/TLS/RTP/SAVPF 111\r\n\ a=mid:0\r\na=rtpmap:111 opus/48000/2\r\n"; let desc = SessionDescription::parse(SdpType::Offer, sdp).unwrap(); let audio_section = desc.first_audio_section().unwrap(); // Video capabilities should be empty for audio section let video_caps = audio_section.to_video_capabilities(); assert!(video_caps.is_empty()); // But audio capabilities should work let audio_caps = audio_section.to_audio_capabilities(); assert_eq!(audio_caps.len(), 1); ``` -------------------------------- ### Create New IceServer Source: https://docs.rs/rustrtc/0.3.51/rustrtc/config/struct.IceServer.html Constructs a new IceServer instance with the provided URLs. This is the primary way to initialize an IceServer. ```rust pub fn new>>(urls: T) -> Self> ``` -------------------------------- ### Get IceTransport Source: https://docs.rs/rustrtc/0.3.51/rustrtc/peer_connection/struct.PeerConnection.html Retrieves the underlying IceTransport associated with the PeerConnection. ```rust pub fn ice_transport(&self) -> IceTransport ``` -------------------------------- ### Create Offer API Source: https://docs.rs/rustrtc/0.3.51/src/rustrtc/peer_connection.rs.html Initiates the creation of an SDP offer for establishing a WebRTC connection. This method checks the current signaling state before proceeding. ```APIDOC ## POST /createOffer ### Description Creates an SDP offer to initiate a WebRTC connection. The operation is conditional on the RtcPeerConnection's signaling state being 'Stable'. ### Method POST ### Endpoint /createOffer ### Parameters This endpoint does not accept any parameters. ### Response #### Success Response (200) - **offer** (SessionDescription) - The generated SDP offer. #### Error Response (400) - **error** (string) - Indicates that the offer cannot be created because the signaling state is not stable. #### Response Example ```json { "offer": { "type": "offer", "sdp": "v=0\r\no=- 1234567890 1234567890 IN IP4 0.0.0.0\r\ns= \r\nt=0 0\r\n... (SDP content) ..." } } ``` ``` -------------------------------- ### Get RtpTransceiver ID Source: https://docs.rs/rustrtc/0.3.51/rustrtc/peer_connection/struct.RtpTransceiver.html Retrieves the unique identifier for the RtpTransceiver. ```rust pub fn id(&self) -> u64 ``` -------------------------------- ### Get Interceptors Source: https://docs.rs/rustrtc/0.3.51/rustrtc/peer_connection/struct.RtpSender.html Returns a slice of the RtpSenderInterceptors configured for this sender. ```rust pub fn interceptors(&self) -> &[Arc] ``` -------------------------------- ### RtpReceiverBuilder::new Source: https://docs.rs/rustrtc/0.3.51/src/rustrtc/peer_connection.rs.html Initializes a new RtpReceiverBuilder with the specified media kind and SSRC. ```APIDOC ## RtpReceiverBuilder::new ### Description Creates a new instance of `RtpReceiverBuilder`. ### Method Associated function (constructor) ### Parameters - **kind** (MediaKind) - Required - The media kind (Audio or Video) for the receiver. - **ssrc** (u32) - Required - The SSRC (Synchronization Source) identifier for the RTP stream. ``` -------------------------------- ### Construct Server Hello Extensions Source: https://docs.rs/rustrtc/0.3.51/src/rustrtc/transports/dtls/mod.rs.html Constructs the extensions for a Server Hello message, including Supported Point Formats, Renegotiation Info, and Extended Master Secret. ```rust let mut extensions = Vec::new(); // Supported Point Formats (uncompressed) extensions.extend_from_slice(&[0x00, 0x0b]); // Type extensions.extend_from_slice(&[0x00, 0x02]); // Length extensions.extend_from_slice(&[0x01]); // List Length extensions.extend_from_slice(&[0x00]); // uncompressed // Renegotiation Info (empty) extensions.extend_from_slice(&[0xff, 0x01]); // Type extensions.extend_from_slice(&[0x00, 0x01]); // Length extensions.extend_from_slice(&[0x00]); // Body (len 0) // Extended Master Secret if ctx.ems_negotiated { extensions.extend_from_slice(&[0x00, 0x17]); // Type 23 extensions.extend_from_slice(&[0x00, 0x00]); // Length 0 } ``` -------------------------------- ### Get Codec Parameters Source: https://docs.rs/rustrtc/0.3.51/rustrtc/peer_connection/struct.RtpSender.html Retrieves the RtpCodecParameters used by this sender. ```rust pub fn params(&self) -> RtpCodecParameters ``` -------------------------------- ### Get SpscRing Capacity Source: https://docs.rs/rustrtc/0.3.51/rustrtc/media/spsc/struct.SpscRing.html Returns the total capacity of the SpscRing. ```rust pub fn capacity(&self) -> usize ``` -------------------------------- ### Create Offer in Rust Source: https://docs.rs/rustrtc/0.3.51/src/rustrtc/peer_connection.rs.html Initiates the creation of an SDP offer to establish a WebRTC connection. This function checks the current signaling state to ensure it's stable before proceeding. ```rust pub async fn create_offer(&self) -> RtcResult { let state = &self.inner.signaling_state; if *state.borrow() != SignalingState::Stable { ``` -------------------------------- ### Struct Timing Source: https://docs.rs/rustrtc/0.3.51/rustrtc/sdp/struct.Timing.html Represents timing information with start and stop timestamps. ```APIDOC ## Struct Timing ### Description Represents timing information with start and stop timestamps. ### Fields - **start** (u64) - The start timestamp. - **stop** (u64) - The stop timestamp. ### Methods #### pub fn parse(value: &str) -> SdpResult Parses a string representation into a `Timing` struct. ### Implementations - **Clone**: Allows creating copies of `Timing` instances. - **Debug**: Enables debugging output for `Timing` instances. - **Default**: Provides a default value for `Timing`. - **Deserialize**: Allows deserializing `Timing` from various formats (e.g., JSON, using Serde). - **PartialEq**: Enables comparison of `Timing` instances for equality. - **Serialize**: Allows serializing `Timing` into various formats (e.g., JSON, using Serde). - **Eq**: Indicates that `Timing` implements total equality. - **StructuralPartialEq**: Enables structural comparison of `Timing` instances. ``` -------------------------------- ### Initialize TURN Client Source: https://docs.rs/rustrtc/0.3.51/src/rustrtc/transports/ice/turn.rs.html Connects to a TURN server via UDP or TCP. Binds to a random local port for UDP. Initializes authentication and channel state. ```rust impl TurnClient { pub(crate) async fn connect(uri: &IceServerUri, disable_ipv6: bool) -> Result { let addr = uri.resolve(disable_ipv6).await?; let transport = match uri.transport { IceTransportProtocol::Udp => { let socket = Arc::new(UdpSocket::bind("0.0.0.0:0").await?); TurnTransport::Udp { socket, server: addr, } } IceTransportProtocol::Tcp => { let stream = TcpStream::connect(addr).await?; let (read, write) = stream.into_split(); TurnTransport::Tcp { read: Arc::new(Mutex::new(read)), write: Arc::new(Mutex::new(write)), } } }; Ok(Self { transport, auth: Mutex::new(None), channels: Mutex::new(HashMap::new()), channel_map: Mutex::new(HashMap::new()), next_channel: Mutex::new(0x4000), }) } } ``` -------------------------------- ### Implement SampleQueueSender send method Source: https://docs.rs/rustrtc/0.3.51/src/rustrtc/media/pipeline.rs.html The `send` method for `SampleQueueSender` attempts to push a `MediaSample` into the queue. If the queue is full, it tries to make space by popping an old sample, then pushes the new one. It notifies receivers upon successful send. ```rust impl SampleQueueSender { pub async fn send(&self, sample: MediaSample) -> Result<(), ()> { if self.closed.load(std::sync::atomic::Ordering::Acquire) { return Err(()); } let sample = match self.queue.push(sample) { Ok(()) => { self.notify.notify_one(); return Ok(()); } Err(sample) => sample, }; let _guard = match self.pop_lock.try_lock() { Some(g) => g, None => return Ok(()), }; let _ = self.queue.pop(); if self.queue.push(sample).is_ok() { self.notify.notify_one(); } Ok(()) } pub fn try_send(&self, sample: MediaSample) -> Result<(), MediaSample> { if self.closed.load(std::sync::atomic::Ordering::Acquire) { return Err(sample); } match self.queue.push(sample) { Ok(()) => { self.notify.notify_one(); Ok(()) } Err(sample) => Err(sample), } } } ``` -------------------------------- ### Get Remote Description Source: https://docs.rs/rustrtc/0.3.51/src/rustrtc/peer_connection.rs.html Retrieves the current remote session description. ```APIDOC ## GET /remote_description ### Description Returns the current remote session description. This contains the session details provided by the remote peer. ### Method GET ### Endpoint /remote_description ### Parameters None ### Response #### Success Response (200) - **Option** - The remote session description, or `None` if not yet set. #### Response Example ```rust let remote_desc = peer_connection.remote_description(); if let Some(desc) = remote_desc { println!("Remote Description: {:?}", desc); } ``` ``` -------------------------------- ### H.264 Offer SDP with fmtp Attributes Source: https://docs.rs/rustrtc/0.3.51/src/rustrtc/peer_connection.rs.html Creates an H.264 offer and asserts that the generated SDP includes 'fmtp' attributes for 'packetization-mode' and 'profile-level-id'. This is crucial for proper H.264 stream negotiation. ```rust use crate::TransportMode; use crate::config::{MediaCapabilities, VideoCapability}; let mut config = RtcConfiguration::default(); config.transport_mode = TransportMode::Rtp; config.media_capabilities = Some(MediaCapabilities { audio: vec![], video: vec![VideoCapability::h264()], application: None, }); let pc = PeerConnection::new(config); pc.add_transceiver(MediaKind::Video, TransceiverDirection::SendRecv); let offer = pc.create_offer().await.unwrap(); let section = &offer.media_sections[0]; assert_eq!(section.kind, MediaKind::Video); let fmtp = section .attributes .iter() .find(|a| a.key == "fmtp") .expect("H264 offer must contain a=fmtp"); assert!( fmtp.value .as_deref() .unwrap_or("") .contains("packetization-mode"), "a=fmtp must contain packetization-mode, got: {:?}", fmtp.value ); assert!( fmtp.value .as_deref() .unwrap_or("") .contains("profile-level-id"), "a=fmtp must contain profile-level-id, got: {:?}", fmtp.value ); ``` -------------------------------- ### Get Local Description Source: https://docs.rs/rustrtc/0.3.51/src/rustrtc/peer_connection.rs.html Retrieves the current local session description. ```APIDOC ## GET /local_description ### Description Returns the current local session description. This includes details about the media capabilities and configuration set by the local peer. ### Method GET ### Endpoint /local_description ### Parameters None ### Response #### Success Response (200) - **Option** - The local session description, or `None` if not yet set. #### Response Example ```rust let local_desc = peer_connection.local_description(); if let Some(desc) = local_desc { println!("Local Description: {:?}", desc); } ``` ```