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:
@ -330,6 +330,7 @@ static BOOL const kARDAppClientEnableTracing = NO;
|
||||
[_messageQueue insertObject:message atIndex:0];
|
||||
break;
|
||||
case kARDSignalingMessageTypeCandidate:
|
||||
case kARDSignalingMessageTypeCandidateRemoval:
|
||||
[_messageQueue addObject:message];
|
||||
break;
|
||||
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
|
||||
didOpenDataChannel:(RTCDataChannel *)dataChannel {
|
||||
}
|
||||
@ -573,6 +584,12 @@ static BOOL const kARDAppClientEnableTracing = NO;
|
||||
[_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
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
|
||||
typedef enum {
|
||||
kARDSignalingMessageTypeCandidate,
|
||||
kARDSignalingMessageTypeCandidateRemoval,
|
||||
kARDSignalingMessageTypeOffer,
|
||||
kARDSignalingMessageTypeAnswer,
|
||||
kARDSignalingMessageTypeBye,
|
||||
@ -37,6 +38,15 @@ typedef enum {
|
||||
|
||||
@end
|
||||
|
||||
@interface ARDICECandidateRemovalMessage : ARDSignalingMessage
|
||||
|
||||
@property(nonatomic, readonly) NSArray<RTCIceCandidate *> *candidates;
|
||||
|
||||
- (instancetype)initWithRemovedCandidates:
|
||||
(NSArray<RTCIceCandidate *> *)candidates;
|
||||
|
||||
@end
|
||||
|
||||
@interface ARDSessionDescriptionMessage : ARDSignalingMessage
|
||||
|
||||
@property(nonatomic, readonly) RTCSessionDescription *sessionDescription;
|
||||
|
||||
@ -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 @@ static NSString const *kARDSignalingMessageTypeKey = @"type";
|
||||
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 @@ static NSString const *kARDSignalingMessageTypeKey = @"type";
|
||||
|
||||
@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;
|
||||
|
||||
@ -233,6 +233,7 @@ static NSString const *kARDWSSMessagePayloadKey = @"msg";
|
||||
// Should not receive answer in loopback scenario.
|
||||
break;
|
||||
case kARDSignalingMessageTypeCandidate:
|
||||
case kARDSignalingMessageTypeCandidateRemoval:
|
||||
// Send back to server.
|
||||
[self sendMessage:message];
|
||||
break;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -17,6 +17,8 @@ static NSString const *kRTCICECandidateTypeValue = @"candidate";
|
||||
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 @@ static NSString const *kRTCICECandidateSdpKey = @"candidate";
|
||||
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 @@ static NSString const *kRTCICECandidateSdpKey = @"candidate";
|
||||
return data;
|
||||
}
|
||||
|
||||
- (NSDictionary *)JSONDictionary{
|
||||
NSDictionary *json = @{
|
||||
kRTCICECandidateMLineIndexKey : @(self.sdpMLineIndex),
|
||||
kRTCICECandidateMidKey : self.sdpMid,
|
||||
kRTCICECandidateSdpKey : self.sdp
|
||||
};
|
||||
return json;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@ -45,6 +45,9 @@ class PeerConnectionDelegateAdapter : public PeerConnectionObserver {
|
||||
|
||||
void OnIceCandidate(const IceCandidateInterface *candidate) override;
|
||||
|
||||
void OnIceCandidatesRemoved(
|
||||
const std::vector<cricket::Candidate>& candidates) override;
|
||||
|
||||
private:
|
||||
__weak RTCPeerConnection *peer_connection_;
|
||||
};
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "webrtc/api/jsepicecandidate.h"
|
||||
#include "webrtc/base/checks.h"
|
||||
|
||||
NSString * const kRTCPeerConnectionErrorDomain =
|
||||
@ -182,6 +183,23 @@ void PeerConnectionDelegateAdapter::OnIceCandidate(
|
||||
[peer_connection.delegate peerConnection:peer_connection
|
||||
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
|
||||
|
||||
|
||||
@ -273,6 +291,22 @@ void PeerConnectionDelegateAdapter::OnIceCandidate(
|
||||
_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 {
|
||||
if (!_peerConnection->AddStream(stream.nativeMediaStream)) {
|
||||
RTCLogError(@"Failed to add stream: %@", stream);
|
||||
|
||||
@ -98,6 +98,10 @@ RTC_EXPORT
|
||||
- (void)peerConnection:(RTCPeerConnection *)peerConnection
|
||||
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. */
|
||||
- (void)peerConnection:(RTCPeerConnection *)peerConnection
|
||||
didOpenDataChannel:(RTCDataChannel *)dataChannel;
|
||||
@ -148,6 +152,9 @@ RTC_EXPORT
|
||||
/** Provide a remote candidate to the ICE Agent. */
|
||||
- (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. */
|
||||
- (void)addStream:(RTCMediaStream *)stream;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user