Implement ObjC DataChannel wrapper

R=fischman@webrtc.org
BUG=3112

Review URL: https://webrtc-codereview.appspot.com/16369004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@6031 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
tkchin@webrtc.org
2014-04-30 18:32:33 +00:00
parent 65f933899b
commit ff2733204d
14 changed files with 622 additions and 7 deletions

View File

@@ -97,7 +97,9 @@ class DataChannelObserver {
class DataChannelInterface : public talk_base::RefCountInterface {
public:
enum DataState { // Keep in sync with DataChannel.java:State.
// Keep in sync with DataChannel.java:State and
// RTCDataChannel.h:RTCDataChannelState.
enum DataState {
kConnecting,
kOpen, // The DataChannel is ready to send data.
kClosing,

View File

@@ -0,0 +1,55 @@
/*
* libjingle
* Copyright 2014, Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "RTCDataChannel.h"
#include "talk/app/webrtc/datachannelinterface.h"
#include "talk/base/scoped_ref_ptr.h"
@interface RTCDataBuffer (Internal)
@property(nonatomic, readonly) const webrtc::DataBuffer* dataBuffer;
- (instancetype)initWithDataBuffer:(const webrtc::DataBuffer&)buffer;
@end
@interface RTCDataChannelInit (Internal)
@property(nonatomic, readonly) const webrtc::DataChannelInit* dataChannelInit;
@end
@interface RTCDataChannel (Internal)
@property(nonatomic, readonly)
talk_base::scoped_refptr<webrtc::DataChannelInterface> dataChannel;
- (instancetype)initWithDataChannel:
(talk_base::scoped_refptr<webrtc::DataChannelInterface>)dataChannel;
@end

View File

@@ -0,0 +1,273 @@
/*
* libjingle
* Copyright 2014, Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
#import "RTCDataChannel+Internal.h"
#include "talk/app/webrtc/datachannelinterface.h"
namespace webrtc {
class RTCDataChannelObserver : public DataChannelObserver {
public:
RTCDataChannelObserver(RTCDataChannel* channel) { _channel = channel; }
virtual void OnStateChange() OVERRIDE {
[_channel.delegate channelDidChangeState:_channel];
}
virtual void OnMessage(const DataBuffer& buffer) OVERRIDE {
if (!_channel.delegate) {
return;
}
RTCDataBuffer* dataBuffer =
[[RTCDataBuffer alloc] initWithDataBuffer:buffer];
[_channel.delegate channel:_channel didReceiveMessageWithBuffer:dataBuffer];
}
private:
__weak RTCDataChannel* _channel;
};
}
// TODO(tkchin): move to shared location
NSString* NSStringFromStdString(const std::string& stdString) {
// std::string may contain null termination character so we construct
// using length.
return [[NSString alloc] initWithBytes:stdString.data()
length:stdString.length()
encoding:NSUTF8StringEncoding];
}
std::string StdStringFromNSString(NSString* nsString) {
NSData* charData = [nsString dataUsingEncoding:NSUTF8StringEncoding];
return std::string(reinterpret_cast<const char*>([charData bytes]),
[charData length]);
}
@implementation RTCDataChannelInit {
webrtc::DataChannelInit _dataChannelInit;
}
- (BOOL)isOrdered {
return _dataChannelInit.ordered;
}
- (void)setIsOrdered:(BOOL)isOrdered {
_dataChannelInit.ordered = isOrdered;
}
- (NSInteger)maxRetransmitTime {
return _dataChannelInit.maxRetransmitTime;
}
- (void)setMaxRetransmitTime:(NSInteger)maxRetransmitTime {
_dataChannelInit.maxRetransmitTime = maxRetransmitTime;
}
- (NSInteger)maxRetransmits {
return _dataChannelInit.maxRetransmits;
}
- (void)setMaxRetransmits:(NSInteger)maxRetransmits {
_dataChannelInit.maxRetransmits = maxRetransmits;
}
- (NSString*)protocol {
return NSStringFromStdString(_dataChannelInit.protocol);
}
- (void)setProtocol:(NSString*)protocol {
_dataChannelInit.protocol = StdStringFromNSString(protocol);
}
- (BOOL)isNegotiated {
return _dataChannelInit.negotiated;
}
- (void)setIsNegotiated:(BOOL)isNegotiated {
_dataChannelInit.negotiated = isNegotiated;
}
- (NSInteger)streamId {
return _dataChannelInit.id;
}
- (void)setStreamId:(NSInteger)streamId {
_dataChannelInit.id = streamId;
}
@end
@implementation RTCDataChannelInit (Internal)
- (const webrtc::DataChannelInit*)dataChannelInit {
return &_dataChannelInit;
}
@end
@implementation RTCDataBuffer {
talk_base::scoped_ptr<webrtc::DataBuffer> _dataBuffer;
}
- (instancetype)initWithData:(NSData*)data isBinary:(BOOL)isBinary {
NSAssert(data, @"data cannot be nil");
if (self = [super init]) {
talk_base::Buffer buffer([data bytes], [data length]);
_dataBuffer.reset(new webrtc::DataBuffer(buffer, isBinary));
}
return self;
}
- (NSData*)data {
return [NSData dataWithBytes:_dataBuffer->data.data()
length:_dataBuffer->data.length()];
}
- (BOOL)isBinary {
return _dataBuffer->binary;
}
@end
@implementation RTCDataBuffer (Internal)
- (instancetype)initWithDataBuffer:(const webrtc::DataBuffer&)buffer {
if (self = [super init]) {
_dataBuffer.reset(new webrtc::DataBuffer(buffer));
}
return self;
}
- (const webrtc::DataBuffer*)dataBuffer {
return _dataBuffer.get();
}
@end
@implementation RTCDataChannel {
talk_base::scoped_refptr<webrtc::DataChannelInterface> _dataChannel;
talk_base::scoped_ptr<webrtc::RTCDataChannelObserver> _observer;
BOOL _isObserverRegistered;
}
- (NSString*)label {
return NSStringFromStdString(_dataChannel->label());
}
- (BOOL)isReliable {
return _dataChannel->reliable();
}
- (BOOL)isOrdered {
return _dataChannel->ordered();
}
- (NSUInteger)maxRetransmitTimeMs {
return _dataChannel->maxRetransmitTime();
}
- (NSUInteger)maxRetransmits {
return _dataChannel->maxRetransmits();
}
- (NSString*)protocol {
return NSStringFromStdString(_dataChannel->protocol());
}
- (BOOL)isNegotiated {
return _dataChannel->negotiated();
}
- (NSInteger)streamId {
return _dataChannel->id();
}
- (RTCDataChannelState)state {
switch (_dataChannel->state()) {
case webrtc::DataChannelInterface::DataState::kConnecting:
return kRTCDataChannelStateConnecting;
case webrtc::DataChannelInterface::DataState::kOpen:
return kRTCDataChannelStateOpen;
case webrtc::DataChannelInterface::DataState::kClosing:
return kRTCDataChannelStateClosing;
case webrtc::DataChannelInterface::DataState::kClosed:
return kRTCDataChannelStateClosed;
}
}
- (NSUInteger)bufferedAmount {
return _dataChannel->buffered_amount();
}
- (void)setDelegate:(id<RTCDataChannelDelegate>)delegate {
if (_delegate == delegate) {
return;
}
if (_isObserverRegistered) {
_dataChannel->UnregisterObserver();
_isObserverRegistered = NO;
}
_delegate = delegate;
if (_delegate) {
_dataChannel->RegisterObserver(_observer.get());
_isObserverRegistered = YES;
}
}
- (void)close {
_dataChannel->Close();
}
- (BOOL)sendData:(RTCDataBuffer*)data {
return _dataChannel->Send(*data.dataBuffer);
}
@end
@implementation RTCDataChannel (Internal)
- (instancetype)initWithDataChannel:
(talk_base::scoped_refptr<webrtc::DataChannelInterface>)
dataChannel {
NSAssert(dataChannel != NULL, @"dataChannel cannot be NULL");
if (self = [super init]) {
_dataChannel = dataChannel;
_observer.reset(new webrtc::RTCDataChannelObserver(self));
}
return self;
}
- (talk_base::scoped_refptr<webrtc::DataChannelInterface>)dataChannel {
return _dataChannel;
}
@end

View File

@@ -31,6 +31,7 @@
#import "RTCPeerConnection+Internal.h"
#import "RTCDataChannel+Internal.h"
#import "RTCEnumConverter.h"
#import "RTCICECandidate+Internal.h"
#import "RTCICEServer+Internal.h"
@@ -160,6 +161,15 @@ class RTCStatsObserver : public StatsObserver {
return YES;
}
- (RTCDataChannel*)createDataChannelWithLabel:(NSString*)label
config:(RTCDataChannelInit*)config {
std::string labelString([label UTF8String]);
talk_base::scoped_refptr<webrtc::DataChannelInterface> dataChannel =
self.peerConnection->CreateDataChannel(labelString,
config.dataChannelInit);
return [[RTCDataChannel alloc] initWithDataChannel:dataChannel];
}
- (void)createAnswerWithDelegate:(id<RTCSessionDescriptionDelegate>)delegate
constraints:(RTCMediaConstraints*)constraints {
talk_base::scoped_refptr<webrtc::RTCCreateSessionDescriptionObserver>

View File

@@ -31,6 +31,7 @@
#import "RTCPeerConnectionObserver.h"
#import "RTCDataChannel+Internal.h"
#import "RTCICECandidate+Internal.h"
#import "RTCMediaStream+Internal.h"
#import "RTCEnumConverter.h"
@@ -74,7 +75,9 @@ void RTCPeerConnectionObserver::OnRemoveStream(MediaStreamInterface* stream) {
void RTCPeerConnectionObserver::OnDataChannel(
DataChannelInterface* data_channel) {
// TODO(hughv): Implement for future version.
RTCDataChannel* dataChannel =
[[RTCDataChannel alloc] initWithDataChannel:data_channel];
[_delegate peerConnection:_peerConnection didOpenDataChannel:dataChannel];
}
void RTCPeerConnectionObserver::OnRenegotiationNeeded() {

View File

@@ -0,0 +1,112 @@
/*
* libjingle
* Copyright 2014, Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import <Foundation/Foundation.h>
// ObjectiveC wrapper for a DataChannelInit object.
@interface RTCDataChannelInit : NSObject
// Set to YES if ordered delivery is required
@property(nonatomic) BOOL isOrdered;
// Max period in milliseconds in which retransmissions will be sent. After this
// time, no more retransmissions will be sent. -1 if unset.
@property(nonatomic) NSInteger maxRetransmitTimeMs;
// The max number of retransmissions. -1 if unset.
@property(nonatomic) NSInteger maxRetransmits;
// Set to YES if the channel has been externally negotiated and we do not send
// an in-band signalling in the form of an "open" message
@property(nonatomic) BOOL isNegotiated;
// The stream id, or SID, for SCTP data channels. -1 if unset.
@property(nonatomic) NSInteger streamId;
// Set by the application and opaque to the WebRTC implementation.
@property(nonatomic) NSString* protocol;
@end
// ObjectiveC wrapper for a DataBuffer object.
@interface RTCDataBuffer : NSObject
@property(nonatomic, readonly) NSData* data;
@property(nonatomic, readonly) BOOL isBinary;
- (instancetype)initWithData:(NSData*)data isBinary:(BOOL)isBinary;
#ifndef DOXYGEN_SHOULD_SKIP_THIS
// Disallow init and don't add to documentation
- (id)init __attribute__((
unavailable("init is not a supported initializer for this class.")));
#endif /* DOXYGEN_SHOULD_SKIP_THIS */
@end
// Keep in sync with webrtc::DataChannelInterface::DataState
typedef enum {
kRTCDataChannelStateConnecting,
kRTCDataChannelStateOpen,
kRTCDataChannelStateClosing,
kRTCDataChannelStateClosed
} RTCDataChannelState;
@class RTCDataChannel;
// Protocol for receving data channel state and message events.
@protocol RTCDataChannelDelegate<NSObject>
// Called when the data channel state has changed.
- (void)channelDidChangeState:(RTCDataChannel*)channel;
// Called when a data buffer was successfully received.
- (void)channel:(RTCDataChannel*)channel
didReceiveMessageWithBuffer:(RTCDataBuffer*)buffer;
@end
// ObjectiveC wrapper for a DataChannel object.
// See talk/app/webrtc/datachannelinterface.h
@interface RTCDataChannel : NSObject
@property(nonatomic, readonly) NSString* label;
@property(nonatomic, readonly) BOOL isReliable;
@property(nonatomic, readonly) BOOL isOrdered;
@property(nonatomic, readonly) NSUInteger maxRetransmitTime;
@property(nonatomic, readonly) NSUInteger maxRetransmits;
@property(nonatomic, readonly) NSString* protocol;
@property(nonatomic, readonly) BOOL isNegotiated;
@property(nonatomic, readonly) NSInteger streamId;
@property(nonatomic, readonly) RTCDataChannelState state;
@property(nonatomic, readonly) NSUInteger bufferedAmount;
@property(nonatomic, weak) id<RTCDataChannelDelegate> delegate;
- (void)close;
- (BOOL)sendData:(RTCDataBuffer*)data;
#ifndef DOXYGEN_SHOULD_SKIP_THIS
// Disallow init and don't add to documentation
- (id)init __attribute__((
unavailable("init is not a supported initializer for this class.")));
#endif /* DOXYGEN_SHOULD_SKIP_THIS */
@end

View File

@@ -27,6 +27,8 @@
#import "RTCPeerConnectionDelegate.h"
@class RTCDataChannel;
@class RTCDataChannelInit;
@class RTCICECandidate;
@class RTCICEServers;
@class RTCMediaConstraints;
@@ -68,6 +70,10 @@
// remote peer is notified.
- (void)removeStream:(RTCMediaStream *)stream;
// Create a data channel.
- (RTCDataChannel*)createDataChannelWithLabel:(NSString*)label
config:(RTCDataChannelInit*)config;
// Create a new offer.
// Success or failure will be reported via RTCSessionDescriptionDelegate.
- (void)createOfferWithDelegate:(id<RTCSessionDescriptionDelegate>)delegate

View File

@@ -29,6 +29,7 @@
#import "RTCTypes.h"
@class RTCDataChannel;
@class RTCICECandidate;
@class RTCMediaStream;
@class RTCPeerConnection;
@@ -67,4 +68,8 @@
- (void)peerConnection:(RTCPeerConnection *)peerConnection
gotICECandidate:(RTCICECandidate *)candidate;
// New data channel has been opened.
- (void)peerConnection:(RTCPeerConnection*)peerConnection
didOpenDataChannel:(RTCDataChannel*)dataChannel;
@end

View File

@@ -27,11 +27,14 @@
#import <Foundation/Foundation.h>
#import "RTCDataChannel.h"
#import "RTCPeerConnectionDelegate.h"
// Observer of PeerConnection events, used by RTCPeerConnectionTest to check
// expectations.
@interface RTCPeerConnectionSyncObserver : NSObject<RTCPeerConnectionDelegate>
@interface RTCPeerConnectionSyncObserver
: NSObject<RTCPeerConnectionDelegate, RTCDataChannelDelegate>
@property(nonatomic) RTCDataChannel* dataChannel;
// TODO(hughv): Add support for RTCVideoRendererDelegate when Video is enabled.
// Transfer received ICE candidates to the caller.
@@ -46,6 +49,9 @@
- (void)expectICECandidates:(int)count;
- (void)expectICEConnectionChange:(RTCICEConnectionState)state;
- (void)expectICEGatheringChange:(RTCICEGatheringState)state;
- (void)expectDataChannel:(NSString*)label;
- (void)expectStateChange:(RTCDataChannelState)state;
- (void)expectMessage:(NSData*)message isBinary:(BOOL)isBinary;
// Wait until all registered expectations above have been observed.
- (void)waitForAllExpectationsToBeSatisfied;

View File

@@ -42,6 +42,9 @@
NSMutableArray* _receivedICECandidates;
NSMutableArray* _expectedICEConnectionChanges;
NSMutableArray* _expectedICEGatheringChanges;
NSMutableArray* _expectedDataChannels;
NSMutableArray* _expectedStateChanges;
NSMutableArray* _expectedMessages;
}
- (id)init {
@@ -54,6 +57,9 @@
_receivedICECandidates = [NSMutableArray array];
_expectedICEConnectionChanges = [NSMutableArray array];
_expectedICEGatheringChanges = [NSMutableArray array];
_expectedDataChannels = [NSMutableArray array];
_expectedMessages = [NSMutableArray array];
_expectedStateChanges = [NSMutableArray array];
}
return self;
}
@@ -78,7 +84,10 @@
[_expectedICEConnectionChanges count] == 0 &&
[_expectedICEGatheringChanges count] == 0 &&
[_expectedAddStreamLabels count] == 0 &&
[_expectedRemoveStreamLabels count] == 0;
[_expectedRemoveStreamLabels count] == 0 &&
[_expectedDataChannels count] == 0 &&
[_expectedStateChanges count] == 0 &&
[_expectedMessages count] == 0;
// TODO(hughv): Test video state here too.
}
@@ -116,6 +125,20 @@
[_expectedICEGatheringChanges addObject:@((int)state)];
}
- (void)expectDataChannel:(NSString*)label {
[_expectedDataChannels addObject:label];
}
- (void)expectStateChange:(RTCDataChannelState)state {
[_expectedStateChanges addObject:@(state)];
}
- (void)expectMessage:(NSData*)message isBinary:(BOOL)isBinary {
RTCDataBuffer* buffer = [[RTCDataBuffer alloc] initWithData:message
isBinary:isBinary];
[_expectedMessages addObject:buffer];
}
- (void)waitForAllExpectationsToBeSatisfied {
// TODO (fischman): Revisit. Keeping in sync with the Java version, but
// polling is not optimal.
@@ -191,4 +214,37 @@
NSAssert(expectedState == (int)newState, @"Empty expectation array");
}
- (void)peerConnection:(RTCPeerConnection*)peerConnection
didOpenDataChannel:(RTCDataChannel*)dataChannel {
NSString* expectedLabel =
[self popFirstElementAsNSString:_expectedDataChannels];
NSAssert([expectedLabel isEqual:dataChannel.label],
@"Data channel not expected");
self.dataChannel = dataChannel;
dataChannel.delegate = self;
NSAssert(kRTCDataChannelStateConnecting == dataChannel.state,
@"Unexpected state");
}
#pragma mark - RTCDataChannelDelegate
- (void)channelDidChangeState:(RTCDataChannel*)channel {
NSAssert([_expectedStateChanges count] > 0,
@"Unexpected state change");
int expectedState = [self popFirstElementAsInt:_expectedStateChanges];
NSAssert(expectedState == channel.state, @"Channel state should match");
}
- (void)channel:(RTCDataChannel*)channel
didReceiveMessageWithBuffer:(RTCDataBuffer*)buffer {
NSAssert([_expectedMessages count] > 0,
@"Unexpected message received");
RTCDataBuffer* expectedBuffer = [_expectedMessages objectAtIndex:0];
NSAssert(expectedBuffer.isBinary == buffer.isBinary,
@"Buffer isBinary should match");
NSAssert([expectedBuffer.data isEqual:buffer.data],
@"Buffer data should match");
[_expectedMessages removeObjectAtIndex:0];
}
@end

View File

@@ -30,6 +30,7 @@
#import "RTCICEServer.h"
#import "RTCMediaConstraints.h"
#import "RTCMediaStream.h"
#import "RTCPair.h"
#import "RTCPeerConnection.h"
#import "RTCPeerConnectionFactory.h"
#import "RTCPeerConnectionSyncObserver.h"
@@ -94,12 +95,20 @@
}
- (void)testCompleteSessionWithFactory:(RTCPeerConnectionFactory*)factory {
NSArray* mandatory = @[
[[RTCPair alloc] initWithKey:@"DtlsSrtpKeyAgreement" value:@"true"],
[[RTCPair alloc] initWithKey:@"internalSctpDataChannels" value:@"true"],
];
RTCMediaConstraints* constraints = [[RTCMediaConstraints alloc] init];
RTCMediaConstraints* pcConstraints =
[[RTCMediaConstraints alloc] initWithMandatoryConstraints:mandatory
optionalConstraints:nil];
RTCPeerConnectionSyncObserver* offeringExpectations =
[[RTCPeerConnectionSyncObserver alloc] init];
RTCPeerConnection* pcOffer =
[factory peerConnectionWithICEServers:nil
constraints:constraints
constraints:pcConstraints
delegate:offeringExpectations];
RTCPeerConnectionSyncObserver* answeringExpectations =
@@ -107,7 +116,7 @@
RTCPeerConnection* pcAnswer =
[factory peerConnectionWithICEServers:nil
constraints:constraints
constraints:pcConstraints
delegate:answeringExpectations];
// TODO(hughv): Create video capturer
RTCVideoCapturer* capturer = nil;
@@ -123,6 +132,14 @@
streamLabel:@"oLMS"
videoTrackID:@"oLMSv0"
audioTrackID:@"oLMSa0"];
RTCDataChannel* offerDC =
[pcOffer createDataChannelWithLabel:@"offerDC"
config:[[RTCDataChannelInit alloc] init]];
EXPECT_TRUE([offerDC.label isEqual:@"offerDC"]);
offerDC.delegate = offeringExpectations;
offeringExpectations.dataChannel = offerDC;
RTCSessionDescriptionSyncObserver* sdpObserver =
[[RTCSessionDescriptionSyncObserver alloc] init];
[pcOffer createOfferWithDelegate:sdpObserver constraints:constraints];
@@ -181,6 +198,10 @@
[answeringExpectations expectICEConnectionChange:RTCICEConnectionChecking];
[answeringExpectations expectICEConnectionChange:RTCICEConnectionConnected];
[offeringExpectations expectStateChange:kRTCDataChannelStateOpen];
[answeringExpectations expectDataChannel:@"offerDC"];
[answeringExpectations expectStateChange:kRTCDataChannelStateOpen];
[offeringExpectations expectICEGatheringChange:RTCICEGatheringComplete];
[answeringExpectations expectICEGatheringChange:RTCICEGatheringComplete];
@@ -209,6 +230,42 @@
[offeringExpectations waitForAllExpectationsToBeSatisfied];
[answeringExpectations waitForAllExpectationsToBeSatisfied];
EXPECT_EQ(pcOffer.signalingState, RTCSignalingStable);
EXPECT_EQ(pcAnswer.signalingState, RTCSignalingStable);
// Test send and receive UTF-8 text
NSString* text = @"你好";
NSData* textData = [text dataUsingEncoding:NSUTF8StringEncoding];
RTCDataBuffer* buffer =
[[RTCDataBuffer alloc] initWithData:textData isBinary:NO];
[answeringExpectations expectMessage:[textData copy] isBinary:NO];
EXPECT_TRUE([offeringExpectations.dataChannel sendData:buffer]);
[answeringExpectations waitForAllExpectationsToBeSatisfied];
// Test send and receive binary data
const size_t byteLength = 5;
char bytes[byteLength] = {1, 2, 3, 4, 5};
NSData* byteData = [NSData dataWithBytes:bytes length:byteLength];
buffer = [[RTCDataBuffer alloc] initWithData:byteData isBinary:YES];
[answeringExpectations expectMessage:[byteData copy] isBinary:YES];
EXPECT_TRUE([offeringExpectations.dataChannel sendData:buffer]);
[answeringExpectations waitForAllExpectationsToBeSatisfied];
[offeringExpectations expectStateChange:kRTCDataChannelStateClosing];
[answeringExpectations expectStateChange:kRTCDataChannelStateClosing];
[offeringExpectations expectStateChange:kRTCDataChannelStateClosed];
[answeringExpectations expectStateChange:kRTCDataChannelStateClosed];
[answeringExpectations.dataChannel close];
[offeringExpectations.dataChannel close];
[offeringExpectations waitForAllExpectationsToBeSatisfied];
[answeringExpectations waitForAllExpectationsToBeSatisfied];
// Don't need to listen to further state changes.
// TODO(tkchin): figure out why Closed->Closing without this.
offeringExpectations.dataChannel.delegate = nil;
answeringExpectations.dataChannel.delegate = nil;
// Let the audio feedback run for 2s to allow human testing and to ensure
// things stabilize. TODO(fischman): replace seconds with # of video frames,
// when we have video flowing.

View File

@@ -150,6 +150,11 @@
});
}
- (void)peerConnection:(RTCPeerConnection*)peerConnection
didOpenDataChannel:(RTCDataChannel*)dataChannel {
NSAssert(NO, @"AppRTC doesn't use DataChannels");
}
#pragma mark - Private
- (void)displayLogMessage:(NSString*)message {

View File

@@ -157,7 +157,8 @@
},
],
}],
['OS=="ios" or (OS=="mac" and target_arch!="ia32")', {
['OS=="ios" or (OS=="mac" and target_arch!="ia32" and mac_sdk>="10.7")', {
# The >= 10.7 above is required for ARC.
'targets': [
{
'target_name': 'libjingle_peerconnection_objc',
@@ -168,6 +169,8 @@
'sources': [
'app/webrtc/objc/RTCAudioTrack+Internal.h',
'app/webrtc/objc/RTCAudioTrack.mm',
'app/webrtc/objc/RTCDataChannel+Internal.h',
'app/webrtc/objc/RTCDataChannel.mm',
'app/webrtc/objc/RTCEnumConverter.h',
'app/webrtc/objc/RTCEnumConverter.mm',
'app/webrtc/objc/RTCI420Frame.mm',
@@ -205,6 +208,7 @@
'app/webrtc/objc/RTCVideoTrack.mm',
'app/webrtc/objc/public/RTCAudioSource.h',
'app/webrtc/objc/public/RTCAudioTrack.h',
'app/webrtc/objc/public/RTCDataChannel.h',
'app/webrtc/objc/public/RTCI420Frame.h',
'app/webrtc/objc/public/RTCICECandidate.h',
'app/webrtc/objc/public/RTCICEServer.h',
@@ -249,6 +253,15 @@
# like it is for ios.
'CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS': 'NO',
},
'conditions': [
['OS=="mac"', {
'xcode_settings': {
# Need to build against 10.7 framework for full ARC support
# on OSX.
'MACOSX_DEPLOYMENT_TARGET' : '10.7',
},
}],
],
}, # target libjingle_peerconnection_objc
],
}],

View File

@@ -535,8 +535,20 @@
],
'xcode_settings': {
'CLANG_ENABLE_OBJC_ARC': 'YES',
# common.gypi enables this for mac but we want this to be disabled
# like it is for ios.
'CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS': 'NO',
'INFOPLIST_FILE': '<(infoplist_file)',
},
'conditions': [
['OS=="mac"', {
'xcode_settings': {
# Need to build against 10.7 framework for full ARC support
# on OSX.
'MACOSX_DEPLOYMENT_TARGET' : '10.7',
},
}],
],
}, # target libjingle_peerconnection_objc_test
],
}],