diff --git a/call_sim/src/main.rs b/call_sim/src/main.rs index 804d3fcb..6c7d34b2 100644 --- a/call_sim/src/main.rs +++ b/call_sim/src/main.rs @@ -993,6 +993,99 @@ async fn run_plc_tests(test: &mut Test) -> Result<()> { Ok(()) } +async fn run_dred_tests(test: &mut Test) -> Result<()> { + let configs = [ + (60, true, 0, Some(0)), // Before DRED with FEC and Opus PLC + (60, false, 6, Some(5)), // DRED 60ms + (60, false, 12, Some(5)), // DRED 120ms + (60, false, 25, Some(5)), // DRED 250ms + (60, false, 50, Some(5)), // DRED 500ms + (60, false, 100, Some(5)), // DRED 1s + ]; + + let losses = [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50]; + + let test_cases: Vec<_> = configs + .iter() + .flat_map(|&(initial_packet_size_ms, enable_fec, dred_duration, decoder_complexity)| { + losses.iter().map(move |&loss| TestCaseConfig { + test_case_name: format!( + "ptime_{initial_packet_size_ms}-fec_{enable_fec}-dred_duration_{dred_duration}-plc_{}-loss_{loss}", + decoder_complexity.map_or("None".to_string(), |c| c.to_string()) + ), + length_seconds: 30, + client_a_config: CallConfig { + audio: AudioConfig { + input_name: "normal_phrasing".to_string(), + generate_spectrogram: false, + visqol_speech_analysis: false, + visqol_audio_analysis: false, + pesq_speech_analysis: false, + plc_speech_analysis: false, + complexity: 9, + initial_packet_size_ms, + enable_fec, + dred_duration, + decoder_complexity, + // Force DRED to be encoded with the expected loss rate. + min_packet_loss_percent: if dred_duration > 0 { loss } else { 0 }, + // Only used for Deep PLC (decoder complexity 5) or DRED tests. + dnn_weights_path: "/data/deep_plc-dred-weights.bin".to_string(), + ..Default::default() + }, + profile: DeterministicLoss(loss), + ..Default::default() + }, + client_b_config: CallConfig { + audio: AudioConfig { + input_name: "normal_phrasing".to_string(), + visqol_speech_analysis: true, + visqol_audio_analysis: true, + pesq_speech_analysis: true, + plc_speech_analysis: true, + complexity: 9, + initial_packet_size_ms, + enable_fec, + dred_duration, + decoder_complexity, + // Force DRED to be encoded with the expected loss rate. + min_packet_loss_percent: if dred_duration > 0 { loss } else { 0 }, + // Only used for Deep PLC (decoder complexity 5) or DRED tests. + dnn_weights_path: "/data/deep_plc-dred-weights.bin".to_string(), + ..Default::default() + }, + profile: DeterministicLoss(loss), + ..Default::default() + }, + iterations: 3, + ..Default::default() + }) + }) + .collect(); + + test.run( + GroupConfig { + group_name: "dred_tests".to_string(), + summary_report_columns: SummaryReportColumns { + show_visqol_mos_speech: true, + show_visqol_mos_audio: true, + show_pesq_mos: true, + show_plc_mos: true, + show_video: false, + show_send_stats: false, + show_dred_stats: true, + ..Default::default() + }, + ..Default::default() + }, + test_cases, + vec![NetworkProfile::None], + ) + .await?; + + Ok(()) +} + #[tokio::main] async fn main() -> Result<()> { let args = Args::parse(); @@ -1078,6 +1171,7 @@ async fn main() -> Result<()> { "changing_bandwidth_audio_test" => run_changing_bandwidth_audio_test(test).await?, "profiling_suite" => run_perf_test(test).await?, "plc_tests" => run_plc_tests(test).await?, + "dred_tests" => run_dred_tests(test).await?, _ => panic!("unknown test set \"{test_set_name}\""), } test.report().await?; diff --git a/call_sim/src/test.rs b/call_sim/src/test.rs index 27c37d57..2b00adb4 100644 --- a/call_sim/src/test.rs +++ b/call_sim/src/test.rs @@ -169,6 +169,7 @@ pub struct MediaFileIo { } impl Test { + #[allow(clippy::too_many_arguments)] pub fn new( root_path: &PathBuf, output_dir: &str, diff --git a/config/version.properties b/config/version.properties index 7334dae5..88cbdbd0 100644 --- a/config/version.properties +++ b/config/version.properties @@ -1,4 +1,4 @@ -webrtc.version=7680c +webrtc.version=7680e ringrtc.version.major=2 ringrtc.version.minor=68 diff --git a/config/webrtc_artifact_checksums.json b/config/webrtc_artifact_checksums.json index 611b8edb..4834708b 100644 --- a/config/webrtc_artifact_checksums.json +++ b/config/webrtc_artifact_checksums.json @@ -1,10 +1,10 @@ { - "android": "8be76daee99a7ea273683dbcd396f92db4d7aa0a7a0aac61631cd53693322cf0", - "ios": "665f1f19f3de74444c7953f70d599a94c57113374ac62d558f9bce11dc21d1e8", - "linux-x64": "74b2e7f9e36b24e81eb06df067e9459d97a9f4d89e1d10dc81c766fb823d1f51", - "linux-arm64": "77ee9067a80db4556b02f1f8d97a363ddd2f53499c7e0b1c945bc753d840458d", - "mac-x64": "217bc4868e2751b51cd05e332fc87f219b314c8312e1cf02ec75d3be20eefdcc", - "mac-arm64": "60536d4de2926fe5a71dae57d671f8d43e1b6cbbb55e555e3cfd79b40c6e6f48", - "windows-x64": "c28a52dc851655b45bcc90251b2cc32aa0741e5b34c9ec6ec3ecefbe970f9ce6", - "windows-arm64": "0cafb1d30500fe4f3dca465202d6bffb3c54e2ae5dc6e05ce638d600d132b60a" + "android": "220b03c2a3af7b9262459aee837b432c6c05d120887c0fe5fb6283f3721e99cb", + "ios": "43642dea9ebf9db29d69f0cb1dd9082978a69501bf0e69a14eaf37d015ae1faa", + "linux-x64": "194055090f078b7e9f946b9f756144612b854f0d17fe077824d52753d7d7d916", + "linux-arm64": "00c54e0fd9afd38c28f011d9ea5d09ba0472e4ae2c93ac756d8e051b55f9f8bf", + "mac-x64": "07ac844dc85d808cbfead56e38584515b623efaddcd49dee54cb74da2f9338a0", + "mac-arm64": "f35c85ebfaa6bc6dc70d56df552c0805c40f62643e8ff12df23093b663102273", + "windows-x64": "8c748f17a958c96c931040329c95cb6235b782ffea2d19c5e1c0ed43b5f12d81", + "windows-arm64": "93457fb51b8cd9cbfdcb2dff2a591896fb971c4ddcd38ac1854530e3f2173b29" } diff --git a/src/rust/src/core/call.rs b/src/rust/src/core/call.rs index d189da3d..fa505a10 100644 --- a/src/rust/src/core/call.rs +++ b/src/rust/src/core/call.rs @@ -37,7 +37,9 @@ use crate::{ }, error::RingRtcError, webrtc::{ - ice_gatherer::IceGatherer, media::MediaStream, peer_connection::AudioLevel, + ice_gatherer::IceGatherer, + media::{MediaStream, configure_dred_from_assets}, + peer_connection::AudioLevel, peer_connection_observer::NetworkRoute, }, }; @@ -583,47 +585,11 @@ where let mut call_manager = self.call_manager()?; - // Change the call configuration based on available assets. Don't use this - // if building for the call_sim feature. - if cfg!(not(feature = "call_sim")) && call_config.audio_encoder_config.dred_duration > 0 { - // See if model assets are available for Opus DRED (including Deep PLC). - info!("assets: Checking for opus-dred assets in the registry..."); - if let Some(versions) = self.asset_registry.get_options_for("opus-dred") { - info!( - "assets: There are {} opus-dred asset versions available", - versions.len() - ); - if let Some(version) = versions.first() { - if let Some(asset) = self.asset_registry.get_asset("opus-dred", *version) { - info!("assets: opus-dred asset version {version} found"); - - // Set the weights on both the encoder and decoder. - // Lifetime: Each clone of the Arc will be held by - // a connection or group call object which lives as long as the - // PeerConnection in WebRTC. - call_config.audio_encoder_config.dnn_weights = - Some(Arc::clone(&asset.content)); - call_config.audio_decoder_config.dnn_weights = Some(asset.content); - - // Set up Opus for the optimal DRED configuration. - // Disable FEC and make sure that Opus Deep PLC is always used. - call_config.audio_encoder_config.enable_fec = false; - call_config.audio_decoder_config.complexity = Some(5); - } else { - warn!("assets: Failed to get opus-dred asset version {version}!"); - } - } else { - warn!("assets: No versions found for opus-dred!"); - } - } else { - warn!("assets: No opus-dred assets found!"); - } - - if call_config.audio_encoder_config.dnn_weights.is_none() { - warn!("assets: Disabling DRED since no dnn weights were found!"); - call_config.audio_encoder_config.dred_duration = 0; - } - } + configure_dred_from_assets( + &self.asset_registry, + &mut call_config.audio_encoder_config, + &mut call_config.audio_decoder_config, + ); match self.direction { // This happens after received_offer and an offer is put in self.pending_call. diff --git a/src/rust/src/core/group_call.rs b/src/rust/src/core/group_call.rs index 57efc2a5..75374603 100644 --- a/src/rust/src/core/group_call.rs +++ b/src/rust/src/core/group_call.rs @@ -63,7 +63,8 @@ use crate::{ webrtc::{ self, media::{ - AudioEncoderConfig, AudioTrack, VideoFrame, VideoFrameMetadata, VideoSink, VideoTrack, + AudioDecoderConfig, AudioEncoderConfig, AudioTrack, VideoFrame, VideoFrameMetadata, + VideoSink, VideoTrack, configure_dred_from_assets, }, peer_connection::{AudioLevel, PeerConnection, Protocol, ReceivedAudioLevel, SendRates}, peer_connection_factory::{self as pcf, AudioJitterBufferConfig, PeerConnectionFactory}, @@ -2927,12 +2928,24 @@ impl Client { // Currently, this occurs via on_sfu_client_joined (Joining -> Joined) or // or via peek_result_inner (Joining -> Pending -> Joined) fn on_client_joined(state: &mut State) { + let mut encoder_config = AudioEncoderConfig { + dred_duration: state.dred_duration, + ..AudioEncoderConfig::default() + }; + let mut decoder_config = AudioDecoderConfig::default(); + + configure_dred_from_assets( + &state.asset_registry, + &mut encoder_config, + &mut decoder_config, + ); + state .peer_connection - .configure_audio_encoders(&AudioEncoderConfig { - dred_duration: state.dred_duration, - ..AudioEncoderConfig::default() - }); + .configure_audio_encoders(&encoder_config); + state + .peer_connection + .configure_audio_decoders(&decoder_config); } pub fn on_signaling_message_received( diff --git a/src/rust/src/webrtc/media.rs b/src/rust/src/webrtc/media.rs index 35066f39..f2daa760 100644 --- a/src/rust/src/webrtc/media.rs +++ b/src/rust/src/webrtc/media.rs @@ -12,7 +12,7 @@ use crate::webrtc::ffi::media; pub use crate::webrtc::peer_connection_factory::RffiPeerConnectionFactoryOwner; #[cfg(feature = "sim")] use crate::webrtc::sim::media; -use crate::{lite::sfu::DemuxId, webrtc}; +use crate::{core::assets::AssetRegistry, lite::sfu::DemuxId, webrtc}; /// Rust wrapper around WebRTC C++ MediaStream object. #[derive(Clone, Debug)] @@ -541,3 +541,51 @@ impl AudioDecoderConfig { } } } + +/// If dred_duration > 0, looks up DNN weights from the asset registry +/// and configures both encoder and decoder for DRED. If no weights are +/// found, disables DRED by setting dred_duration to 0. +pub fn configure_dred_from_assets( + asset_registry: &AssetRegistry, + encoder_config: &mut AudioEncoderConfig, + decoder_config: &mut AudioDecoderConfig, +) { + // Don't load assets if we aren't using DRED or building for the Call Simulator. + if cfg!(feature = "call_sim") || encoder_config.dred_duration == 0 { + return; + } + + info!("assets: Checking for opus-dred assets in the registry..."); + if let Some(versions) = asset_registry.get_options_for("opus-dred") { + info!( + "assets: There are {} opus-dred asset versions available", + versions.len() + ); + if let Some(version) = versions.first() { + if let Some(asset) = asset_registry.get_asset("opus-dred", *version) { + info!("assets: opus-dred asset version {version} found"); + + // Set the weights on both the encoder and decoder. + // Lifetime: Each clone of the Arc will be held by + // a connection or group call object which lives as long as the + // PeerConnection in WebRTC. + encoder_config.dnn_weights = Some(Arc::clone(&asset.content)); + decoder_config.dnn_weights = Some(asset.content); + + // Disable FEC when using DRED. + encoder_config.enable_fec = false; + + return; + } else { + warn!("assets: Failed to get opus-dred asset version {version}!"); + } + } else { + warn!("assets: No versions found for opus-dred!"); + } + } else { + warn!("assets: No opus-dred assets found!"); + } + + warn!("assets: Disabling DRED since no dnn weights were found!"); + encoder_config.dred_duration = 0; +}