diff --git a/examples/androidapp/src/org/appspot/apprtc/PeerConnectionClient.java b/examples/androidapp/src/org/appspot/apprtc/PeerConnectionClient.java index 2bc75ff617..7bdce00b2f 100644 --- a/examples/androidapp/src/org/appspot/apprtc/PeerConnectionClient.java +++ b/examples/androidapp/src/org/appspot/apprtc/PeerConnectionClient.java @@ -46,6 +46,7 @@ import org.webrtc.DefaultVideoDecoderFactory; import org.webrtc.DefaultVideoEncoderFactory; import org.webrtc.EglBase; import org.webrtc.IceCandidate; +import org.webrtc.IceCandidateErrorEvent; import org.webrtc.Logging; import org.webrtc.MediaConstraints; import org.webrtc.MediaStream; @@ -1213,6 +1214,13 @@ public class PeerConnectionClient { executor.execute(() -> events.onIceCandidate(candidate)); } + @Override + public void onIceCandidateError(final IceCandidateErrorEvent event) { + Log.d(TAG, + "IceCandidateError address: " + event.address + ", port: " + event.port + ", url: " + + event.url + ", errorCode: " + event.errorCode + ", errorText: " + event.errorText); + } + @Override public void onIceCandidatesRemoved(final IceCandidate[] candidates) { executor.execute(() -> events.onIceCandidatesRemoved(candidates)); diff --git a/examples/objc/AppRTCMobile/ARDAppClient.m b/examples/objc/AppRTCMobile/ARDAppClient.m index 04e17ea07f..4420972598 100644 --- a/examples/objc/AppRTCMobile/ARDAppClient.m +++ b/examples/objc/AppRTCMobile/ARDAppClient.m @@ -13,6 +13,7 @@ #import "sdk/objc/api/peerconnection/RTCAudioTrack.h" #import "sdk/objc/api/peerconnection/RTCConfiguration.h" #import "sdk/objc/api/peerconnection/RTCFileLogger.h" +#import "sdk/objc/api/peerconnection/RTCIceCandidateErrorEvent.h" #import "sdk/objc/api/peerconnection/RTCIceServer.h" #import "sdk/objc/api/peerconnection/RTCMediaConstraints.h" #import "sdk/objc/api/peerconnection/RTCMediaStream.h" @@ -425,6 +426,17 @@ static int const kKbpsMultiplier = 1000; }); } +- (void)peerConnection:(RTC_OBJC_TYPE(RTCPeerConnection) *)peerConnection + didFailToGatherIceCandidate:(RTC_OBJC_TYPE(RTCIceCandidateErrorEvent) *)event { + RTCLog(@"Failed to gather ICE candidate. address: %@, port: %d, url: %@, errorCode: %d, " + @"errorText: %@", + event.address, + event.port, + event.url, + event.errorCode, + event.errorText); +} + - (void)peerConnection:(RTC_OBJC_TYPE(RTCPeerConnection) *)peerConnection didRemoveIceCandidates:(NSArray *)candidates { dispatch_async(dispatch_get_main_queue(), ^{ diff --git a/sdk/BUILD.gn b/sdk/BUILD.gn index 19e612e2d1..ff02e78cd6 100644 --- a/sdk/BUILD.gn +++ b/sdk/BUILD.gn @@ -890,6 +890,9 @@ if (is_ios || is_mac) { "objc/api/peerconnection/RTCIceCandidate+Private.h", "objc/api/peerconnection/RTCIceCandidate.h", "objc/api/peerconnection/RTCIceCandidate.mm", + "objc/api/peerconnection/RTCIceCandidateErrorEvent+Private.h", + "objc/api/peerconnection/RTCIceCandidateErrorEvent.h", + "objc/api/peerconnection/RTCIceCandidateErrorEvent.mm", "objc/api/peerconnection/RTCIceServer+Private.h", "objc/api/peerconnection/RTCIceServer.h", "objc/api/peerconnection/RTCIceServer.mm", @@ -1261,6 +1264,7 @@ if (is_ios || is_mac) { "objc/api/peerconnection/RTCDataChannelConfiguration.h", "objc/api/peerconnection/RTCFieldTrials.h", "objc/api/peerconnection/RTCIceCandidate.h", + "objc/api/peerconnection/RTCIceCandidateErrorEvent.h", "objc/api/peerconnection/RTCIceServer.h", "objc/api/peerconnection/RTCLegacyStatsReport.h", "objc/api/peerconnection/RTCMediaConstraints.h", @@ -1375,6 +1379,7 @@ if (is_ios || is_mac) { "objc/api/peerconnection/RTCDtmfSender.h", "objc/api/peerconnection/RTCFieldTrials.h", "objc/api/peerconnection/RTCIceCandidate.h", + "objc/api/peerconnection/RTCIceCandidateErrorEvent.h", "objc/api/peerconnection/RTCIceServer.h", "objc/api/peerconnection/RTCLegacyStatsReport.h", "objc/api/peerconnection/RTCMediaConstraints.h", diff --git a/sdk/android/BUILD.gn b/sdk/android/BUILD.gn index 20bee2b832..1532acfa64 100644 --- a/sdk/android/BUILD.gn +++ b/sdk/android/BUILD.gn @@ -263,6 +263,7 @@ if (is_android) { "api/org/webrtc/FrameDecryptor.java", "api/org/webrtc/FrameEncryptor.java", "api/org/webrtc/IceCandidate.java", + "api/org/webrtc/IceCandidateErrorEvent.java", "api/org/webrtc/MediaConstraints.java", "api/org/webrtc/MediaSource.java", "api/org/webrtc/MediaStream.java", @@ -1330,6 +1331,7 @@ if (current_os == "linux" || is_android) { "api/org/webrtc/DataChannel.java", "api/org/webrtc/DtmfSender.java", "api/org/webrtc/IceCandidate.java", + "api/org/webrtc/IceCandidateErrorEvent.java", "api/org/webrtc/MediaConstraints.java", "api/org/webrtc/MediaSource.java", "api/org/webrtc/MediaStream.java", diff --git a/sdk/android/api/org/webrtc/IceCandidateErrorEvent.java b/sdk/android/api/org/webrtc/IceCandidateErrorEvent.java new file mode 100644 index 0000000000..aae9da7061 --- /dev/null +++ b/sdk/android/api/org/webrtc/IceCandidateErrorEvent.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2021 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; + +public final class IceCandidateErrorEvent { + /** The local IP address used to communicate with the STUN or TURN server. */ + public final String address; + /** The port used to communicate with the STUN or TURN server. */ + public final int port; + /** + * The STUN or TURN URL that identifies the STUN or TURN server for which the failure occurred. + */ + public final String url; + /** + * The numeric STUN error code returned by the STUN or TURN server. If no host candidate can reach + * the server, errorCode will be set to the value 701 which is outside the STUN error code range. + * This error is only fired once per server URL while in the RTCIceGatheringState of "gathering". + */ + public final int errorCode; + /** + * The STUN reason text returned by the STUN or TURN server. If the server could not be reached, + * errorText will be set to an implementation-specific value providing details about the error. + */ + public final String errorText; + + @CalledByNative + public IceCandidateErrorEvent( + String address, int port, String url, int errorCode, String errorText) { + this.address = address; + this.port = port; + this.url = url; + this.errorCode = errorCode; + this.errorText = errorText; + } +} diff --git a/sdk/android/api/org/webrtc/PeerConnection.java b/sdk/android/api/org/webrtc/PeerConnection.java index 7ad72c4eb4..468413ba2f 100644 --- a/sdk/android/api/org/webrtc/PeerConnection.java +++ b/sdk/android/api/org/webrtc/PeerConnection.java @@ -118,6 +118,9 @@ public class PeerConnection { /** Triggered when a new ICE candidate has been found. */ @CalledByNative("Observer") void onIceCandidate(IceCandidate candidate); + /** Triggered when gathering of an ICE candidate failed. */ + default @CalledByNative("Observer") void onIceCandidateError(IceCandidateErrorEvent event) {} + /** Triggered when some ICE candidates have been removed. */ @CalledByNative("Observer") void onIceCandidatesRemoved(IceCandidate[] candidates); diff --git a/sdk/android/instrumentationtests/src/org/webrtc/PeerConnectionEndToEndTest.java b/sdk/android/instrumentationtests/src/org/webrtc/PeerConnectionEndToEndTest.java index 1281cbe137..d9799ab448 100644 --- a/sdk/android/instrumentationtests/src/org/webrtc/PeerConnectionEndToEndTest.java +++ b/sdk/android/instrumentationtests/src/org/webrtc/PeerConnectionEndToEndTest.java @@ -125,6 +125,9 @@ public class PeerConnectionEndToEndTest { } } + @Override + public void onIceCandidateError(IceCandidateErrorEvent event) {} + @Override public void onIceCandidatesRemoved(IceCandidate[] candidates) {} diff --git a/sdk/android/src/jni/pc/peer_connection.cc b/sdk/android/src/jni/pc/peer_connection.cc index 9c73b94000..143ad2bbc1 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/logging.h" #include "rtc_base/numerics/safe_conversions.h" #include "sdk/android/generated_peerconnection_jni/CandidatePairChangeEvent_jni.h" +#include "sdk/android/generated_peerconnection_jni/IceCandidateErrorEvent_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" @@ -306,6 +307,19 @@ void PeerConnectionObserverJni::OnIceCandidate( NativeToJavaIceCandidate(env, *candidate)); } +void PeerConnectionObserverJni::OnIceCandidateError( + const std::string& address, + int port, + const std::string& url, + int error_code, + const std::string& error_text) { + JNIEnv* env = AttachCurrentThreadIfNeeded(); + ScopedJavaLocalRef event = Java_IceCandidateErrorEvent_Constructor( + env, NativeToJavaString(env, address), port, NativeToJavaString(env, url), + error_code, NativeToJavaString(env, error_text)); + Java_Observer_onIceCandidateError(env, j_observer_global_, event); +} + void PeerConnectionObserverJni::OnIceCandidatesRemoved( const std::vector& candidates) { JNIEnv* env = AttachCurrentThreadIfNeeded(); diff --git a/sdk/android/src/jni/pc/peer_connection.h b/sdk/android/src/jni/pc/peer_connection.h index 86d99f31c4..9976e8e4f5 100644 --- a/sdk/android/src/jni/pc/peer_connection.h +++ b/sdk/android/src/jni/pc/peer_connection.h @@ -48,6 +48,12 @@ class PeerConnectionObserverJni : public PeerConnectionObserver { // Implementation of PeerConnectionObserver interface, which propagates // the callbacks to the Java observer. void OnIceCandidate(const IceCandidateInterface* candidate) override; + void OnIceCandidateError(const std::string& address, + int port, + const std::string& url, + int error_code, + const std::string& error_text) override; + void OnIceCandidatesRemoved( const std::vector& candidates) override; void OnSignalingChange( diff --git a/sdk/objc/api/peerconnection/RTCIceCandidateErrorEvent+Private.h b/sdk/objc/api/peerconnection/RTCIceCandidateErrorEvent+Private.h new file mode 100644 index 0000000000..8502da08a8 --- /dev/null +++ b/sdk/objc/api/peerconnection/RTCIceCandidateErrorEvent+Private.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2021 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. + */ + +#import "RTCIceCandidateErrorEvent.h" + +#include + +NS_ASSUME_NONNULL_BEGIN + +@interface RTC_OBJC_TYPE (RTCIceCandidateErrorEvent) +() + + - (instancetype)initWithAddress : (const std::string&)address port : (const int)port url + : (const std::string&)url errorCode : (const int)errorCode errorText + : (const std::string&)errorText; + +@end + +NS_ASSUME_NONNULL_END diff --git a/sdk/objc/api/peerconnection/RTCIceCandidateErrorEvent.h b/sdk/objc/api/peerconnection/RTCIceCandidateErrorEvent.h new file mode 100644 index 0000000000..e0906fdbdd --- /dev/null +++ b/sdk/objc/api/peerconnection/RTCIceCandidateErrorEvent.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2021 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. + */ + +#import + +#import "RTCMacros.h" + +NS_ASSUME_NONNULL_BEGIN + +RTC_OBJC_EXPORT +@interface RTC_OBJC_TYPE (RTCIceCandidateErrorEvent) : NSObject + +/** The local IP address used to communicate with the STUN or TURN server. */ +@property(nonatomic, readonly) NSString *address; + +/** The port used to communicate with the STUN or TURN server. */ +@property(nonatomic, readonly) int port; + +/** The STUN or TURN URL that identifies the STUN or TURN server for which the failure occurred. */ +@property(nonatomic, readonly) NSString *url; + +/** The numeric STUN error code returned by the STUN or TURN server. If no host candidate can reach + * the server, errorCode will be set to the value 701 which is outside the STUN error code range. + * This error is only fired once per server URL while in the RTCIceGatheringState of "gathering". */ +@property(nonatomic, readonly) int errorCode; + +/** The STUN reason text returned by the STUN or TURN server. If the server could not be reached, + * errorText will be set to an implementation-specific value providing details about the error. */ +@property(nonatomic, readonly) NSString *errorText; + +- (instancetype)init NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/sdk/objc/api/peerconnection/RTCIceCandidateErrorEvent.mm b/sdk/objc/api/peerconnection/RTCIceCandidateErrorEvent.mm new file mode 100644 index 0000000000..573e30642b --- /dev/null +++ b/sdk/objc/api/peerconnection/RTCIceCandidateErrorEvent.mm @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2021 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. + */ + +#import "RTCIceCandidateErrorEvent+Private.h" + +#import "helpers/NSString+StdString.h" + +@implementation RTC_OBJC_TYPE (RTCIceCandidateErrorEvent) + +@synthesize address = _address; +@synthesize port = _port; +@synthesize url = _url; +@synthesize errorCode = _errorCode; +@synthesize errorText = _errorText; + +- (instancetype)init { + return [super init]; +} + +- (instancetype)initWithAddress:(const std::string&)address + port:(const int)port + url:(const std::string&)url + errorCode:(const int)errorCode + errorText:(const std::string&)errorText { + if (self = [self init]) { + _address = [NSString stringForStdString:address]; + _port = port; + _url = [NSString stringForStdString:url]; + _errorCode = errorCode; + _errorText = [NSString stringForStdString:errorText]; + } + return self; +} + +@end diff --git a/sdk/objc/api/peerconnection/RTCPeerConnection+Private.h b/sdk/objc/api/peerconnection/RTCPeerConnection+Private.h index 558cf07dce..43ee420ffe 100644 --- a/sdk/objc/api/peerconnection/RTCPeerConnection+Private.h +++ b/sdk/objc/api/peerconnection/RTCPeerConnection+Private.h @@ -48,6 +48,12 @@ class PeerConnectionDelegateAdapter : public PeerConnectionObserver { void OnIceCandidate(const IceCandidateInterface *candidate) override; + void OnIceCandidateError(const std::string &address, + int port, + const std::string &url, + int error_code, + const std::string &error_text) override; + void OnIceCandidatesRemoved(const std::vector &candidates) override; void OnIceSelectedCandidatePairChanged(const cricket::CandidatePairChangeEvent &event) override; diff --git a/sdk/objc/api/peerconnection/RTCPeerConnection.h b/sdk/objc/api/peerconnection/RTCPeerConnection.h index 98088ec9c5..55af6868fd 100644 --- a/sdk/objc/api/peerconnection/RTCPeerConnection.h +++ b/sdk/objc/api/peerconnection/RTCPeerConnection.h @@ -16,6 +16,7 @@ @class RTC_OBJC_TYPE(RTCDataChannel); @class RTC_OBJC_TYPE(RTCDataChannelConfiguration); @class RTC_OBJC_TYPE(RTCIceCandidate); +@class RTC_OBJC_TYPE(RTCIceCandidateErrorEvent); @class RTC_OBJC_TYPE(RTCMediaConstraints); @class RTC_OBJC_TYPE(RTCMediaStream); @class RTC_OBJC_TYPE(RTCMediaStreamTrack); @@ -164,6 +165,10 @@ RTC_OBJC_EXPORT lastReceivedMs:(int)lastDataReceivedMs changeReason:(NSString *)reason; +/** Called when gathering of an ICE candidate failed. */ +- (void)peerConnection:(RTC_OBJC_TYPE(RTCPeerConnection) *)peerConnection + didFailToGatherIceCandidate:(RTC_OBJC_TYPE(RTCIceCandidateErrorEvent) *)event; + @end RTC_OBJC_EXPORT diff --git a/sdk/objc/api/peerconnection/RTCPeerConnection.mm b/sdk/objc/api/peerconnection/RTCPeerConnection.mm index 67d0ff0cd6..24242acadd 100644 --- a/sdk/objc/api/peerconnection/RTCPeerConnection.mm +++ b/sdk/objc/api/peerconnection/RTCPeerConnection.mm @@ -13,6 +13,7 @@ #import "RTCConfiguration+Private.h" #import "RTCDataChannel+Private.h" #import "RTCIceCandidate+Private.h" +#import "RTCIceCandidateErrorEvent+Private.h" #import "RTCLegacyStatsReport+Private.h" #import "RTCMediaConstraints+Private.h" #import "RTCMediaStream+Private.h" @@ -226,6 +227,21 @@ void PeerConnectionDelegateAdapter::OnIceCandidate( didGenerateIceCandidate:iceCandidate]; } +void PeerConnectionDelegateAdapter::OnIceCandidateError(const std::string &address, + int port, + const std::string &url, + int error_code, + const std::string &error_text) { + RTC_OBJC_TYPE(RTCPeerConnection) *peer_connection = peer_connection_; + RTC_OBJC_TYPE(RTCIceCandidateErrorEvent) *event = + [[RTC_OBJC_TYPE(RTCIceCandidateErrorEvent) alloc] initWithAddress:address + port:port + url:url + errorCode:error_code + errorText:error_text]; + [peer_connection.delegate peerConnection:peer_connection didFailToGatherIceCandidate:event]; +} + void PeerConnectionDelegateAdapter::OnIceCandidatesRemoved( const std::vector& candidates) { NSMutableArray* ice_candidates =