Pass around the candidate removals events in IOS clients
When local candidates are removed, signal to RTCPeerConnection
and eventually send to the remote client.
When a candidate-removal message is received, notify the native PeerConnection.
BUG=
R=tkchin@webrtc.org
Review URL: https://codereview.webrtc.org/1972483002 .
Cr-Commit-Position: refs/heads/master@{#12852}
diff --git a/webrtc/examples/objc/AppRTCDemo/ARDAppClient.m b/webrtc/examples/objc/AppRTCDemo/ARDAppClient.m
index 86d18d1..8fb1841 100644
--- a/webrtc/examples/objc/AppRTCDemo/ARDAppClient.m
+++ b/webrtc/examples/objc/AppRTCDemo/ARDAppClient.m
@@ -330,6 +330,7 @@
[_messageQueue insertObject:message atIndex:0];
break;
case kARDSignalingMessageTypeCandidate:
+ case kARDSignalingMessageTypeCandidateRemoval:
[_messageQueue addObject:message];
break;
case kARDSignalingMessageTypeBye:
@@ -410,6 +411,16 @@
}
- (void)peerConnection:(RTCPeerConnection *)peerConnection
+ didRemoveIceCandidates:(NSArray<RTCIceCandidate *> *)candidates {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ ARDICECandidateRemovalMessage *message =
+ [[ARDICECandidateRemovalMessage alloc]
+ initWithRemovedCandidates:candidates];
+ [self sendSignalingMessage:message];
+ });
+}
+
+- (void)peerConnection:(RTCPeerConnection *)peerConnection
didOpenDataChannel:(RTCDataChannel *)dataChannel {
}
@@ -573,6 +584,12 @@
[_peerConnection addIceCandidate:candidateMessage.candidate];
break;
}
+ case kARDSignalingMessageTypeCandidateRemoval: {
+ ARDICECandidateRemovalMessage *candidateMessage =
+ (ARDICECandidateRemovalMessage *)message;
+ [_peerConnection removeIceCandidates:candidateMessage.candidates];
+ break;
+ }
case kARDSignalingMessageTypeBye:
// Other client disconnected.
// TODO(tkchin): support waiting in room for next client. For now just
diff --git a/webrtc/examples/objc/AppRTCDemo/ARDSignalingMessage.h b/webrtc/examples/objc/AppRTCDemo/ARDSignalingMessage.h
index 18eafe2..e605172 100644
--- a/webrtc/examples/objc/AppRTCDemo/ARDSignalingMessage.h
+++ b/webrtc/examples/objc/AppRTCDemo/ARDSignalingMessage.h
@@ -15,6 +15,7 @@
typedef enum {
kARDSignalingMessageTypeCandidate,
+ kARDSignalingMessageTypeCandidateRemoval,
kARDSignalingMessageTypeOffer,
kARDSignalingMessageTypeAnswer,
kARDSignalingMessageTypeBye,
@@ -37,6 +38,15 @@
@end
+@interface ARDICECandidateRemovalMessage : ARDSignalingMessage
+
+@property(nonatomic, readonly) NSArray<RTCIceCandidate *> *candidates;
+
+- (instancetype)initWithRemovedCandidates:
+ (NSArray<RTCIceCandidate *> *)candidates;
+
+@end
+
@interface ARDSessionDescriptionMessage : ARDSignalingMessage
@property(nonatomic, readonly) RTCSessionDescription *sessionDescription;
diff --git a/webrtc/examples/objc/AppRTCDemo/ARDSignalingMessage.m b/webrtc/examples/objc/AppRTCDemo/ARDSignalingMessage.m
index a5ca295..3fab185 100644
--- a/webrtc/examples/objc/AppRTCDemo/ARDSignalingMessage.m
+++ b/webrtc/examples/objc/AppRTCDemo/ARDSignalingMessage.m
@@ -16,7 +16,8 @@
#import "RTCIceCandidate+JSON.h"
#import "RTCSessionDescription+JSON.h"
-static NSString const *kARDSignalingMessageTypeKey = @"type";
+static NSString * const kARDSignalingMessageTypeKey = @"type";
+static NSString * const kARDTypeValueRemoveCandidates = @"remove-candidates";
@implementation ARDSignalingMessage
@@ -47,6 +48,12 @@
RTCIceCandidate *candidate =
[RTCIceCandidate candidateFromJSONDictionary:values];
message = [[ARDICECandidateMessage alloc] initWithCandidate:candidate];
+ } else if ([typeString isEqualToString:kARDTypeValueRemoveCandidates]) {
+ RTCLogInfo(@"Received remove-candidates message");
+ NSArray<RTCIceCandidate *> *candidates =
+ [RTCIceCandidate candidatesFromJSONDictionary:values];
+ message = [[ARDICECandidateRemovalMessage alloc]
+ initWithRemovedCandidates:candidates];
} else if ([typeString isEqualToString:@"offer"] ||
[typeString isEqualToString:@"answer"]) {
RTCSessionDescription *description =
@@ -84,6 +91,27 @@
@end
+@implementation ARDICECandidateRemovalMessage
+
+@synthesize candidates = _candidates;
+
+- (instancetype)initWithRemovedCandidates:(
+ NSArray<RTCIceCandidate *> *)candidates {
+ NSParameterAssert(candidates.count);
+ if (self = [super initWithType:kARDSignalingMessageTypeCandidateRemoval]) {
+ _candidates = candidates;
+ }
+ return self;
+}
+
+- (NSData *)JSONData {
+ return
+ [RTCIceCandidate JSONDataForIceCandidates:_candidates
+ withType:kARDTypeValueRemoveCandidates];
+}
+
+@end
+
@implementation ARDSessionDescriptionMessage
@synthesize sessionDescription = _sessionDescription;
diff --git a/webrtc/examples/objc/AppRTCDemo/ARDWebSocketChannel.m b/webrtc/examples/objc/AppRTCDemo/ARDWebSocketChannel.m
index 87a690e..6f60380 100644
--- a/webrtc/examples/objc/AppRTCDemo/ARDWebSocketChannel.m
+++ b/webrtc/examples/objc/AppRTCDemo/ARDWebSocketChannel.m
@@ -233,6 +233,7 @@
// Should not receive answer in loopback scenario.
break;
case kARDSignalingMessageTypeCandidate:
+ case kARDSignalingMessageTypeCandidateRemoval:
// Send back to server.
[self sendMessage:message];
break;
diff --git a/webrtc/examples/objc/AppRTCDemo/RTCICECandidate+JSON.h b/webrtc/examples/objc/AppRTCDemo/RTCICECandidate+JSON.h
index 1051f8e..d2e5e33 100644
--- a/webrtc/examples/objc/AppRTCDemo/RTCICECandidate+JSON.h
+++ b/webrtc/examples/objc/AppRTCDemo/RTCICECandidate+JSON.h
@@ -13,6 +13,10 @@
@interface RTCIceCandidate (JSON)
+ (RTCIceCandidate *)candidateFromJSONDictionary:(NSDictionary *)dictionary;
++ (NSArray<RTCIceCandidate *> *)candidatesFromJSONDictionary:
+ (NSDictionary *)dictionary;
++ (NSData *)JSONDataForIceCandidates:(NSArray<RTCIceCandidate *> *)candidates
+ withType:(NSString *)typeValue;
- (NSData *)JSONData;
@end
diff --git a/webrtc/examples/objc/AppRTCDemo/RTCICECandidate+JSON.m b/webrtc/examples/objc/AppRTCDemo/RTCICECandidate+JSON.m
index f20c490..b1be7fb 100644
--- a/webrtc/examples/objc/AppRTCDemo/RTCICECandidate+JSON.m
+++ b/webrtc/examples/objc/AppRTCDemo/RTCICECandidate+JSON.m
@@ -17,6 +17,8 @@
static NSString const *kRTCICECandidateMidKey = @"id";
static NSString const *kRTCICECandidateMLineIndexKey = @"label";
static NSString const *kRTCICECandidateSdpKey = @"candidate";
+static NSString const *kRTCICECandidatesTypeKey = @"candidates";
+
@implementation RTCIceCandidate (JSON)
@@ -30,6 +32,43 @@
sdpMid:mid];
}
++ (NSData *)JSONDataForIceCandidates:(NSArray<RTCIceCandidate *> *)candidates
+ withType:(NSString *)typeValue {
+ NSMutableArray *jsonCandidates =
+ [NSMutableArray arrayWithCapacity:candidates.count];
+ for (RTCIceCandidate *candidate in candidates) {
+ NSDictionary *jsonCandidate = [candidate JSONDictionary];
+ [jsonCandidates addObject:jsonCandidate];
+ }
+ NSDictionary *json = @{
+ kRTCICECandidateTypeKey : typeValue,
+ kRTCICECandidatesTypeKey : jsonCandidates
+ };
+ NSError *error = nil;
+ NSData *data =
+ [NSJSONSerialization dataWithJSONObject:json
+ options:NSJSONWritingPrettyPrinted
+ error:&error];
+ if (error) {
+ RTCLogError(@"Error serializing JSON: %@", error);
+ return nil;
+ }
+ return data;
+}
+
++ (NSArray<RTCIceCandidate *> *)candidatesFromJSONDictionary:
+ (NSDictionary *)dictionary {
+ NSArray *jsonCandidates = dictionary[kRTCICECandidatesTypeKey];
+ NSMutableArray<RTCIceCandidate *> *candidates =
+ [NSMutableArray arrayWithCapacity:jsonCandidates.count];
+ for (NSDictionary *jsonCandidate in jsonCandidates) {
+ RTCIceCandidate *candidate =
+ [RTCIceCandidate candidateFromJSONDictionary:jsonCandidate];
+ [candidates addObject:candidate];
+ }
+ return candidates;
+}
+
- (NSData *)JSONData {
NSDictionary *json = @{
kRTCICECandidateTypeKey : kRTCICECandidateTypeValue,
@@ -49,4 +88,13 @@
return data;
}
+- (NSDictionary *)JSONDictionary{
+ NSDictionary *json = @{
+ kRTCICECandidateMLineIndexKey : @(self.sdpMLineIndex),
+ kRTCICECandidateMidKey : self.sdpMid,
+ kRTCICECandidateSdpKey : self.sdp
+ };
+ return json;
+}
+
@end