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];
|
[_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
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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_;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user