Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions webrtc/src/api/media_engine/media_engine_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -801,3 +801,77 @@ a=rtpmap:111 opus/48000/2

Ok(())
}

#[tokio::test]
async fn test_multi_codec_negotiation() -> Result<()> {
const OFFER_SDP: &str = "v=0
o=- 781500112831855234 6 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE 0 1 2 3
a=extmap-allow-mixed
a=msid-semantic: WMS be0216be-f3d8-40ca-a624-379edf70f1c9
m=application 53555 UDP/DTLS/SCTP webrtc-datachannel
a=mid:0
a=sctp-port:5000
a=max-message-size:262144
m=video 9 UDP/TLS/RTP/SAVPF 98
a=mid:1
a=sendonly
a=msid:be0216be-f3d8-40ca-a624-379edf70f1c9 3d032b3b-ffe5-48ec-b783-21375668d1c3
a=rtcp-mux
a=rtcp-rsize
a=rtpmap:98 VP9/90000
a=rtcp-fb:98 goog-remb
a=rtcp-fb:98 transport-cc
a=rtcp-fb:98 ccm fir
a=rtcp-fb:98 nack
a=rtcp-fb:98 nack pli
a=fmtp:98 profile-id=0
a=rid:q send
a=rid:h send
a=simulcast:send q;h
m=video 9 UDP/TLS/RTP/SAVPF 96
a=mid:2
a=sendonly
a=msid:6ff05509-be96-4ef1-a74f-425e14720983 16d5d7fe-d076-4718-9ca9-ec62b4543727
a=rtcp-mux
a=rtcp-rsize
a=rtpmap:96 VP8/90000
a=rtcp-fb:96 goog-remb
a=rtcp-fb:96 transport-cc
a=rtcp-fb:96 ccm fir
a=rtcp-fb:96 nack
a=rtcp-fb:96 nack pli
a=ssrc:4281768245 cname:JDM9GNMEg+9To6K7
a=ssrc:4281768245 msid:6ff05509-be96-4ef1-a74f-425e14720983 16d5d7fe-d076-4718-9ca9-ec62b4543727
";
let must_parse = |raw: &str| -> Result<SessionDescription> {
let mut reader = Cursor::new(raw.as_bytes());
Ok(SessionDescription::unmarshal(&mut reader)?)
};

// "Multi codec negotiation disabled"
{
let mut m = MediaEngine::default();
m.register_default_codecs()?;
m.update_from_remote_description(&must_parse(OFFER_SDP)?)
.await?;
let negotiated_video_codecs = m.negotiated_video_codecs.lock();
assert_eq!(negotiated_video_codecs.len(), 1)
}

// "Multi codec negotiation enabled"
{
let mut m = MediaEngine::default();
m.set_multi_codec_negotiation(true);
assert!(m.multi_codec_negotiation());
m.register_default_codecs()?;
m.update_from_remote_description(&must_parse(OFFER_SDP)?)
.await?;
let negotiated_video_codecs = m.negotiated_video_codecs.lock();
assert_eq!(negotiated_video_codecs.len(), 2)
}

Ok(())
}
18 changes: 16 additions & 2 deletions webrtc/src/api/media_engine/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ pub struct MediaEngine {
// If we have attempted to negotiate a codec type yet.
pub(crate) negotiated_video: AtomicBool,
pub(crate) negotiated_audio: AtomicBool,
pub(crate) negotiate_multi_codecs: AtomicBool,
Copy link
Preview

Copilot AI Sep 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new field negotiate_multi_codecs is not initialized in the default constructor. This could lead to undefined behavior. Consider adding initialization in the Default implementation or constructor.

Copilot uses AI. Check for mistakes.


pub(crate) video_codecs: Vec<RTCRtpCodecParameters>,
pub(crate) audio_codecs: Vec<RTCRtpCodecParameters>,
Expand Down Expand Up @@ -461,6 +462,17 @@ impl MediaEngine {
}
}

/// set_multi_codec_negotiation enables or disables the negotiation of multiple codecs.
pub(crate) fn set_multi_codec_negotiation(&self, negotiate_multi_codecs: bool) {
self.negotiate_multi_codecs
.store(negotiate_multi_codecs, Ordering::SeqCst);
}

/// multi_codec_negotiation returns the current state of the negotiation of multiple codecs.
pub(crate) fn multi_codec_negotiation(&self) -> bool {
self.negotiate_multi_codecs.load(Ordering::SeqCst)
}

pub(crate) async fn get_codec_by_payload(
&self,
payload_type: PayloadType,
Expand Down Expand Up @@ -653,12 +665,14 @@ impl MediaEngine {
desc: &SessionDescription,
) -> Result<()> {
for media in &desc.media_descriptions {
let typ = if !self.negotiated_audio.load(Ordering::SeqCst)
let typ = if (!self.negotiated_audio.load(Ordering::SeqCst)
|| self.negotiate_multi_codecs.load(Ordering::SeqCst))
&& media.media_name.media.to_lowercase() == "audio"
{
self.negotiated_audio.store(true, Ordering::SeqCst);
RTPCodecType::Audio
} else if !self.negotiated_video.load(Ordering::SeqCst)
} else if (!self.negotiated_video.load(Ordering::SeqCst)
|| self.negotiate_multi_codecs.load(Ordering::SeqCst))
Comment on lines +668 to +675
Copy link
Preview

Copilot AI Sep 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The parentheses around the first condition are unnecessary and reduce readability. The logical precedence of ! and || operators makes these parentheses redundant.

Copilot uses AI. Check for mistakes.

Comment on lines +674 to +675
Copy link
Preview

Copilot AI Sep 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The parentheses around the first condition are unnecessary and reduce readability. The logical precedence of ! and || operators makes these parentheses redundant.

Copilot uses AI. Check for mistakes.

&& media.media_name.media.to_lowercase() == "video"
{
self.negotiated_video.store(true, Ordering::SeqCst);
Expand Down
11 changes: 11 additions & 0 deletions webrtc/src/api/setting_engine/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ pub struct SettingEngine {
//iceProxyDialer :proxy.Dialer,?
pub(crate) udp_network: UDPNetwork,
pub(crate) disable_media_engine_copy: bool,
pub(crate) disable_media_engine_multiple_codecs: bool,
pub(crate) srtp_protection_profiles: Vec<SrtpProtectionProfile>,
pub(crate) receive_mtu: usize,
pub(crate) mid_generator: Option<Arc<dyn Fn(isize) -> String + Send + Sync>>,
Expand Down Expand Up @@ -342,6 +343,16 @@ impl SettingEngine {
self.disable_media_engine_copy = is_disabled;
}

/// disable_media_engine_multiple_codecs disables the MediaEngine negotiating different codecs.
/// With the default value multiple media sections in the SDP can each negotiate different
/// codecs. This is the new default behvior, because it makes Pion more spec compliant.
/// The value of this setting will get copied to every copy of the MediaEngine generated
/// for new PeerConnections (assuming DisableMediaEngineCopy is set to false).
/// Note: this setting is targeted to be removed in release 4.2.0 (or later).
pub fn disable_media_engine_multiple_codecs(&mut self, is_disabled: bool) {
self.disable_media_engine_multiple_codecs = is_disabled;
}

/// set_receive_mtu sets the size of read buffer that copies incoming packets. This is optional.
/// Leave this 0 for the default receive_mtu
pub fn set_receive_mtu(&mut self, receive_mtu: usize) {
Expand Down
12 changes: 12 additions & 0 deletions webrtc/src/api/setting_engine/setting_engine_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,3 +269,15 @@ async fn test_setting_engine_set_disable_media_engine_copy() -> Result<()> {

Ok(())
}

#[test]
fn test_setting_engine_media_engine_and_mtu_flags() -> Result<()> {
let mut s = SettingEngine::default();

s.disable_media_engine_multiple_codecs(true);
assert!(s.disable_media_engine_multiple_codecs);

s.set_receive_mtu(1337);
assert_eq!(1337, s.receive_mtu);
Ok(())
}
10 changes: 7 additions & 3 deletions webrtc/src/peer_connection/peer_connection_internal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,10 +121,14 @@ impl PeerConnectionInternal {
peer_connection_state: Arc::new(AtomicU8::new(RTCPeerConnectionState::New as u8)),

setting_engine: Arc::clone(&api.setting_engine),
media_engine: if !api.setting_engine.disable_media_engine_copy {
Arc::new(api.media_engine.clone_to())
} else {
media_engine: if api.setting_engine.disable_media_engine_copy {
Arc::clone(&api.media_engine)
} else {
let cloned_media_engine = Arc::new(api.media_engine.clone_to());
cloned_media_engine.set_multi_codec_negotiation(
!api.setting_engine.disable_media_engine_multiple_codecs,
);
cloned_media_engine
},
interceptor,
stats_interceptor,
Expand Down
Loading