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:
@@ -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,
|
||||
|
||||
55
talk/app/webrtc/objc/RTCDataChannel+Internal.h
Normal file
55
talk/app/webrtc/objc/RTCDataChannel+Internal.h
Normal 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
|
||||
273
talk/app/webrtc/objc/RTCDataChannel.mm
Normal file
273
talk/app/webrtc/objc/RTCDataChannel.mm
Normal 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
|
||||
@@ -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>
|
||||
|
||||
@@ -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() {
|
||||
|
||||
112
talk/app/webrtc/objc/public/RTCDataChannel.h
Normal file
112
talk/app/webrtc/objc/public/RTCDataChannel.h
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
],
|
||||
}],
|
||||
|
||||
@@ -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
|
||||
],
|
||||
}],
|
||||
|
||||
Reference in New Issue
Block a user