From 3fa7eb2a5ac66e50218aef38302df6f07ed0f15f Mon Sep 17 00:00:00 2001 From: Miriam Zimmerman Date: Fri, 30 Jan 2026 12:11:03 -0500 Subject: [PATCH 01/10] iOS: Add ifdef'd support for video file input --- SignalRingRTC.podspec | 1 + .../VideoCaptureController.swift | 142 +++++++++++++----- 2 files changed, 109 insertions(+), 34 deletions(-) diff --git a/SignalRingRTC.podspec b/SignalRingRTC.podspec index f917754b..8503b651 100644 --- a/SignalRingRTC.podspec +++ b/SignalRingRTC.podspec @@ -56,6 +56,7 @@ Pod::Spec.new do |s| 'CARGO_BUILD_TARGET[sdk=iphonesimulator*][arch=arm64]' => 'aarch64-apple-ios-sim', 'CARGO_BUILD_TARGET[sdk=iphonesimulator*][arch=*]' => 'x86_64-apple-ios', 'CARGO_BUILD_TARGET[sdk=iphoneos*]' => 'aarch64-apple-ios', + 'SWIFT_ACTIVE_COMPILATION_CONDITIONS' => ENV.include?('RINGRTC_USE_FILE_BASED_CAMERA') ? 'USE_FILE_BASED_CAMERA' : '', } s.script_phases = [ diff --git a/src/ios/SignalRingRTC/SignalRingRTC/VideoCaptureController.swift b/src/ios/SignalRingRTC/SignalRingRTC/VideoCaptureController.swift index 3bba39fe..4ce43e4d 100644 --- a/src/ios/SignalRingRTC/SignalRingRTC/VideoCaptureController.swift +++ b/src/ios/SignalRingRTC/SignalRingRTC/VideoCaptureController.swift @@ -12,18 +12,41 @@ public class VideoCaptureController { static let maxCaptureHeight: Int32 = 720 static let maxCaptureFrameRate: Int32 = 30 + // Keep around for captureSession even if USE_FILE_BASED_CAMERA private let capturer = RTCCameraVideoCapturer() - var capturerDelegate: RTCVideoCapturerDelegate? { - set { capturer.delegate = newValue } - get { capturer.delegate } - } - private let serialQueue = DispatchQueue(label: "org.signal.videoCaptureController") + + #if USE_FILE_BASED_CAMERA + private var fileCapturer = RTCFileVideoCapturer() + private var delegate: RTCVideoCapturerDelegate? + var capturerDelegate: RTCVideoCapturerDelegate? { + set { + self.delegate = newValue + let wasCapturing = self.isCapturing + if wasCapturing { + self.stopCapture() + } + self.fileCapturer = RTCFileVideoCapturer.init( + delegate: newValue! + ) + if wasCapturing { + self.startCapture() + } + } + get { self.delegate } + } + #else + var capturerDelegate: RTCVideoCapturerDelegate? { + set { capturer.delegate = newValue } + get { capturer.delegate } + } + #endif + private let serialQueue = DispatchQueue( + label: "org.signal.videoCaptureController" + ) private var _isUsingFrontCamera: Bool = true public var isUsingFrontCamera: Bool? { - get { - serialQueue.sync { [weak self] in - return self?._isUsingFrontCamera - } + serialQueue.sync { [weak self] in + return self?._isUsingFrontCamera } } private var isCapturing: Bool = false @@ -62,7 +85,11 @@ public class VideoCaptureController { // a crash on iOS 13 when built with the iOS 13 SDK. guard strongSelf.isCapturing else { return } - strongSelf.capturer.stopCapture() + #if USE_FILE_BASED_CAMERA + strongSelf.fileCapturer.stopCapture() + #else + strongSelf.capturer.stopCapture() + #endif strongSelf.isCapturing = false } } @@ -78,7 +105,9 @@ public class VideoCaptureController { // Only restart capturing again if the camera changes. if strongSelf._isUsingFrontCamera != isUsingFrontCamera { strongSelf._isUsingFrontCamera = isUsingFrontCamera - strongSelf.startCaptureSync() + #if !USE_FILE_BASED_CAMERA + strongSelf.startCaptureSync() + #endif } } } @@ -93,24 +122,44 @@ public class VideoCaptureController { Logger.info("startCaptureSync():") assertIsOnSerialQueue() - let position: AVCaptureDevice.Position = _isUsingFrontCamera ? .front : .back - guard let device: AVCaptureDevice = self.device(position: position) else { - failDebug("unable to find captureDevice") - return - } + #if USE_FILE_BASED_CAMERA + fileCapturer.startCapturing( + fromFileNamed: "input_video.mp4", + onError: { (error: Error) -> Void in + Logger.error("Failed to start capturing: \(error)") + } + ) + #else + + let position: AVCaptureDevice.Position = + _isUsingFrontCamera ? .front : .back + guard let device: AVCaptureDevice = self.device(position: position) + else { + failDebug("unable to find captureDevice") + return + } - guard let format: AVCaptureDevice.Format = self.format(device: device) else { - failDebug("unable to find captureDevice") - return - } + guard + let format: AVCaptureDevice.Format = self.format(device: device) + else { + failDebug("unable to find captureDevice") + return + } + capturer.startCapture( + with: device, + format: format, + fps: Int(VideoCaptureController.maxCaptureFrameRate) + ) + #endif - capturer.startCapture(with: device, format: format, fps: Int(VideoCaptureController.maxCaptureFrameRate)) isCapturing = true } - private func device(position: AVCaptureDevice.Position) -> AVCaptureDevice? { + private func device(position: AVCaptureDevice.Position) -> AVCaptureDevice? + { let captureDevices = RTCCameraVideoCapturer.captureDevices() - guard let device = (captureDevices.first { $0.position == position }) else { + guard let device = (captureDevices.first { $0.position == position }) + else { Logger.debug("unable to find desired position: \(position)") return captureDevices.first } @@ -124,7 +173,7 @@ public class VideoCaptureController { CChar(pixelFormat >> 16 & 0xFF), CChar(pixelFormat >> 8 & 0xFF), CChar(pixelFormat & 0xFF), - 0 + 0, ] var subTypeString = "" @@ -145,37 +194,62 @@ public class VideoCaptureController { // on all devices the client supports. let screenSize = UIScreen.main.nativeBounds.size // screenSize is given in portrait-up orientation, but capture dimensions are in landscape. - let targetWidth = max(Int32(screenSize.height), VideoCaptureController.maxCaptureWidth) - let targetHeight = max(Int32(screenSize.width), VideoCaptureController.maxCaptureHeight) + let targetWidth = max( + Int32(screenSize.height), + VideoCaptureController.maxCaptureWidth + ) + let targetHeight = max( + Int32(screenSize.width), + VideoCaptureController.maxCaptureHeight + ) let targetFrameRate = VideoCaptureController.maxCaptureFrameRate Logger.info("Capture Formats") Logger.info(" screenSize: \(screenSize)") - Logger.info(" maxCaptureWidth: \(VideoCaptureController.maxCaptureWidth)") - Logger.info(" maxCaptureHeight: \(VideoCaptureController.maxCaptureHeight)") + Logger.info( + " maxCaptureWidth: \(VideoCaptureController.maxCaptureWidth)" + ) + Logger.info( + " maxCaptureHeight: \(VideoCaptureController.maxCaptureHeight)" + ) Logger.info(" targetWidth: \(targetWidth)") Logger.info(" targetHeight: \(targetHeight)") Logger.info(" targetFrameRate: \(targetFrameRate)") - Logger.info(" preferredPixelFormat: \(getSubTypeString(pixelFormat: capturer.preferredOutputPixelFormat()))") + #if !USE_FILE_BASED_CAMERA + // Not there on RTCFileVideoCapture + Logger.info( + " preferredPixelFormat: \(getSubTypeString(pixelFormat: capturer.preferredOutputPixelFormat()))" + ) + #endif Logger.debug(" formats:") var selectedFormat: AVCaptureDevice.Format? var currentDiff: Int32 = Int32.max for format in formats { - let dimension = CMVideoFormatDescriptionGetDimensions(format.formatDescription) - let pixelFormat = CMFormatDescriptionGetMediaSubType(format.formatDescription); + let dimension = CMVideoFormatDescriptionGetDimensions( + format.formatDescription + ) + let pixelFormat = CMFormatDescriptionGetMediaSubType( + format.formatDescription + ) for range in format.videoSupportedFrameRateRanges { - Logger.debug(" width: \(dimension.width) height: \(dimension.height) pixelFormat: \(getSubTypeString(pixelFormat: pixelFormat)) fps range: \(range.minFrameRate) - \(range.maxFrameRate)") + Logger.debug( + " width: \(dimension.width) height: \(dimension.height) pixelFormat: \(getSubTypeString(pixelFormat: pixelFormat)) fps range: \(range.minFrameRate) - \(range.maxFrameRate)" + ) } - let diff = abs(targetWidth - dimension.width) + abs(targetHeight - dimension.height) + let diff = + abs(targetWidth - dimension.width) + + abs(targetHeight - dimension.height) if diff < currentDiff { // Look through all framerate ranges for this capture format and find // the first that supports the desired framerate. for range in format.videoSupportedFrameRateRanges { - if Double(targetFrameRate) >= range.minFrameRate && Double(targetFrameRate) <= range.maxFrameRate { + if Double(targetFrameRate) >= range.minFrameRate + && Double(targetFrameRate) <= range.maxFrameRate + { selectedFormat = format currentDiff = diff } From 109ff5d83e9322007dcbd251060cb29647860116 Mon Sep 17 00:00:00 2001 From: emir-signal Date: Fri, 30 Jan 2026 13:09:14 -0500 Subject: [PATCH 02/10] Rename rttMedianConnection to rttMedianConnectionMillis survey field in typescript --- src/node/ringrtc/CallSummary.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node/ringrtc/CallSummary.ts b/src/node/ringrtc/CallSummary.ts index 365fbb6f..231a2fe5 100644 --- a/src/node/ringrtc/CallSummary.ts +++ b/src/node/ringrtc/CallSummary.ts @@ -44,7 +44,7 @@ export class QualityStats { * Median connection RTT in milliseconds calculated via STUN/ICE, * or undefined if unavailable. */ - readonly rttMedianConnection: number | undefined; + readonly rttMedianConnectionMillis: number | undefined; /** Audio quality statistics. */ readonly audioStats!: MediaQualityStats; /** Video quality statistics. */ From 021cc5559c7a88c28cca565a8b33f6931db47ede Mon Sep 17 00:00:00 2001 From: Jim Gustafson Date: Fri, 23 Jan 2026 17:36:33 -0800 Subject: [PATCH 03/10] Call Sim: Add vp8/9 comparison bitrate option --- call_sim/src/main.rs | 113 +++++++++++++++++++++++-------------------- 1 file changed, 61 insertions(+), 52 deletions(-) diff --git a/call_sim/src/main.rs b/call_sim/src/main.rs index 0c2a3815..4407cba6 100644 --- a/call_sim/src/main.rs +++ b/call_sim/src/main.rs @@ -656,69 +656,76 @@ async fn run_video_send_over_bandwidth(test: &mut Test) -> Result<()> { } /// Bidirectional video test comparing the vp8 and vp9 video codecs. -async fn run_video_compare_vp8_vs_vp9(test: &mut Test) -> Result<()> { - test.preprocess_sounds(vec!["normal_phrasing"]).await?; +async fn run_video_compare_vp8_vs_vp9(test: &mut Test, bitrate_values: &Vec) -> Result<()> { + let mut test_cases = Vec::new(); - test.run( - GroupConfig { - group_name: "video_compare_vp8_vs_vp9".to_string(), - chart_dimensions: vec![ChartDimension::MosSpeech], - ..Default::default() - }, - vec![ - TestCaseConfig { - test_case_name: "vp8".to_string(), - client_a_config: CallConfig { - audio: AudioConfig { - input_name: "normal_phrasing".to_string(), - ..Default::default() - }, - video: VideoConfig { - input_name: Some("ConferenceMotion_50fps@1280x720".to_string()), - ..Default::default() - }, + for bitrate in bitrate_values { + test_cases.push(TestCaseConfig { + test_case_name: format!("vp8_{}", bitrate), + client_a_config: CallConfig { + audio: AudioConfig { + input_name: "normal_phrasing".to_string(), ..Default::default() }, - client_b_config: CallConfig { - audio: AudioConfig { - input_name: "normal_phrasing".to_string(), - ..Default::default() - }, - video: VideoConfig { - input_name: Some("ConferenceMotion_50fps@1280x720".to_string()), - ..Default::default() - }, + video: VideoConfig { + input_name: Some("ConferenceMotion_50fps@1280x720".to_string()), ..Default::default() }, + allowed_bitrate_kbps: *bitrate, ..Default::default() }, - TestCaseConfig { - test_case_name: "vp9".to_string(), - client_a_config: CallConfig { - audio: AudioConfig { - input_name: "normal_phrasing".to_string(), - ..Default::default() - }, - video: VideoConfig { - input_name: Some("ConferenceMotion_50fps@1280x720".to_string()), - enable_vp9: true, - }, + client_b_config: CallConfig { + audio: AudioConfig { + input_name: "normal_phrasing".to_string(), ..Default::default() }, - client_b_config: CallConfig { - audio: AudioConfig { - input_name: "normal_phrasing".to_string(), - ..Default::default() - }, - video: VideoConfig { - input_name: Some("ConferenceMotion_50fps@1280x720".to_string()), - enable_vp9: true, - }, + video: VideoConfig { + input_name: Some("ConferenceMotion_50fps@1280x720".to_string()), ..Default::default() }, + allowed_bitrate_kbps: *bitrate, ..Default::default() }, - ], + ..Default::default() + }); + + test_cases.push(TestCaseConfig { + test_case_name: format!("vp9_{}", bitrate), + client_a_config: CallConfig { + audio: AudioConfig { + input_name: "normal_phrasing".to_string(), + ..Default::default() + }, + video: VideoConfig { + input_name: Some("ConferenceMotion_50fps@1280x720".to_string()), + enable_vp9: true, + }, + allowed_bitrate_kbps: *bitrate, + ..Default::default() + }, + client_b_config: CallConfig { + audio: AudioConfig { + input_name: "normal_phrasing".to_string(), + ..Default::default() + }, + video: VideoConfig { + input_name: Some("ConferenceMotion_50fps@1280x720".to_string()), + enable_vp9: true, + }, + allowed_bitrate_kbps: *bitrate, + ..Default::default() + }, + ..Default::default() + }); + } + + test.run( + GroupConfig { + group_name: "video_compare_vp8_vs_vp9".to_string(), + chart_dimensions: vec![ChartDimension::MosSpeech], + ..Default::default() + }, + test_cases, vec![NetworkProfile::Default], ) .await?; @@ -950,7 +957,7 @@ async fn main() -> Result<()> { let mut test_sets = args.test_sets; if test_sets.is_empty() { // For quick testing, change this to the name of your test case. - test_sets.push("baseline".to_string()); + test_sets.push("video_compare_vp8_vs_vp9".to_string()); } let direct_call_config = CallTypeConfig::Direct; @@ -990,7 +997,9 @@ async fn main() -> Result<()> { "relay_tests" => run_relay_tests(test).await?, "turn_long_tests" => run_turn_long_tests(test).await?, "video_send_over_bandwidth" => run_video_send_over_bandwidth(test).await?, - "video_compare_vp8_vs_vp9" => run_video_compare_vp8_vs_vp9(test).await?, + "video_compare_vp8_vs_vp9" => { + run_video_compare_vp8_vs_vp9(test, &vec![1000, 2000]).await? + } "changing_bandwidth_audio_test" => run_changing_bandwidth_audio_test(test).await?, "profiling_suite" => run_perf_test(test).await?, _ => panic!("unknown test set \"{test_set_name}\""), From 71a4e58b459a3fe15c58de63326c8eac28979db7 Mon Sep 17 00:00:00 2001 From: Jim Gustafson Date: Fri, 23 Jan 2026 17:35:10 -0800 Subject: [PATCH 04/10] Call Sim: Fix docker stats --- call_sim/src/docker.rs | 108 ++++++++++++++++++++++------------------- 1 file changed, 59 insertions(+), 49 deletions(-) diff --git a/call_sim/src/docker.rs b/call_sim/src/docker.rs index ab2e798b..d7f8db4e 100644 --- a/call_sim/src/docker.rs +++ b/call_sim/src/docker.rs @@ -10,10 +10,10 @@ use bollard::{ Docker, models::ContainerMemoryStats, query_parameters, - secret::{ContainerCpuStats, ContainerCpuUsage, ContainerStatsResponse}, + secret::{ContainerCpuStats, ContainerCpuUsage}, }; use chrono::DateTime; -use futures_util::stream::TryStreamExt; +use futures_util::stream::StreamExt; use itertools::Itertools; use tokio::{ fs::OpenOptions, @@ -1595,36 +1595,37 @@ impl DockerStats { let path = path.to_string(); tokio::spawn(async move { + // Setup to stream statistics from Docker (default: every 1 second). let query_parameters = query_parameters::StatsOptionsBuilder::new() .stream(true) .build(); - let stream = &mut docker.stats(&name, Some(query_parameters)); - - // Collect the stats. This will await until the container is stopped then dump - // all the stats to a log. - match stream.try_collect::>().await { - Ok(responses) => { - match OpenOptions::new() - .write(true) - .create(true) - .truncate(true) - .open(format!("{}/{}_stats.log", path, name)) - .await - { - Ok(mut file) => { - let _ = file - .write_all(b"Timestamp\tCPU\tMEM\tTX_Bitrate\tRX_Bitrate\n") - .await; - - let mut prev_timestamp = 0i64; - - let mut prev_tx_bytes = 0u64; - let mut prev_rx_bytes = 0u64; - - let mut prev_total_cpu_usage = 0u64; - let mut prev_system_cpu_usage = 0u64; - - for response in responses { + let mut stream = docker.stats(&name, Some(query_parameters)); + + // Collect the stats. Open a file and write the values as they arrive. + match OpenOptions::new() + .write(true) + .create(true) + .truncate(true) + .open(format!("{}/{}_stats.log", path, name)) + .await + { + Ok(mut file) => { + let _ = file + .write_all(b"Timestamp\tCPU\tMEM\tTX_Bitrate\tRX_Bitrate\n") + .await; + + let mut prev_timestamp = 0i64; + + let mut prev_tx_bytes = 0u64; + let mut prev_rx_bytes = 0u64; + + let mut prev_total_cpu_usage = 0u64; + let mut prev_system_cpu_usage = 0u64; + + // Process stats as they arrive. + while let Some(result) = stream.next().await { + match result { + Ok(response) => { match (response.cpu_stats, response.memory_stats, response.networks) { ( @@ -1655,25 +1656,29 @@ impl DockerStats { Some(network) => { let tx_bytes = network.tx_bytes.unwrap(); let rx_bytes = network.rx_bytes.unwrap(); - let time_delta = - (timestamp - prev_timestamp) as f32 / 1000.0; - let tx_bitrate = (tx_bytes - prev_tx_bytes) as f32 - * 8.0 - / time_delta; - let rx_bitrate = (rx_bytes - prev_rx_bytes) as f32 - * 8.0 - / time_delta; + + let (tx_bitrate, rx_bitrate) = + if prev_timestamp == 0 { + // Ignore the first data point since there was no reference. + (0.0, 0.0) + } else { + let time_delta = + (timestamp - prev_timestamp) as f32 + / 1000.0; + let tx_bitrate = + (tx_bytes - prev_tx_bytes) as f32 * 8.0 + / time_delta; + let rx_bitrate = + (rx_bytes - prev_rx_bytes) as f32 * 8.0 + / time_delta; + (tx_bitrate, rx_bitrate) + }; prev_timestamp = timestamp; prev_tx_bytes = tx_bytes; prev_rx_bytes = rx_bytes; - if prev_timestamp == 0 { - // Ignore the first data point since there was no reference. - (0.0, 0.0) - } else { - (tx_bitrate, rx_bitrate) - } + (tx_bitrate, rx_bitrate) } None => { println!("Error: stat missing eth0!"); @@ -1692,8 +1697,12 @@ impl DockerStats { // grow over time and doesn't directly reflect RingRTC's // memory usage. // https://docs.docker.com/engine/reference/commandline/stats/#description - let memory = memory_usage - - memory_stats.get("total_inactive_file").unwrap(); + let cache_usage = *memory_stats + .get("total_inactive_file") + .or_else(|| memory_stats.get("inactive_file")) + .unwrap_or(&0); + + let memory = memory_usage.saturating_sub(cache_usage); let _ = file .write_all( format!( @@ -1717,14 +1726,15 @@ impl DockerStats { } } } - } - Err(err) => { - println!("Error creating stats file: {:?}", err); + Err(err) => { + println!("Error collecting stats for {}: {:?}", name, err); + break; + } } } } Err(err) => { - println!("Error collecting stats for {}: {:?}", name, err); + println!("Error creating stats file: {:?}", err); } } }); From 98fb194606aa3bc935c81dcbc6dcbd89051e9357 Mon Sep 17 00:00:00 2001 From: Jim Gustafson Date: Fri, 30 Jan 2026 14:54:16 -0800 Subject: [PATCH 05/10] Call Sim: Reset default test to baseline --- call_sim/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/call_sim/src/main.rs b/call_sim/src/main.rs index 4407cba6..71b429ca 100644 --- a/call_sim/src/main.rs +++ b/call_sim/src/main.rs @@ -957,7 +957,7 @@ async fn main() -> Result<()> { let mut test_sets = args.test_sets; if test_sets.is_empty() { // For quick testing, change this to the name of your test case. - test_sets.push("video_compare_vp8_vs_vp9".to_string()); + test_sets.push("baseline".to_string()); } let direct_call_config = CallTypeConfig::Direct; From d0245b00f5303194bbea817d6b3395925f54e9f6 Mon Sep 17 00:00:00 2001 From: emir-signal Date: Fri, 30 Jan 2026 20:56:38 -0500 Subject: [PATCH 06/10] Make call summary optional in protobuf --- protobuf/Cargo.toml | 3 ++- protobuf/build.rs | 13 ++++++++++--- protobuf/src/lib.rs | 4 ++-- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/protobuf/Cargo.toml b/protobuf/Cargo.toml index df1c504b..ebab5701 100644 --- a/protobuf/Cargo.toml +++ b/protobuf/Cargo.toml @@ -16,9 +16,10 @@ path = "src/lib.rs" proc-macro = true [features] -default = ["signaling"] +default = ["signaling", "call_summary"] signaling = [] call_sim = ["signaling"] +call_summary = [] [build-dependencies] prost-build = "0.14.1" diff --git a/protobuf/build.rs b/protobuf/build.rs index 992e70fe..365239da 100644 --- a/protobuf/build.rs +++ b/protobuf/build.rs @@ -7,17 +7,24 @@ fn main() { // Explicitly state that by depending on build.rs itself, as recommended. println!("cargo:rerun-if-changed=build.rs"); + if cfg!(feature = "call_summary") { + prost_build::Config::new() + .type_attribute(".call_summary", "#[serde_with::skip_serializing_none]") + .type_attribute(".call_summary", "#[derive(serde::Serialize)]") + .compile_protos(&["protobuf/call_summary.proto"], &["protobuf"]) + .expect("Protobufs are valid"); + + println!("cargo:rerun-if-changed=protobuf/call_summary.proto"); + } + if cfg!(feature = "signaling") { let protos = [ "protobuf/group_call.proto", "protobuf/rtp_data.proto", "protobuf/signaling.proto", - "protobuf/call_summary.proto", ]; prost_build::Config::new() - .type_attribute(".call_summary", "#[serde_with::skip_serializing_none]") - .type_attribute(".call_summary", "#[derive(serde::Serialize)]") .compile_protos(&protos, &["protobuf"]) .expect("Protobufs are valid"); diff --git a/protobuf/src/lib.rs b/protobuf/src/lib.rs index 5c93728f..b0b5bb08 100644 --- a/protobuf/src/lib.rs +++ b/protobuf/src/lib.rs @@ -26,7 +26,7 @@ const RTP_DATA_PROTO: &str = include_str!(concat!(env!("OUT_DIR"), "/rtp_data.rs #[cfg(feature = "signaling")] const SIGNALING_PROTO: &str = include_str!(concat!(env!("OUT_DIR"), "/signaling.rs")); -#[cfg(feature = "signaling")] +#[cfg(feature = "call_summary")] const CALL_SUMMARY_PROTO: &str = include_str!(concat!(env!("OUT_DIR"), "/call_summary.rs")); #[cfg(feature = "call_sim")] @@ -50,7 +50,7 @@ pub fn include_signaling_proto(_input: TokenStream) -> TokenStream { SIGNALING_PROTO.parse().unwrap() } -#[cfg(feature = "signaling")] +#[cfg(feature = "call_summary")] #[proc_macro] pub fn include_call_summary_proto(_input: TokenStream) -> TokenStream { CALL_SUMMARY_PROTO.parse().unwrap() From 130a1bdf2ed4113adc15d7145325ecbc677769b8 Mon Sep 17 00:00:00 2001 From: Jim Gustafson Date: Mon, 2 Feb 2026 16:40:26 -0800 Subject: [PATCH 07/10] Update to webrtc 7444f - Send DTX TOC only in lieu of refresh packets - Update logging in connection.cc to log ICE failures --- bin/fetch-artifact.py | 16 ++++++++-------- config/version.properties | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/bin/fetch-artifact.py b/bin/fetch-artifact.py index 04650f59..87442f88 100755 --- a/bin/fetch-artifact.py +++ b/bin/fetch-artifact.py @@ -19,14 +19,14 @@ UNVERIFIED_DOWNLOAD_NAME = "unverified.tmp" PREBUILD_CHECKSUMS = { - 'android': 'f746796a0494f005d9a032bcec5a811522089658fb3bcffb172b50f918bfbe74', - 'ios': '3b2c249daeac4b3ee25d11d1b1659ba0f0405b1ae0230da91cc73ac7c1b24ff2', - 'linux-x64': '497531230622c2a934be55ddc7c9f7c7ac2ce4577e87201f2492e3febdf1d694', - 'linux-arm64': 'c585cc746a94f37f9a40fbbae92c544d2a2552f5b6f8e006effe7b42add3b1d6', - 'mac-x64': '6728ee6e3dd29f291237359d2d69100c935be8e8cce0cf78efb7b282a506d64d', - 'mac-arm64': 'a839ed44de14330d6fd33f8d074bcef40abf1ad6dca276898a319188e2784326', - 'windows-x64': 'e76f45191fa48f1a66b82d80f41b9045b89a11caeb47e7fd83d64fda58960be0', - 'windows-arm64': 'd0fcb0081e3c5ff0e716003f824672fdafd265e275eba8a6f4ed61298005c28c', + 'android': '520be7a10fa6c796cba29a790c8bf839b2e9f08b06b9314ebb165f0d76bbf7f9', + 'ios': '5421d640ce6f598a42cbc22eeb74223135d6d9869f8929d6bd5acaf0722527ff', + 'linux-x64': '9135254b5b230b50ddbe6787d85715676ccc41636af331bef670303762153c99', + 'linux-arm64': '3e9a4eab524c386fa87a30f3ff2156f375e563bed2b9e3ba5a78917f8dd76e70', + 'mac-x64': '36d19d0ee14a0bbe45dc24298b1b211ec4ee11b7d891c585feb43383e4d8920f', + 'mac-arm64': '30cd81aca0f9c8f971895b584104f8412abd3c7a067f49c5b8322e1b7beebf2f', + 'windows-x64': '51fa1684901009f04684c45f039a9cbf48be2b7cf5242ad730b203adf69bd0c0', + 'windows-arm64': '5cf450c5fc0cb50840e5c18dc97afeb9a17c5ea7b359949b8c9af62adcf7770a', } diff --git a/config/version.properties b/config/version.properties index 451a092a..bce73c93 100644 --- a/config/version.properties +++ b/config/version.properties @@ -1,4 +1,4 @@ -webrtc.version=7444e +webrtc.version=7444f ringrtc.version.major=2 ringrtc.version.minor=63 From ff0ef313ff9f1c13a4cfc30664fa04d76bd315c4 Mon Sep 17 00:00:00 2001 From: Jim Gustafson Date: Mon, 2 Feb 2026 17:23:00 -0800 Subject: [PATCH 08/10] Bump version to v2.64.0 --- CHANGELOG.md | 12 ++++++++++++ Cargo.lock | 12 ++++++------ Cargo.toml | 2 +- SignalRingRTC.podspec | 2 +- acknowledgments/acknowledgments.html | 6 +++--- acknowledgments/acknowledgments.md | 2 +- acknowledgments/acknowledgments.plist | 2 +- call_sim/docker/signaling_server/Cargo.lock | 2 +- config/version.properties | 2 +- src/node/package-lock.json | 4 ++-- src/node/package.json | 2 +- 11 files changed, 30 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 28c45a68..64c2348e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog +## v2.64.0 + +- Update to webrtc 7444f + - Send DTX TOC only in lieu of refresh packets + - Update logging in connection.cc to log ICE failures + +- Desktop: Rename rttMedianConnection to rttMedianConnectionMillis survey field + +- iOS: Add ifdef'd support for video file input + +- Call Sim: Minor improvements and fixes + ## v2.63.0 - Desktop: Always disable mic and camera on call end diff --git a/Cargo.lock b/Cargo.lock index 54742bfe..68ee65cf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -357,7 +357,7 @@ checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" [[package]] name = "call_sim" -version = "2.63.0" +version = "2.64.0" dependencies = [ "anyhow", "base64", @@ -371,7 +371,7 @@ dependencies = [ "itertools", "plotters", "prost", - "protobuf 2.63.0", + "protobuf 2.64.0", "regex", "relative-path", "serde", @@ -1857,7 +1857,7 @@ dependencies = [ [[package]] name = "mrp" -version = "2.63.0" +version = "2.64.0" dependencies = [ "anyhow", "log", @@ -2315,7 +2315,7 @@ dependencies = [ [[package]] name = "protobuf" -version = "2.63.0" +version = "2.64.0" dependencies = [ "prost-build", "tonic-prost-build", @@ -2587,7 +2587,7 @@ dependencies = [ [[package]] name = "ringrtc" -version = "2.63.0" +version = "2.64.0" dependencies = [ "aes", "aes-gcm-siv", @@ -2615,7 +2615,7 @@ dependencies = [ "neon", "num_enum", "prost", - "protobuf 2.63.0", + "protobuf 2.64.0", "rand 0.8.5", "rand_chacha 0.3.1", "regex", diff --git a/Cargo.toml b/Cargo.toml index a7d3bb34..a41294d2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ members = [ ] [workspace.package] -version = "2.63.0" +version = "2.64.0" authors = ["Calling Team "] [patch.crates-io] diff --git a/SignalRingRTC.podspec b/SignalRingRTC.podspec index 8503b651..5361155f 100644 --- a/SignalRingRTC.podspec +++ b/SignalRingRTC.podspec @@ -8,7 +8,7 @@ Pod::Spec.new do |s| s.name = "SignalRingRTC" - s.version = "2.63.0" + s.version = "2.64.0" s.summary = "A Swift & Objective-C library used by the Signal iOS app for WebRTC interactions." s.description = <<-DESC diff --git a/acknowledgments/acknowledgments.html b/acknowledgments/acknowledgments.html index a25be412..0e31d1e2 100644 --- a/acknowledgments/acknowledgments.html +++ b/acknowledgments/acknowledgments.html @@ -734,9 +734,9 @@

Used by:

  • libsignal-account-keys 0.1.0
  • libsignal-core 0.1.0
  • -
  • mrp 2.63.0
  • -
  • protobuf 2.63.0
  • -
  • ringrtc 2.63.0
  • +
  • mrp 2.64.0
  • +
  • protobuf 2.64.0
  • +
  • ringrtc 2.64.0
  • regex-aot 0.1.0
  • partial-default-derive 0.1.0
  • partial-default 0.1.0
  • diff --git a/acknowledgments/acknowledgments.md b/acknowledgments/acknowledgments.md index e5d525a5..fb6b7e90 100644 --- a/acknowledgments/acknowledgments.md +++ b/acknowledgments/acknowledgments.md @@ -669,7 +669,7 @@ For more information on this, and how to apply and follow the GNU AGPL, see ``` -## libsignal-account-keys 0.1.0, libsignal-core 0.1.0, mrp 2.63.0, protobuf 2.63.0, ringrtc 2.63.0, regex-aot 0.1.0, partial-default-derive 0.1.0, partial-default 0.1.0 +## libsignal-account-keys 0.1.0, libsignal-core 0.1.0, mrp 2.64.0, protobuf 2.64.0, ringrtc 2.64.0, regex-aot 0.1.0, partial-default-derive 0.1.0, partial-default 0.1.0 ``` GNU AFFERO GENERAL PUBLIC LICENSE diff --git a/acknowledgments/acknowledgments.plist b/acknowledgments/acknowledgments.plist index 9d2a25f7..fda3761c 100644 --- a/acknowledgments/acknowledgments.plist +++ b/acknowledgments/acknowledgments.plist @@ -924,7 +924,7 @@ You should also get your employer (if you work as a programmer) or school, if an License GNU Affero General Public License v3.0 only Title - libsignal-account-keys 0.1.0, libsignal-core 0.1.0, mrp 2.63.0, protobuf 2.63.0, ringrtc 2.63.0, regex-aot 0.1.0, partial-default-derive 0.1.0, partial-default 0.1.0 + libsignal-account-keys 0.1.0, libsignal-core 0.1.0, mrp 2.64.0, protobuf 2.64.0, ringrtc 2.64.0, regex-aot 0.1.0, partial-default-derive 0.1.0, partial-default 0.1.0 Type PSGroupSpecifier diff --git a/call_sim/docker/signaling_server/Cargo.lock b/call_sim/docker/signaling_server/Cargo.lock index d5870fdc..0dce2d41 100644 --- a/call_sim/docker/signaling_server/Cargo.lock +++ b/call_sim/docker/signaling_server/Cargo.lock @@ -662,7 +662,7 @@ dependencies = [ [[package]] name = "protobuf" -version = "2.63.0" +version = "2.64.0" dependencies = [ "prost-build", "tonic-prost-build", diff --git a/config/version.properties b/config/version.properties index bce73c93..3f1e622a 100644 --- a/config/version.properties +++ b/config/version.properties @@ -1,5 +1,5 @@ webrtc.version=7444f ringrtc.version.major=2 -ringrtc.version.minor=63 +ringrtc.version.minor=64 ringrtc.version.revision=0 diff --git a/src/node/package-lock.json b/src/node/package-lock.json index 0fb1524e..a888eb0d 100644 --- a/src/node/package-lock.json +++ b/src/node/package-lock.json @@ -1,12 +1,12 @@ { "name": "@signalapp/ringrtc", - "version": "2.63.0", + "version": "2.64.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@signalapp/ringrtc", - "version": "2.63.0", + "version": "2.64.0", "hasInstallScript": true, "license": "AGPL-3.0-only", "dependencies": { diff --git a/src/node/package.json b/src/node/package.json index c66abd0c..087b4ffa 100644 --- a/src/node/package.json +++ b/src/node/package.json @@ -1,6 +1,6 @@ { "name": "@signalapp/ringrtc", - "version": "2.63.0", + "version": "2.64.0", "repository": { "type": "git", "url": "https://github.com/signalapp/ringrtc.git", From bb33d633a8b4ad78be2c08aed577367756f2f8e8 Mon Sep 17 00:00:00 2001 From: adel-signal Date: Tue, 3 Feb 2026 10:47:39 -0800 Subject: [PATCH 09/10] Fix bug in starting peek after receiving device_joined_or_left --- src/rust/src/core/group_call.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/rust/src/core/group_call.rs b/src/rust/src/core/group_call.rs index 6ad746c7..b9a4d43f 100644 --- a/src/rust/src/core/group_call.rs +++ b/src/rust/src/core/group_call.rs @@ -4445,12 +4445,10 @@ impl Client { Self::request_remote_devices_as_soon_as_possible(state); } } + } else { + info!("SFU notified that a remote device has joined or left, requesting update"); + Self::request_remote_devices_as_soon_as_possible(state); } - } else { - info!( - "SFU notified that a remote device has joined or left, requesting update" - ); - Self::request_remote_devices_as_soon_as_possible(state); } }); } From e5966463b1e065ddadfcc402829df9d1a9f1b5bb Mon Sep 17 00:00:00 2001 From: Jim Gustafson Date: Tue, 3 Feb 2026 10:57:20 -0800 Subject: [PATCH 10/10] Bump version to v2.64.1 --- CHANGELOG.md | 4 ++++ Cargo.lock | 12 ++++++------ Cargo.toml | 2 +- SignalRingRTC.podspec | 2 +- acknowledgments/acknowledgments.html | 6 +++--- acknowledgments/acknowledgments.md | 2 +- acknowledgments/acknowledgments.plist | 2 +- call_sim/docker/signaling_server/Cargo.lock | 2 +- config/version.properties | 2 +- src/node/package-lock.json | 4 ++-- src/node/package.json | 2 +- 11 files changed, 22 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 64c2348e..09701773 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## v2.64.1 + +- Fix bug in starting peek after receiving device_joined_or_left + ## v2.64.0 - Update to webrtc 7444f diff --git a/Cargo.lock b/Cargo.lock index 68ee65cf..88d2c850 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -357,7 +357,7 @@ checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" [[package]] name = "call_sim" -version = "2.64.0" +version = "2.64.1" dependencies = [ "anyhow", "base64", @@ -371,7 +371,7 @@ dependencies = [ "itertools", "plotters", "prost", - "protobuf 2.64.0", + "protobuf 2.64.1", "regex", "relative-path", "serde", @@ -1857,7 +1857,7 @@ dependencies = [ [[package]] name = "mrp" -version = "2.64.0" +version = "2.64.1" dependencies = [ "anyhow", "log", @@ -2315,7 +2315,7 @@ dependencies = [ [[package]] name = "protobuf" -version = "2.64.0" +version = "2.64.1" dependencies = [ "prost-build", "tonic-prost-build", @@ -2587,7 +2587,7 @@ dependencies = [ [[package]] name = "ringrtc" -version = "2.64.0" +version = "2.64.1" dependencies = [ "aes", "aes-gcm-siv", @@ -2615,7 +2615,7 @@ dependencies = [ "neon", "num_enum", "prost", - "protobuf 2.64.0", + "protobuf 2.64.1", "rand 0.8.5", "rand_chacha 0.3.1", "regex", diff --git a/Cargo.toml b/Cargo.toml index a41294d2..a520d208 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ members = [ ] [workspace.package] -version = "2.64.0" +version = "2.64.1" authors = ["Calling Team "] [patch.crates-io] diff --git a/SignalRingRTC.podspec b/SignalRingRTC.podspec index 5361155f..7d9be679 100644 --- a/SignalRingRTC.podspec +++ b/SignalRingRTC.podspec @@ -8,7 +8,7 @@ Pod::Spec.new do |s| s.name = "SignalRingRTC" - s.version = "2.64.0" + s.version = "2.64.1" s.summary = "A Swift & Objective-C library used by the Signal iOS app for WebRTC interactions." s.description = <<-DESC diff --git a/acknowledgments/acknowledgments.html b/acknowledgments/acknowledgments.html index 0e31d1e2..295eaedf 100644 --- a/acknowledgments/acknowledgments.html +++ b/acknowledgments/acknowledgments.html @@ -734,9 +734,9 @@

    Used by:

    • libsignal-account-keys 0.1.0
    • libsignal-core 0.1.0
    • -
    • mrp 2.64.0
    • -
    • protobuf 2.64.0
    • -
    • ringrtc 2.64.0
    • +
    • mrp 2.64.1
    • +
    • protobuf 2.64.1
    • +
    • ringrtc 2.64.1
    • regex-aot 0.1.0
    • partial-default-derive 0.1.0
    • partial-default 0.1.0
    • diff --git a/acknowledgments/acknowledgments.md b/acknowledgments/acknowledgments.md index fb6b7e90..f07d2cd3 100644 --- a/acknowledgments/acknowledgments.md +++ b/acknowledgments/acknowledgments.md @@ -669,7 +669,7 @@ For more information on this, and how to apply and follow the GNU AGPL, see ``` -## libsignal-account-keys 0.1.0, libsignal-core 0.1.0, mrp 2.64.0, protobuf 2.64.0, ringrtc 2.64.0, regex-aot 0.1.0, partial-default-derive 0.1.0, partial-default 0.1.0 +## libsignal-account-keys 0.1.0, libsignal-core 0.1.0, mrp 2.64.1, protobuf 2.64.1, ringrtc 2.64.1, regex-aot 0.1.0, partial-default-derive 0.1.0, partial-default 0.1.0 ``` GNU AFFERO GENERAL PUBLIC LICENSE diff --git a/acknowledgments/acknowledgments.plist b/acknowledgments/acknowledgments.plist index fda3761c..2925ba18 100644 --- a/acknowledgments/acknowledgments.plist +++ b/acknowledgments/acknowledgments.plist @@ -924,7 +924,7 @@ You should also get your employer (if you work as a programmer) or school, if an License GNU Affero General Public License v3.0 only Title - libsignal-account-keys 0.1.0, libsignal-core 0.1.0, mrp 2.64.0, protobuf 2.64.0, ringrtc 2.64.0, regex-aot 0.1.0, partial-default-derive 0.1.0, partial-default 0.1.0 + libsignal-account-keys 0.1.0, libsignal-core 0.1.0, mrp 2.64.1, protobuf 2.64.1, ringrtc 2.64.1, regex-aot 0.1.0, partial-default-derive 0.1.0, partial-default 0.1.0 Type PSGroupSpecifier diff --git a/call_sim/docker/signaling_server/Cargo.lock b/call_sim/docker/signaling_server/Cargo.lock index 0dce2d41..63f25b35 100644 --- a/call_sim/docker/signaling_server/Cargo.lock +++ b/call_sim/docker/signaling_server/Cargo.lock @@ -662,7 +662,7 @@ dependencies = [ [[package]] name = "protobuf" -version = "2.64.0" +version = "2.64.1" dependencies = [ "prost-build", "tonic-prost-build", diff --git a/config/version.properties b/config/version.properties index 3f1e622a..e9d46b8f 100644 --- a/config/version.properties +++ b/config/version.properties @@ -2,4 +2,4 @@ webrtc.version=7444f ringrtc.version.major=2 ringrtc.version.minor=64 -ringrtc.version.revision=0 +ringrtc.version.revision=1 diff --git a/src/node/package-lock.json b/src/node/package-lock.json index a888eb0d..b3eb8948 100644 --- a/src/node/package-lock.json +++ b/src/node/package-lock.json @@ -1,12 +1,12 @@ { "name": "@signalapp/ringrtc", - "version": "2.64.0", + "version": "2.64.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@signalapp/ringrtc", - "version": "2.64.0", + "version": "2.64.1", "hasInstallScript": true, "license": "AGPL-3.0-only", "dependencies": { diff --git a/src/node/package.json b/src/node/package.json index 087b4ffa..719199cb 100644 --- a/src/node/package.json +++ b/src/node/package.json @@ -1,6 +1,6 @@ { "name": "@signalapp/ringrtc", - "version": "2.64.0", + "version": "2.64.1", "repository": { "type": "git", "url": "https://github.com/signalapp/ringrtc.git",