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}
This commit is contained in:
Honghai Zhang
2016-05-23 11:53:14 -07:00
parent 3ebb3efd13
commit da2ba4dcba
9 changed files with 153 additions and 1 deletions

View File

@ -330,6 +330,7 @@ static BOOL const kARDAppClientEnableTracing = NO;
[_messageQueue insertObject:message atIndex:0]; [_messageQueue insertObject:message atIndex:0];
break; break;
case kARDSignalingMessageTypeCandidate: case kARDSignalingMessageTypeCandidate:
case kARDSignalingMessageTypeCandidateRemoval:
[_messageQueue addObject:message]; [_messageQueue addObject:message];
break; break;
case kARDSignalingMessageTypeBye: case kARDSignalingMessageTypeBye:
@ -409,6 +410,16 @@ static BOOL const kARDAppClientEnableTracing = NO;
}); });
} }
- (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 - (void)peerConnection:(RTCPeerConnection *)peerConnection
didOpenDataChannel:(RTCDataChannel *)dataChannel { didOpenDataChannel:(RTCDataChannel *)dataChannel {
} }
@ -573,6 +584,12 @@ static BOOL const kARDAppClientEnableTracing = NO;
[_peerConnection addIceCandidate:candidateMessage.candidate]; [_peerConnection addIceCandidate:candidateMessage.candidate];
break; break;
} }
case kARDSignalingMessageTypeCandidateRemoval: {
ARDICECandidateRemovalMessage *candidateMessage =
(ARDICECandidateRemovalMessage *)message;
[_peerConnection removeIceCandidates:candidateMessage.candidates];
break;
}
case kARDSignalingMessageTypeBye: case kARDSignalingMessageTypeBye:
// Other client disconnected. // Other client disconnected.
// TODO(tkchin): support waiting in room for next client. For now just // TODO(tkchin): support waiting in room for next client. For now just

View File

@ -15,6 +15,7 @@
typedef enum { typedef enum {
kARDSignalingMessageTypeCandidate, kARDSignalingMessageTypeCandidate,
kARDSignalingMessageTypeCandidateRemoval,
kARDSignalingMessageTypeOffer, kARDSignalingMessageTypeOffer,
kARDSignalingMessageTypeAnswer, kARDSignalingMessageTypeAnswer,
kARDSignalingMessageTypeBye, kARDSignalingMessageTypeBye,
@ -37,6 +38,15 @@ typedef enum {
@end @end
@interface ARDICECandidateRemovalMessage : ARDSignalingMessage
@property(nonatomic, readonly) NSArray<RTCIceCandidate *> *candidates;
- (instancetype)initWithRemovedCandidates:
(NSArray<RTCIceCandidate *> *)candidates;
@end
@interface ARDSessionDescriptionMessage : ARDSignalingMessage @interface ARDSessionDescriptionMessage : ARDSignalingMessage
@property(nonatomic, readonly) RTCSessionDescription *sessionDescription; @property(nonatomic, readonly) RTCSessionDescription *sessionDescription;

View File

@ -16,7 +16,8 @@
#import "RTCIceCandidate+JSON.h" #import "RTCIceCandidate+JSON.h"
#import "RTCSessionDescription+JSON.h" #import "RTCSessionDescription+JSON.h"
static NSString const *kARDSignalingMessageTypeKey = @"type"; static NSString * const kARDSignalingMessageTypeKey = @"type";
static NSString * const kARDTypeValueRemoveCandidates = @"remove-candidates";
@implementation ARDSignalingMessage @implementation ARDSignalingMessage
@ -47,6 +48,12 @@ static NSString const *kARDSignalingMessageTypeKey = @"type";
RTCIceCandidate *candidate = RTCIceCandidate *candidate =
[RTCIceCandidate candidateFromJSONDictionary:values]; [RTCIceCandidate candidateFromJSONDictionary:values];
message = [[ARDICECandidateMessage alloc] initWithCandidate:candidate]; 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"] || } else if ([typeString isEqualToString:@"offer"] ||
[typeString isEqualToString:@"answer"]) { [typeString isEqualToString:@"answer"]) {
RTCSessionDescription *description = RTCSessionDescription *description =
@ -84,6 +91,27 @@ static NSString const *kARDSignalingMessageTypeKey = @"type";
@end @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 @implementation ARDSessionDescriptionMessage
@synthesize sessionDescription = _sessionDescription; @synthesize sessionDescription = _sessionDescription;

View File

@ -233,6 +233,7 @@ static NSString const *kARDWSSMessagePayloadKey = @"msg";
// Should not receive answer in loopback scenario. // Should not receive answer in loopback scenario.
break; break;
case kARDSignalingMessageTypeCandidate: case kARDSignalingMessageTypeCandidate:
case kARDSignalingMessageTypeCandidateRemoval:
// Send back to server. // Send back to server.
[self sendMessage:message]; [self sendMessage:message];
break; break;

View File

@ -13,6 +13,10 @@
@interface RTCIceCandidate (JSON) @interface RTCIceCandidate (JSON)
+ (RTCIceCandidate *)candidateFromJSONDictionary:(NSDictionary *)dictionary; + (RTCIceCandidate *)candidateFromJSONDictionary:(NSDictionary *)dictionary;
+ (NSArray<RTCIceCandidate *> *)candidatesFromJSONDictionary:
(NSDictionary *)dictionary;
+ (NSData *)JSONDataForIceCandidates:(NSArray<RTCIceCandidate *> *)candidates
withType:(NSString *)typeValue;
- (NSData *)JSONData; - (NSData *)JSONData;
@end @end

View File

@ -17,6 +17,8 @@ static NSString const *kRTCICECandidateTypeValue = @"candidate";
static NSString const *kRTCICECandidateMidKey = @"id"; static NSString const *kRTCICECandidateMidKey = @"id";
static NSString const *kRTCICECandidateMLineIndexKey = @"label"; static NSString const *kRTCICECandidateMLineIndexKey = @"label";
static NSString const *kRTCICECandidateSdpKey = @"candidate"; static NSString const *kRTCICECandidateSdpKey = @"candidate";
static NSString const *kRTCICECandidatesTypeKey = @"candidates";
@implementation RTCIceCandidate (JSON) @implementation RTCIceCandidate (JSON)
@ -30,6 +32,43 @@ static NSString const *kRTCICECandidateSdpKey = @"candidate";
sdpMid:mid]; 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 { - (NSData *)JSONData {
NSDictionary *json = @{ NSDictionary *json = @{
kRTCICECandidateTypeKey : kRTCICECandidateTypeValue, kRTCICECandidateTypeKey : kRTCICECandidateTypeValue,
@ -49,4 +88,13 @@ static NSString const *kRTCICECandidateSdpKey = @"candidate";
return data; return data;
} }
- (NSDictionary *)JSONDictionary{
NSDictionary *json = @{
kRTCICECandidateMLineIndexKey : @(self.sdpMLineIndex),
kRTCICECandidateMidKey : self.sdpMid,
kRTCICECandidateSdpKey : self.sdp
};
return json;
}
@end @end

View File

@ -45,6 +45,9 @@ class PeerConnectionDelegateAdapter : public PeerConnectionObserver {
void OnIceCandidate(const IceCandidateInterface *candidate) override; void OnIceCandidate(const IceCandidateInterface *candidate) override;
void OnIceCandidatesRemoved(
const std::vector<cricket::Candidate>& candidates) override;
private: private:
__weak RTCPeerConnection *peer_connection_; __weak RTCPeerConnection *peer_connection_;
}; };

View File

@ -25,6 +25,7 @@
#include <memory> #include <memory>
#include "webrtc/api/jsepicecandidate.h"
#include "webrtc/base/checks.h" #include "webrtc/base/checks.h"
NSString * const kRTCPeerConnectionErrorDomain = NSString * const kRTCPeerConnectionErrorDomain =
@ -182,6 +183,23 @@ void PeerConnectionDelegateAdapter::OnIceCandidate(
[peer_connection.delegate peerConnection:peer_connection [peer_connection.delegate peerConnection:peer_connection
didGenerateIceCandidate:iceCandidate]; didGenerateIceCandidate:iceCandidate];
} }
void PeerConnectionDelegateAdapter::OnIceCandidatesRemoved(
const std::vector<cricket::Candidate>& candidates) {
NSMutableArray* ice_candidates =
[NSMutableArray arrayWithCapacity:candidates.size()];
for (const auto& candidate : candidates) {
std::unique_ptr<JsepIceCandidate> candidate_wrapper(
new JsepIceCandidate(candidate.transport_name(), -1, candidate));
RTCIceCandidate* ice_candidate = [[RTCIceCandidate alloc]
initWithNativeCandidate:candidate_wrapper.get()];
[ice_candidates addObject:ice_candidate];
}
RTCPeerConnection* peer_connection = peer_connection_;
[peer_connection.delegate peerConnection:peer_connection
didRemoveIceCandidates:ice_candidates];
}
} // namespace webrtc } // namespace webrtc
@ -273,6 +291,22 @@ void PeerConnectionDelegateAdapter::OnIceCandidate(
_peerConnection->AddIceCandidate(iceCandidate.get()); _peerConnection->AddIceCandidate(iceCandidate.get());
} }
- (void)removeIceCandidates:(NSArray<RTCIceCandidate *> *)iceCandidates {
std::vector<cricket::Candidate> candidates;
for (RTCIceCandidate *iceCandidate in iceCandidates) {
std::unique_ptr<const webrtc::IceCandidateInterface> candidate(
iceCandidate.nativeCandidate);
if (candidate) {
candidates.push_back(candidate->candidate());
// Need to fill the transport name from the sdp_mid.
candidates.back().set_transport_name(candidate->sdp_mid());
}
}
if (!candidates.empty()) {
_peerConnection->RemoveIceCandidates(candidates);
}
}
- (void)addStream:(RTCMediaStream *)stream { - (void)addStream:(RTCMediaStream *)stream {
if (!_peerConnection->AddStream(stream.nativeMediaStream)) { if (!_peerConnection->AddStream(stream.nativeMediaStream)) {
RTCLogError(@"Failed to add stream: %@", stream); RTCLogError(@"Failed to add stream: %@", stream);

View File

@ -98,6 +98,10 @@ RTC_EXPORT
- (void)peerConnection:(RTCPeerConnection *)peerConnection - (void)peerConnection:(RTCPeerConnection *)peerConnection
didGenerateIceCandidate:(RTCIceCandidate *)candidate; didGenerateIceCandidate:(RTCIceCandidate *)candidate;
/** Called when a group of local Ice candidates have been removed. */
- (void)peerConnection:(RTCPeerConnection *)peerConnection
didRemoveIceCandidates:(NSArray<RTCIceCandidate *> *)candidates;
/** New data channel has been opened. */ /** New data channel has been opened. */
- (void)peerConnection:(RTCPeerConnection *)peerConnection - (void)peerConnection:(RTCPeerConnection *)peerConnection
didOpenDataChannel:(RTCDataChannel *)dataChannel; didOpenDataChannel:(RTCDataChannel *)dataChannel;
@ -148,6 +152,9 @@ RTC_EXPORT
/** Provide a remote candidate to the ICE Agent. */ /** Provide a remote candidate to the ICE Agent. */
- (void)addIceCandidate:(RTCIceCandidate *)candidate; - (void)addIceCandidate:(RTCIceCandidate *)candidate;
/** Remove a group of remote candidates from the ICE Agent. */
- (void)removeIceCandidates:(NSArray<RTCIceCandidate *> *)candidates;
/** Add a new media stream to be sent on this peer connection. */ /** Add a new media stream to be sent on this peer connection. */
- (void)addStream:(RTCMediaStream *)stream; - (void)addStream:(RTCMediaStream *)stream;