diff --git a/bin/fetch-artifact.py b/bin/fetch-artifact.py index 04de8a42..2580f14d 100755 --- a/bin/fetch-artifact.py +++ b/bin/fetch-artifact.py @@ -18,14 +18,14 @@ UNVERIFIED_DOWNLOAD_NAME = "unverified.tmp" PREBUILD_CHECKSUMS = { - 'android': '49d569a1e69630f6fcb5374079a0f04c986f407daf24da9039e7444fc3b601fe', - 'ios': '0c3274547678276b0cf38ee715d73072c2b39e8114ebddf860976d3de63eaa45', - 'linux-arm64': '098a6e95f93e0272035249969df004b7ae5cceb0433c90d40b3e3da9d1d6f4cb', - 'linux-x64': '51c8579c2ea85fb63260b857fc58f771a3a3443ecbcebf2ac1c85532852cf978', - 'mac-arm64': 'a877715351f209e99478e9b5fec5a9c152eb2f18243a8cda0e9485f0140ede61', - 'mac-x64': '52cc7d43e756738af5eb75cda5497028eb1e47ff67170d244c2cea2f034f5061', - 'windows-arm64': '38b44c233cb518dd13a990dffd97efed9691c05df5c2c0b64471af7576bc5304', - 'windows-x64': '94266f6bbe7d2331f330276e08cc7a04039a22507bab6ef76c559b6a8f22b696', + 'android': '96d57094ac762aa4ab50e19eae623c77bbb2eb02504b4ddb3717a0a396f7ceea', + 'ios': 'bef1c186ea5522dc8a6d3c025a53efe210f55673e3cd09e125ca811da67a3f50', + 'linux-arm64': '652498b7bdbd2f764535d9c4763c9a752f3ce904109e327596369f1bb6c922dc', + 'linux-x64': 'cc34122e83b7218f58e9857747321925f91bc9b696bf72cfad8cd6d5258d371b', + 'mac-arm64': '47142365fc812364ffd31827315b489e1c6b287475e5597e792a0b7296d6e04d', + 'mac-x64': 'aa0382331b702ca0d770899e3ddc3f052880eb22f6dfd6e34abb1fb727c896b5', + 'windows-arm64': 'a401bd83505bf18a2b56cc48cf42e1783e1221fd89cb60fb63caf44d56293c11', + 'windows-x64': '6a5535d1a751c7ed231d6170af42d0c74000d53da79b3ea91da44d7f33565644', } diff --git a/call_sim/src/common.rs b/call_sim/src/common.rs index a0da3683..40367738 100644 --- a/call_sim/src/common.rs +++ b/call_sim/src/common.rs @@ -295,7 +295,10 @@ impl Default for CallConfig { relay_password: "test".to_string(), force_relay: false, // By default, all tests will disable the ANY port allocator setting. - field_trials: vec!["RingRTC-AnyAddressPortsKillSwitch/Enabled".to_string()], + field_trials: vec![ + "RingRTC-AnyAddressPortsKillSwitch/Enabled".to_string(), + "RingRTC-PruneTurnPorts/Enabled".to_string(), + ], extra_cli_args: vec![], stats_interval_secs: 1, stats_initial_offset_secs: 0, diff --git a/config/version.properties b/config/version.properties index 909bd2d0..3e8d81a9 100644 --- a/config/version.properties +++ b/config/version.properties @@ -1,4 +1,4 @@ -webrtc.version=6099b +webrtc.version=6099c ringrtc.version.major=2 ringrtc.version.minor=37 diff --git a/src/android/api/org/signal/ringrtc/CallManager.java b/src/android/api/org/signal/ringrtc/CallManager.java index 4f48410b..7a8419d3 100644 --- a/src/android/api/org/signal/ringrtc/CallManager.java +++ b/src/android/api/org/signal/ringrtc/CallManager.java @@ -103,6 +103,7 @@ public static void initialize(Context applicationContext, Log.Logger logger, Map Map fieldTrialsWithDefaults = new HashMap<>(); fieldTrialsWithDefaults.put("WebRTC-Audio-OpusSetSignalVoiceWithDtx", "Enabled"); + fieldTrialsWithDefaults.put("RingRTC-PruneTurnPorts", "Enabled"); fieldTrialsWithDefaults.putAll(fieldTrials); String fieldTrialsString = buildFieldTrialsString(fieldTrialsWithDefaults); diff --git a/src/ios/SignalRingRTC/SignalRingRTC/CallManagerGlobal.swift b/src/ios/SignalRingRTC/SignalRingRTC/CallManagerGlobal.swift index 14e5a725..23d8be7f 100644 --- a/src/ios/SignalRingRTC/SignalRingRTC/CallManagerGlobal.swift +++ b/src/ios/SignalRingRTC/SignalRingRTC/CallManagerGlobal.swift @@ -93,6 +93,7 @@ public class CallManagerGlobal { let fieldTrialsWithDefaults = fieldTrials.merging([ "RingRTC-AnyAddressPortsKillSwitch": "Enabled", "WebRTC-Audio-OpusSetSignalVoiceWithDtx": "Enabled", + "RingRTC-PruneTurnPorts": "Enabled", ]) { (provided, _) in provided } RTCInitFieldTrialDictionary(fieldTrialsWithDefaults) Logger.info("Initialized field trials with \(fieldTrialsWithDefaults)") diff --git a/src/node/ringrtc/Service.ts b/src/node/ringrtc/Service.ts index 26134407..8acdc1af 100644 --- a/src/node/ringrtc/Service.ts +++ b/src/node/ringrtc/Service.ts @@ -45,6 +45,7 @@ class NativeCallManager { { 'RingRTC-AnyAddressPortsKillSwitch': 'Enabled', 'WebRTC-Audio-OpusSetSignalVoiceWithDtx': 'Enabled', + 'RingRTC-PruneTurnPorts': 'Enabled', }, config.field_trials ); @@ -516,10 +517,7 @@ export class RingRTCType { sillyDeadlockProtection(() => { this.callManager.proceed( callId, - settings.iceServer.username || '', - settings.iceServer.password || '', - settings.iceServer.hostname || '', - settings.iceServer.urls, + settings.iceServers, settings.hideIp, settings.dataMode, settings.audioLevelsIntervalMillis || 0 @@ -1755,7 +1753,7 @@ export class RingRTCType { } export interface CallSettings { - iceServer: IceServer; + iceServers: Array; hideIp: boolean; dataMode: DataMode; audioLevelsIntervalMillis?: number; @@ -1764,6 +1762,7 @@ export interface CallSettings { interface IceServer { username?: string; password?: string; + /** Provide hostname when urls contain IP addresses instead of hostname */ hostname?: string; urls: Array; } @@ -2710,10 +2709,7 @@ export interface CallManager { ): CallId; proceed( callId: CallId, - iceServerUsername: string, - iceServerPassword: string, - iceServerHostname: string, - iceServerUrls: Array, + iceServers: Array, hideIp: boolean, dataMode: DataMode, audioLevelsIntervalMillis: number diff --git a/src/node/test/CallingClass.ts b/src/node/test/CallingClass.ts index 8791a86e..5436f270 100644 --- a/src/node/test/CallingClass.ts +++ b/src/node/test/CallingClass.ts @@ -191,9 +191,20 @@ export class CallingClass { } return { - iceServer: { - urls: ['stun:turn3.voip.signal.org'], - }, + iceServers: [ + { + hostname: '', + username: 'name', + password: 'pass', + urls: ['stun:turn3.voip.signal.org'], + }, + { + hostname: 'example.org', + username: 'name', + password: 'pass', + urls: ['stun:123.123.123.1'], + }, + ], hideIp: false, dataMode: DataMode.Normal, }; diff --git a/src/rust/src/bin/call_sim-cli/endpoint.rs b/src/rust/src/bin/call_sim-cli/endpoint.rs index bd67c8ed..e7450e48 100644 --- a/src/rust/src/bin/call_sim-cli/endpoint.rs +++ b/src/rust/src/bin/call_sim-cli/endpoint.rs @@ -103,7 +103,7 @@ impl CallEndpoint { let peer_id = PeerId::from(peer_id); // To send across threads - let ice_server = ice_server.clone(); + let ice_servers = vec![ice_server.clone()]; Ok(Self::from_actor( peer_id.clone(), @@ -158,7 +158,7 @@ impl CallEndpoint { pcf.create_outgoing_video_track(&outgoing_video_source)?; let call_context = NativeCallContext::new( hide_ip, - ice_server, + ice_servers, outgoing_audio_track, outgoing_video_track, incoming_video_sink.unwrap_or_else(|| { diff --git a/src/rust/src/core/group_call.rs b/src/rust/src/core/group_call.rs index e1af47d7..4279eaff 100644 --- a/src/rust/src/core/group_call.rs +++ b/src/rust/src/core/group_call.rs @@ -46,7 +46,7 @@ use crate::{ AudioEncoderConfig, AudioTrack, VideoFrame, VideoFrameMetadata, VideoSink, VideoTrack, }, peer_connection::{AudioLevel, PeerConnection, ReceivedAudioLevel, SendRates}, - peer_connection_factory::{self as pcf, IceServer, PeerConnectionFactory}, + peer_connection_factory::{self as pcf, PeerConnectionFactory}, peer_connection_observer::{ IceConnectionState, NetworkRoute, PeerConnectionObserver, PeerConnectionObserverTrait, }, @@ -1119,7 +1119,7 @@ impl Client { let audio_jitter_buffer_max_packets = 50; let audio_jitter_buffer_max_target_delay_ms = 500; let audio_rtcp_report_interval_ms = 5000; - let ice_server = IceServer::none(); + let ice_servers = vec![]; let peer_connection = peer_connection_factory .create_peer_connection( peer_connection_observer, @@ -1127,7 +1127,7 @@ impl Client { audio_jitter_buffer_max_packets, audio_jitter_buffer_max_target_delay_ms, audio_rtcp_report_interval_ms, - &ice_server, + &ice_servers, outgoing_audio_track, outgoing_video_track, ) diff --git a/src/rust/src/electron.rs b/src/rust/src/electron.rs index ee04ce22..367373aa 100644 --- a/src/rust/src/electron.rs +++ b/src/rust/src/electron.rs @@ -733,33 +733,40 @@ fn cancelGroupRing(mut cx: FunctionContext) -> JsResult { #[allow(non_snake_case)] fn proceed(mut cx: FunctionContext) -> JsResult { let call_id = CallId::new(get_id_arg(&mut cx, 0)); - let ice_server_username = cx.argument::(1)?.value(&mut cx); - let ice_server_password = cx.argument::(2)?.value(&mut cx); - let ice_server_hostname = cx.argument::(3)?.value(&mut cx); - let js_ice_server_urls = cx.argument::(4)?; - let hide_ip = cx.argument::(5)?.value(&mut cx); - let data_mode = cx.argument::(6)?.value(&mut cx) as i32; - let audio_levels_interval_millis = cx.argument::(7)?.value(&mut cx) as u64; - - let mut ice_server_urls = Vec::with_capacity(js_ice_server_urls.len(&mut cx) as usize); - for i in 0..js_ice_server_urls.len(&mut cx) { - let url: String = js_ice_server_urls - .get::(&mut cx, i)? - .value(&mut cx); - ice_server_urls.push(url); - } + let js_ice_servers = cx.argument::(1)?; + let hide_ip = cx.argument::(2)?.value(&mut cx); + let data_mode = cx.argument::(3)?.value(&mut cx) as i32; + let audio_levels_interval_millis = cx.argument::(4)?.value(&mut cx) as u64; info!("proceed(): callId: {}, hideIp: {}", call_id, hide_ip); - for ice_server_url in &ice_server_urls { - info!(" server: {}", ice_server_url); - } + let mut ice_servers = Vec::new(); + for i in 0..js_ice_servers.len(&mut cx) { + let obj = js_ice_servers.get::(&mut cx, i)?; + let username = obj + .get::(&mut cx, "username") + .map_or("".to_string(), |handle| handle.value(&mut cx)); + let password: String = obj + .get::(&mut cx, "password") + .map_or("".to_string(), |handle| handle.value(&mut cx)); + let hostname = obj + .get::(&mut cx, "hostname") + .map_or("".to_string(), |handle| handle.value(&mut cx)); + let js_ice_server_urls = obj + .get_opt::(&mut cx, "urls")? + .expect("ice urls"); + + let mut ice_server_urls = Vec::with_capacity(js_ice_server_urls.len(&mut cx) as usize); + for i in 0..js_ice_server_urls.len(&mut cx) { + let url: String = js_ice_server_urls + .get::(&mut cx, i)? + .value(&mut cx); + info!(" server: {}", url); + ice_server_urls.push(url); + } - let ice_server = IceServer::new( - ice_server_username, - ice_server_password, - ice_server_hostname, - ice_server_urls, - ); + let ice_server = IceServer::new(username, password, hostname, ice_server_urls); + ice_servers.push(ice_server); + } let audio_levels_interval = if audio_levels_interval_millis == 0 { None @@ -770,7 +777,7 @@ fn proceed(mut cx: FunctionContext) -> JsResult { with_call_endpoint(&mut cx, |endpoint| { let call_context = NativeCallContext::new( hide_ip, - ice_server, + ice_servers, endpoint.outgoing_audio_track.clone(), endpoint.outgoing_video_track.clone(), endpoint.incoming_video_sink.clone(), diff --git a/src/rust/src/native.rs b/src/rust/src/native.rs index db66cb2a..9c0b1c50 100644 --- a/src/rust/src/native.rs +++ b/src/rust/src/native.rs @@ -35,7 +35,7 @@ use crate::webrtc::peer_connection_observer::{NetworkRoute, PeerConnectionObserv #[derive(Clone)] pub struct NativeCallContext { hide_ip: bool, - ice_server: IceServer, + ice_servers: Vec, outgoing_audio_track: AudioTrack, outgoing_video_track: VideoTrack, incoming_video_sink: Box, @@ -44,14 +44,14 @@ pub struct NativeCallContext { impl NativeCallContext { pub fn new( hide_ip: bool, - ice_server: IceServer, + ice_servers: Vec, outgoing_audio_track: AudioTrack, outgoing_video_track: VideoTrack, incoming_video_sink: Box, ) -> Self { Self { hide_ip, - ice_server, + ice_servers, outgoing_audio_track, outgoing_video_track, incoming_video_sink, @@ -455,7 +455,7 @@ impl Platform for NativePlatform { .call_config() .audio_jitter_buffer_max_target_delay_ms, connection.call_config().audio_rtcp_report_interval_ms, - &context.ice_server, + &context.ice_servers, context.outgoing_audio_track.clone(), Some(context.outgoing_video_track.clone()), )?; diff --git a/src/rust/src/webrtc/ffi/peer_connection_factory.rs b/src/rust/src/webrtc/ffi/peer_connection_factory.rs index a853940f..dd314248 100644 --- a/src/rust/src/webrtc/ffi/peer_connection_factory.rs +++ b/src/rust/src/webrtc/ffi/peer_connection_factory.rs @@ -10,7 +10,7 @@ use crate::webrtc::ffi::peer_connection_observer::RffiPeerConnectionObserver; #[cfg(feature = "injectable_network")] use crate::webrtc::injectable_network::RffiInjectableNetwork; use crate::webrtc::peer_connection_factory::{ - RffiAudioConfig, RffiIceServer, RffiPeerConnectionKind, + RffiAudioConfig, RffiIceServers, RffiPeerConnectionKind, }; #[cfg(feature = "native")] use std::os::raw::c_char; @@ -64,7 +64,7 @@ extern "C" { audio_jitter_buffer_max_packets: isize, audio_jitter_buffer_max_target_delay_ms: isize, audio_rtcp_report_interval_ms: isize, - ice_server: RffiIceServer, + ice_servers: RffiIceServers, outgoing_audio_track: webrtc::ptr::BorrowedRc, outgoing_video_track: webrtc::ptr::BorrowedRc, ) -> webrtc::ptr::OwnedRc; diff --git a/src/rust/src/webrtc/peer_connection_factory.rs b/src/rust/src/webrtc/peer_connection_factory.rs index e0785130..ac4589f2 100644 --- a/src/rust/src/webrtc/peer_connection_factory.rs +++ b/src/rust/src/webrtc/peer_connection_factory.rs @@ -105,6 +105,12 @@ impl IceServer { } } +#[repr(C)] +pub struct RffiIceServers { + servers: webrtc::ptr::Borrowed, + servers_size: usize, +} + /// Describes an audio input or output device. #[derive(Clone, Debug, PartialEq, Eq)] pub struct AudioDevice { @@ -272,7 +278,7 @@ impl PeerConnectionFactory { audio_jitter_buffer_max_packets: isize, audio_jitter_buffer_max_target_delay_ms: isize, audio_rtcp_report_interval_ms: isize, - ice_servers: &IceServer, + ice_servers: &[IceServer], outgoing_audio_track: AudioTrack, outgoing_video_track: Option, ) -> Result { @@ -288,6 +294,11 @@ impl PeerConnectionFactory { // we do this by passing a webrtc::ptr::Unique to // the Rust-level PeerConnection and let it own it. let pc_observer_rffi = pc_observer.into_rffi(); + let servers: Vec = ice_servers.iter().map(|s| s.rffi()).collect(); + let rffi_ice_servers = RffiIceServers { + servers: webrtc::ptr::Borrowed::from_ptr(servers.as_ptr()), + servers_size: servers.len(), + }; let rffi = webrtc::Arc::from_owned(unsafe { pcf::Rust_createPeerConnection( @@ -297,7 +308,7 @@ impl PeerConnectionFactory { audio_jitter_buffer_max_packets, audio_jitter_buffer_max_target_delay_ms, audio_rtcp_report_interval_ms, - ice_servers.rffi(), + rffi_ice_servers, outgoing_audio_track.rffi().as_borrowed(), outgoing_video_track .map_or_else(webrtc::ptr::BorrowedRc::null, |outgoing_video_track| { diff --git a/src/rust/src/webrtc/sim/peer_connection_factory.rs b/src/rust/src/webrtc/sim/peer_connection_factory.rs index 0f317457..7e2ebed7 100644 --- a/src/rust/src/webrtc/sim/peer_connection_factory.rs +++ b/src/rust/src/webrtc/sim/peer_connection_factory.rs @@ -5,7 +5,7 @@ use crate::webrtc; use crate::webrtc::peer_connection_factory::{ - RffiAudioConfig, RffiIceServer, RffiPeerConnectionKind, + RffiAudioConfig, RffiIceServers, RffiPeerConnectionKind, }; use crate::webrtc::sim::media::{ RffiAudioTrack, RffiVideoSource, RffiVideoTrack, FAKE_AUDIO_TRACK, FAKE_VIDEO_SOURCE, @@ -51,7 +51,7 @@ pub unsafe fn Rust_createPeerConnection( _audio_jitter_buffer_max_packets: isize, _audio_jitter_buffer_max_target_delay_ms: isize, _audio_rtcp_report_interval_ms: isize, - _ice_server: RffiIceServer, + _ice_servers: RffiIceServers, _outgoing_audio_track: webrtc::ptr::BorrowedRc, _outgoing_video_track: webrtc::ptr::BorrowedRc, ) -> webrtc::ptr::OwnedRc {