diff --git a/examples/androidapp/src/org/appspot/apprtc/PeerConnectionClient.java b/examples/androidapp/src/org/appspot/apprtc/PeerConnectionClient.java index b4e065b806..1602c9b27b 100644 --- a/examples/androidapp/src/org/appspot/apprtc/PeerConnectionClient.java +++ b/examples/androidapp/src/org/appspot/apprtc/PeerConnectionClient.java @@ -40,6 +40,7 @@ import org.appspot.apprtc.RecordedAudioToFileController; import org.webrtc.AudioSource; import org.webrtc.AudioTrack; import org.webrtc.CameraVideoCapturer; +import org.webrtc.CandidatePairChangeEvent; import org.webrtc.DataChannel; import org.webrtc.DefaultVideoDecoderFactory; import org.webrtc.DefaultVideoEncoderFactory; @@ -1214,6 +1215,11 @@ public class PeerConnectionClient { Log.d(TAG, "IceConnectionReceiving changed to " + receiving); } + @Override + public void onSelectedCandidatePairChanged(CandidatePairChangeEvent event) { + Log.d(TAG, "Selected candidate pair changed because: " + event); + } + @Override public void onAddStream(final MediaStream stream) {} diff --git a/examples/objc/AppRTCMobile/ARDAppClient.m b/examples/objc/AppRTCMobile/ARDAppClient.m index 8b3d105797..ab1e088628 100644 --- a/examples/objc/AppRTCMobile/ARDAppClient.m +++ b/examples/objc/AppRTCMobile/ARDAppClient.m @@ -433,6 +433,14 @@ static int const kKbpsMultiplier = 1000; }); } +- (void)peerConnection:(RTCPeerConnection *)peerConnection + didChangeLocalCandidate:(RTCIceCandidate *)local + didChangeRemoteCandidate:(RTCIceCandidate *)remote + lastReceivedMs:(int)lastDataReceivedMs + didHaveReason:(NSString *)reason { + RTCLog(@"ICE candidate pair changed because: %@", reason); +} + - (void)peerConnection:(RTCPeerConnection *)peerConnection didOpenDataChannel:(RTCDataChannel *)dataChannel { } diff --git a/pc/peer_connection_integrationtest.cc b/pc/peer_connection_integrationtest.cc index 78263b7ca4..59bfb0483a 100644 --- a/pc/peer_connection_integrationtest.cc +++ b/pc/peer_connection_integrationtest.cc @@ -940,6 +940,7 @@ class PeerConnectionWrapper : public webrtc::PeerConnectionObserver, const cricket::CandidatePairChangeEvent& event) { ice_candidate_pair_change_history_.push_back(event); } + void OnIceCandidate(const webrtc::IceCandidateInterface* candidate) override { RTC_LOG(LS_INFO) << debug_name_ << ": OnIceCandidate"; diff --git a/sdk/android/BUILD.gn b/sdk/android/BUILD.gn index 830978ab10..0eca65f7e8 100644 --- a/sdk/android/BUILD.gn +++ b/sdk/android/BUILD.gn @@ -266,6 +266,7 @@ if (is_android) { "api/org/webrtc/AudioSource.java", "api/org/webrtc/AudioTrack.java", "api/org/webrtc/CallSessionFileRotatingLogSink.java", + "api/org/webrtc/CandidatePairChangeEvent.java", "api/org/webrtc/CryptoOptions.java", "api/org/webrtc/DataChannel.java", "api/org/webrtc/DtmfSender.java", @@ -1263,6 +1264,7 @@ if (current_os == "linux" || is_android) { sources = [ "api/org/webrtc/AudioTrack.java", "api/org/webrtc/CallSessionFileRotatingLogSink.java", + "api/org/webrtc/CandidatePairChangeEvent.java", "api/org/webrtc/CryptoOptions.java", "api/org/webrtc/DataChannel.java", "api/org/webrtc/DtmfSender.java", diff --git a/sdk/android/api/org/webrtc/CandidatePairChangeEvent.java b/sdk/android/api/org/webrtc/CandidatePairChangeEvent.java new file mode 100644 index 0000000000..395b629c54 --- /dev/null +++ b/sdk/android/api/org/webrtc/CandidatePairChangeEvent.java @@ -0,0 +1,31 @@ +/* + * Copyright 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +package org.webrtc; + +/** + * Representation of a change in selected ICE candidate pair. + * {@code CandidatePairChangeEvent} in the C++ API. + */ +public final class CandidatePairChangeEvent { + public final IceCandidate local; + public final IceCandidate remote; + public final int lastDataReceivedMs; + public final String reason; + + @CalledByNative + CandidatePairChangeEvent( + IceCandidate local, IceCandidate remote, int lastDataReceivedMs, String reason) { + this.local = local; + this.remote = remote; + this.lastDataReceivedMs = lastDataReceivedMs; + this.reason = reason; + } +} diff --git a/sdk/android/api/org/webrtc/PeerConnection.java b/sdk/android/api/org/webrtc/PeerConnection.java index a44969d99a..a5eeb58c63 100644 --- a/sdk/android/api/org/webrtc/PeerConnection.java +++ b/sdk/android/api/org/webrtc/PeerConnection.java @@ -15,6 +15,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; +import org.webrtc.CandidatePairChangeEvent; import org.webrtc.DataChannel; import org.webrtc.MediaStreamTrack; import org.webrtc.RtpTransceiver; @@ -118,6 +119,10 @@ public class PeerConnection { /** Triggered when some ICE candidates have been removed. */ @CalledByNative("Observer") void onIceCandidatesRemoved(IceCandidate[] candidates); + /** Triggered when the ICE candidate pair is changed. */ + @CalledByNative("Observer") + default void onSelectedCandidatePairChanged(CandidatePairChangeEvent event) {} + /** Triggered when media is received on a new stream from remote peer. */ @CalledByNative("Observer") void onAddStream(MediaStream stream); diff --git a/sdk/android/instrumentationtests/src/org/webrtc/PeerConnectionTest.java b/sdk/android/instrumentationtests/src/org/webrtc/PeerConnectionTest.java index 3836f5057f..ef6f308043 100644 --- a/sdk/android/instrumentationtests/src/org/webrtc/PeerConnectionTest.java +++ b/sdk/android/instrumentationtests/src/org/webrtc/PeerConnectionTest.java @@ -143,6 +143,9 @@ public class PeerConnectionTest { @Override public void onIceCandidatesRemoved(IceCandidate[] candidates) {} + @Override + public void onSelectedCandidatePairChanged(CandidatePairChangeEvent event) {} + // TODO(bugs.webrtc.org/8491): Remove NoSynchronizedMethodCheck suppression. @SuppressWarnings("NoSynchronizedMethodCheck") public synchronized void setExpectedResolution(int width, int height) { diff --git a/sdk/android/src/jni/pc/peer_connection.cc b/sdk/android/src/jni/pc/peer_connection.cc index ee43b258ee..d6290c5df0 100644 --- a/sdk/android/src/jni/pc/peer_connection.cc +++ b/sdk/android/src/jni/pc/peer_connection.cc @@ -41,6 +41,7 @@ #include "rtc_base/checks.h" #include "rtc_base/logging.h" #include "rtc_base/numerics/safe_conversions.h" +#include "sdk/android/generated_peerconnection_jni/CandidatePairChangeEvent_jni.h" #include "sdk/android/generated_peerconnection_jni/PeerConnection_jni.h" #include "sdk/android/native_api/jni/java_types.h" #include "sdk/android/src/jni/jni_helpers.h" @@ -120,6 +121,16 @@ SdpSemantics JavaToNativeSdpSemantics(JNIEnv* jni, return SdpSemantics::kPlanB; } +ScopedJavaLocalRef NativeToJavaCandidatePairChange( + JNIEnv* env, + const cricket::CandidatePairChangeEvent& event) { + return Java_CandidatePairChangeEvent_Constructor( + env, NativeToJavaCandidate(env, event.local_candidate), + NativeToJavaCandidate(env, event.remote_candidate), + static_cast(event.last_data_received_ms), + NativeToJavaString(env, event.reason)); +} + } // namespace void JavaToNativeRTCConfiguration( @@ -325,6 +336,13 @@ void PeerConnectionObserverJni::OnIceConnectionReceivingChange(bool receiving) { receiving); } +void PeerConnectionObserverJni::OnIceSelectedCandidatePairChanged( + const cricket::CandidatePairChangeEvent& event) { + JNIEnv* env = AttachCurrentThreadIfNeeded(); + Java_Observer_onSelectedCandidatePairChanged( + env, j_observer_global_, NativeToJavaCandidatePairChange(env, event)); +} + void PeerConnectionObserverJni::OnIceGatheringChange( PeerConnectionInterface::IceGatheringState new_state) { JNIEnv* env = AttachCurrentThreadIfNeeded(); diff --git a/sdk/android/src/jni/pc/peer_connection.h b/sdk/android/src/jni/pc/peer_connection.h index 884ce7c9b6..c6db49a427 100644 --- a/sdk/android/src/jni/pc/peer_connection.h +++ b/sdk/android/src/jni/pc/peer_connection.h @@ -58,6 +58,8 @@ class PeerConnectionObserverJni : public PeerConnectionObserver { void OnIceConnectionReceivingChange(bool receiving) override; void OnIceGatheringChange( PeerConnectionInterface::IceGatheringState new_state) override; + void OnIceSelectedCandidatePairChanged( + const cricket::CandidatePairChangeEvent& event) override; void OnAddStream(rtc::scoped_refptr stream) override; void OnRemoveStream(rtc::scoped_refptr stream) override; void OnDataChannel(rtc::scoped_refptr channel) override; diff --git a/sdk/objc/api/peerconnection/RTCPeerConnection+Private.h b/sdk/objc/api/peerconnection/RTCPeerConnection+Private.h index b2c6ba892d..ce08cd5f6a 100644 --- a/sdk/objc/api/peerconnection/RTCPeerConnection+Private.h +++ b/sdk/objc/api/peerconnection/RTCPeerConnection+Private.h @@ -50,6 +50,8 @@ class PeerConnectionDelegateAdapter : public PeerConnectionObserver { void OnIceCandidatesRemoved(const std::vector &candidates) override; + void OnIceSelectedCandidatePairChanged(const cricket::CandidatePairChangeEvent &event) override; + void OnAddTrack(rtc::scoped_refptr receiver, const std::vector> &streams) override; diff --git a/sdk/objc/api/peerconnection/RTCPeerConnection.h b/sdk/objc/api/peerconnection/RTCPeerConnection.h index 6956555ce3..012295c241 100644 --- a/sdk/objc/api/peerconnection/RTCPeerConnection.h +++ b/sdk/objc/api/peerconnection/RTCPeerConnection.h @@ -147,6 +147,13 @@ RTC_OBJC_EXPORT - (void)peerConnection:(RTCPeerConnection *)peerConnection didRemoveReceiver:(RTCRtpReceiver *)rtpReceiver; +/** Called when the selected ICE candidate pair is changed. */ +- (void)peerConnection:(RTCPeerConnection *)peerConnection + didChangeLocalCandidate:(RTCIceCandidate *)local + remoteCandidate:(RTCIceCandidate *)remote + lastReceivedMs:(int)lastDataReceivedMs + changeReason:(NSString *)reason; + @end RTC_OBJC_EXPORT diff --git a/sdk/objc/api/peerconnection/RTCPeerConnection.mm b/sdk/objc/api/peerconnection/RTCPeerConnection.mm index 659e1f379e..a66d187840 100644 --- a/sdk/objc/api/peerconnection/RTCPeerConnection.mm +++ b/sdk/objc/api/peerconnection/RTCPeerConnection.mm @@ -233,20 +233,43 @@ void PeerConnectionDelegateAdapter::OnIceCandidatesRemoved( didRemoveIceCandidates:ice_candidates]; } +void PeerConnectionDelegateAdapter::OnIceSelectedCandidatePairChanged( + const cricket::CandidatePairChangeEvent &event) { + std::unique_ptr local_candidate_wrapper( + new JsepIceCandidate(event.local_candidate.transport_name(), -1, event.local_candidate)); + RTCIceCandidate *local_candidate = + [[RTCIceCandidate alloc] initWithNativeCandidate:local_candidate_wrapper.get()]; + std::unique_ptr remote_candidate_wrapper( + new JsepIceCandidate(event.remote_candidate.transport_name(), -1, event.remote_candidate)); + RTCIceCandidate *remote_candidate = + [[RTCIceCandidate alloc] initWithNativeCandidate:remote_candidate_wrapper.get()]; + RTCPeerConnection *peer_connection = peer_connection_; + NSString *nsstr_reason = [NSString stringForStdString:event.reason]; + if ([peer_connection.delegate + respondsToSelector:@selector + (peerConnection:didChangeLocalCandidate:remoteCandidate:lastReceivedMs:changeReason:)]) { + [peer_connection.delegate peerConnection:peer_connection + didChangeLocalCandidate:local_candidate + remoteCandidate:remote_candidate + lastReceivedMs:event.last_data_received_ms + changeReason:nsstr_reason]; + } +} + void PeerConnectionDelegateAdapter::OnAddTrack( rtc::scoped_refptr receiver, - const std::vector>& streams) { + const std::vector> &streams) { RTCPeerConnection *peer_connection = peer_connection_; - if ([peer_connection.delegate - respondsToSelector:@selector(peerConnection:didAddReceiver:streams:)]) { + if ([peer_connection.delegate respondsToSelector:@selector(peerConnection: + didAddReceiver:streams:)]) { NSMutableArray *mediaStreams = [NSMutableArray arrayWithCapacity:streams.size()]; - for (const auto& nativeStream : streams) { + for (const auto &nativeStream : streams) { RTCMediaStream *mediaStream = [[RTCMediaStream alloc] initWithFactory:peer_connection.factory nativeMediaStream:nativeStream]; [mediaStreams addObject:mediaStream]; } - RTCRtpReceiver *rtpReceiver = - [[RTCRtpReceiver alloc] initWithFactory:peer_connection.factory nativeRtpReceiver:receiver]; + RTCRtpReceiver *rtpReceiver = [[RTCRtpReceiver alloc] initWithFactory:peer_connection.factory + nativeRtpReceiver:receiver]; [peer_connection.delegate peerConnection:peer_connection didAddReceiver:rtpReceiver @@ -258,15 +281,14 @@ void PeerConnectionDelegateAdapter::OnRemoveTrack( rtc::scoped_refptr receiver) { RTCPeerConnection *peer_connection = peer_connection_; if ([peer_connection.delegate respondsToSelector:@selector(peerConnection:didRemoveReceiver:)]) { - RTCRtpReceiver *rtpReceiver = - [[RTCRtpReceiver alloc] initWithFactory:peer_connection.factory nativeRtpReceiver:receiver]; + RTCRtpReceiver *rtpReceiver = [[RTCRtpReceiver alloc] initWithFactory:peer_connection.factory + nativeRtpReceiver:receiver]; [peer_connection.delegate peerConnection:peer_connection didRemoveReceiver:rtpReceiver]; } } } // namespace webrtc - @implementation RTCPeerConnection { RTCPeerConnectionFactory *_factory; NSMutableArray *_localStreams;