iOS AppRTC: First unit test.
Tests basic session ICE connection by stubbing out network components, which have been refactored to faciliate testing.
BUG=3994
R=jiayl@webrtc.org, kjellander@webrtc.org, phoglund@webrtc.org
Review URL: https://webrtc-codereview.appspot.com/28349004
git-svn-id: http://webrtc.googlecode.com/svn/trunk@8002 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/.gitignore b/.gitignore
index 1082352..cb684c9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -94,6 +94,7 @@
/third_party/modp_b64
/third_party/nss
/third_party/oauth2
+/third_party/ocmock
/third_party/openmax_dl
/third_party/opus
/third_party/protobuf
diff --git a/setup_links.py b/setup_links.py
index 0dd453c..5891270 100755
--- a/setup_links.py
+++ b/setup_links.py
@@ -55,6 +55,7 @@
'third_party/libyuv',
'third_party/llvm-build',
'third_party/nss',
+ 'third_party/ocmock',
'third_party/openmax_dl',
'third_party/opus',
'third_party/protobuf',
diff --git a/talk/build/ios_tests.gypi b/talk/build/objc_app.gypi
similarity index 68%
rename from talk/build/ios_tests.gypi
rename to talk/build/objc_app.gypi
index baf1f10..a479802 100644
--- a/talk/build/ios_tests.gypi
+++ b/talk/build/objc_app.gypi
@@ -29,27 +29,20 @@
# used as an iOS or OS/X application.
{
- 'conditions': [
- ['OS=="ios"', {
- 'variables': {
- 'infoplist_file': './ios_test.plist',
- },
- 'mac_bundle': 1,
- 'mac_bundle_resources': [
- '<(infoplist_file)',
- ],
- # The plist is listed above so that it appears in XCode's file list,
- # but we don't actually want to bundle it.
- 'mac_bundle_resources!': [
- '<(infoplist_file)',
- ],
- '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
+ 'variables': {
+ 'infoplist_file': './objc_app.plist',
+ },
+ 'mac_bundle': 1,
+ 'mac_bundle_resources': [
+ '<(infoplist_file)',
+ ],
+ # The plist is listed above so that it appears in XCode's file list,
+ # but we don't actually want to bundle it.
+ 'mac_bundle_resources!': [
+ '<(infoplist_file)',
+ ],
+ 'xcode_settings': {
+ 'CLANG_ENABLE_OBJC_ARC': 'YES',
+ 'INFOPLIST_FILE': '<(infoplist_file)',
+ },
}
diff --git a/talk/build/ios_test.plist b/talk/build/objc_app.plist
similarity index 100%
rename from talk/build/ios_test.plist
rename to talk/build/objc_app.plist
diff --git a/talk/examples/objc/AppRTCDemo/ARDAppClient+Internal.h b/talk/examples/objc/AppRTCDemo/ARDAppClient+Internal.h
new file mode 100644
index 0000000..068c041
--- /dev/null
+++ b/talk/examples/objc/AppRTCDemo/ARDAppClient+Internal.h
@@ -0,0 +1,68 @@
+/*
+ * 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 "ARDAppClient.h"
+
+#import "ARDRoomServerClient.h"
+#import "ARDSignalingChannel.h"
+#import "ARDTURNClient.h"
+#import "RTCPeerConnection.h"
+#import "RTCPeerConnectionDelegate.h"
+#import "RTCPeerConnectionFactory.h"
+#import "RTCSessionDescriptionDelegate.h"
+
+@interface ARDAppClient () <ARDSignalingChannelDelegate,
+ RTCPeerConnectionDelegate, RTCSessionDescriptionDelegate>
+
+@property(nonatomic, strong) id<ARDRoomServerClient> roomServerClient;
+@property(nonatomic, strong) id<ARDSignalingChannel> channel;
+@property(nonatomic, strong) id<ARDTURNClient> turnClient;
+
+@property(nonatomic, strong) RTCPeerConnection *peerConnection;
+@property(nonatomic, strong) RTCPeerConnectionFactory *factory;
+@property(nonatomic, strong) NSMutableArray *messageQueue;
+
+@property(nonatomic, assign) BOOL isTurnComplete;
+@property(nonatomic, assign) BOOL hasReceivedSdp;
+@property(nonatomic, readonly) BOOL isRegisteredWithRoomServer;
+
+@property(nonatomic, strong) NSString *roomId;
+@property(nonatomic, strong) NSString *clientId;
+@property(nonatomic, assign) BOOL isInitiator;
+@property(nonatomic, strong) NSMutableArray *iceServers;
+@property(nonatomic, strong) NSURL *webSocketURL;
+@property(nonatomic, strong) NSURL *webSocketRestURL;
+
+@property(nonatomic, strong)
+ RTCMediaConstraints *defaultPeerConnectionConstraints;
+
+- (instancetype)initWithRoomServerClient:(id<ARDRoomServerClient>)rsClient
+ signalingChannel:(id<ARDSignalingChannel>)channel
+ turnClient:(id<ARDTURNClient>)turnClient
+ delegate:(id<ARDAppClientDelegate>)delegate;
+
+@end
diff --git a/talk/examples/objc/AppRTCDemo/ARDAppClient.h b/talk/examples/objc/AppRTCDemo/ARDAppClient.h
index d742ea3..fa3a634 100644
--- a/talk/examples/objc/AppRTCDemo/ARDAppClient.h
+++ b/talk/examples/objc/AppRTCDemo/ARDAppClient.h
@@ -45,6 +45,9 @@
didChangeState:(ARDAppClientState)state;
- (void)appClient:(ARDAppClient *)client
+ didChangeConnectionState:(RTCICEConnectionState)state;
+
+- (void)appClient:(ARDAppClient *)client
didReceiveLocalVideoTrack:(RTCVideoTrack *)localVideoTrack;
- (void)appClient:(ARDAppClient *)client
diff --git a/talk/examples/objc/AppRTCDemo/ARDAppClient.m b/talk/examples/objc/AppRTCDemo/ARDAppClient.m
index d72e8bb..fef7727 100644
--- a/talk/examples/objc/AppRTCDemo/ARDAppClient.m
+++ b/talk/examples/objc/AppRTCDemo/ARDAppClient.m
@@ -25,38 +25,26 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#import "ARDAppClient.h"
+#import "ARDAppClient+Internal.h"
#import <AVFoundation/AVFoundation.h>
+#import "ARDAppEngineClient.h"
+#import "ARDCEODTURNClient.h"
#import "ARDMessageResponse.h"
#import "ARDRegisterResponse.h"
#import "ARDSignalingMessage.h"
#import "ARDUtilities.h"
#import "ARDWebSocketChannel.h"
#import "RTCICECandidate+JSON.h"
-#import "RTCICEServer+JSON.h"
+#import "RTCICEServer.h"
#import "RTCMediaConstraints.h"
#import "RTCMediaStream.h"
#import "RTCPair.h"
-#import "RTCPeerConnection.h"
-#import "RTCPeerConnectionDelegate.h"
-#import "RTCPeerConnectionFactory.h"
#import "RTCSessionDescription+JSON.h"
-#import "RTCSessionDescriptionDelegate.h"
#import "RTCVideoCapturer.h"
#import "RTCVideoTrack.h"
-// TODO(tkchin): move these to a configuration object.
-static NSString *kARDRoomServerHostUrl =
- @"https://apprtc.appspot.com";
-static NSString *kARDRoomServerRegisterFormat =
- @"https://apprtc.appspot.com/register/%@";
-static NSString *kARDRoomServerMessageFormat =
- @"https://apprtc.appspot.com/message/%@/%@";
-static NSString *kARDRoomServerByeFormat =
- @"https://apprtc.appspot.com/bye/%@/%@";
-
static NSString *kARDDefaultSTUNServerUrl =
@"stun:stun.l.google.com:19302";
// TODO(tkchin): figure out a better username for CEOD statistics.
@@ -69,34 +57,16 @@
static NSInteger kARDAppClientErrorRoomFull = -2;
static NSInteger kARDAppClientErrorCreateSDP = -3;
static NSInteger kARDAppClientErrorSetSDP = -4;
-static NSInteger kARDAppClientErrorNetwork = -5;
-static NSInteger kARDAppClientErrorInvalidClient = -6;
-static NSInteger kARDAppClientErrorInvalidRoom = -7;
-
-@interface ARDAppClient () <ARDWebSocketChannelDelegate,
- RTCPeerConnectionDelegate, RTCSessionDescriptionDelegate>
-@property(nonatomic, strong) ARDWebSocketChannel *channel;
-@property(nonatomic, strong) RTCPeerConnection *peerConnection;
-@property(nonatomic, strong) RTCPeerConnectionFactory *factory;
-@property(nonatomic, strong) NSMutableArray *messageQueue;
-
-@property(nonatomic, assign) BOOL isTurnComplete;
-@property(nonatomic, assign) BOOL hasReceivedSdp;
-@property(nonatomic, readonly) BOOL isRegisteredWithRoomServer;
-
-@property(nonatomic, strong) NSString *roomId;
-@property(nonatomic, strong) NSString *clientId;
-@property(nonatomic, assign) BOOL isInitiator;
-@property(nonatomic, strong) NSMutableArray *iceServers;
-@property(nonatomic, strong) NSURL *webSocketURL;
-@property(nonatomic, strong) NSURL *webSocketRestURL;
-@end
+static NSInteger kARDAppClientErrorInvalidClient = -5;
+static NSInteger kARDAppClientErrorInvalidRoom = -6;
@implementation ARDAppClient
@synthesize delegate = _delegate;
@synthesize state = _state;
+@synthesize roomServerClient = _roomServerClient;
@synthesize channel = _channel;
+@synthesize turnClient = _turnClient;
@synthesize peerConnection = _peerConnection;
@synthesize factory = _factory;
@synthesize messageQueue = _messageQueue;
@@ -108,17 +78,46 @@
@synthesize iceServers = _iceServers;
@synthesize webSocketURL = _websocketURL;
@synthesize webSocketRestURL = _websocketRestURL;
+@synthesize defaultPeerConnectionConstraints =
+ _defaultPeerConnectionConstraints;
- (instancetype)initWithDelegate:(id<ARDAppClientDelegate>)delegate {
if (self = [super init]) {
+ _roomServerClient = [[ARDAppEngineClient alloc] init];
_delegate = delegate;
- _factory = [[RTCPeerConnectionFactory alloc] init];
- _messageQueue = [NSMutableArray array];
- _iceServers = [NSMutableArray arrayWithObject:[self defaultSTUNServer]];
+ NSURL *turnRequestURL = [NSURL URLWithString:kARDTurnRequestUrl];
+ _turnClient = [[ARDCEODTURNClient alloc] initWithURL:turnRequestURL];
+ [self configure];
}
return self;
}
+// TODO(tkchin): Provide signaling channel factory interface so we can recreate
+// channel if we need to on network failure. Also, make this the default public
+// constructor.
+- (instancetype)initWithRoomServerClient:(id<ARDRoomServerClient>)rsClient
+ signalingChannel:(id<ARDSignalingChannel>)channel
+ turnClient:(id<ARDTURNClient>)turnClient
+ delegate:(id<ARDAppClientDelegate>)delegate {
+ NSParameterAssert(rsClient);
+ NSParameterAssert(channel);
+ NSParameterAssert(turnClient);
+ if (self = [super init]) {
+ _roomServerClient = rsClient;
+ _channel = channel;
+ _turnClient = turnClient;
+ _delegate = delegate;
+ [self configure];
+ }
+ return self;
+}
+
+- (void)configure {
+ _factory = [[RTCPeerConnectionFactory alloc] init];
+ _messageQueue = [NSMutableArray array];
+ _iceServers = [NSMutableArray arrayWithObject:[self defaultSTUNServer]];
+}
+
- (void)dealloc {
[self disconnect];
}
@@ -139,9 +138,11 @@
// Request TURN.
__weak ARDAppClient *weakSelf = self;
- NSURL *turnRequestURL = [NSURL URLWithString:kARDTurnRequestUrl];
- [self requestTURNServersWithURL:turnRequestURL
- completionHandler:^(NSArray *turnServers) {
+ [_turnClient requestServersWithCompletionHandler:^(NSArray *turnServers,
+ NSError *error) {
+ if (error) {
+ NSLog(@"Error retrieving TURN servers: %@", error);
+ }
ARDAppClient *strongSelf = weakSelf;
[strongSelf.iceServers addObjectsFromArray:turnServers];
strongSelf.isTurnComplete = YES;
@@ -149,23 +150,21 @@
}];
// Register with room server.
- [self registerWithRoomServerForRoomId:roomId
- completionHandler:^(ARDRegisterResponse *response) {
+ [_roomServerClient registerForRoomId:roomId
+ completionHandler:^(ARDRegisterResponse *response, NSError *error) {
ARDAppClient *strongSelf = weakSelf;
- if (!response || response.result != kARDRegisterResultTypeSuccess) {
- NSLog(@"Failed to register with room server. Result:%d",
- (int)response.result);
- [strongSelf disconnect];
- NSDictionary *userInfo = @{
- NSLocalizedDescriptionKey: @"Room is full.",
- };
- NSError *error =
- [[NSError alloc] initWithDomain:kARDAppClientErrorDomain
- code:kARDAppClientErrorRoomFull
- userInfo:userInfo];
+ if (error) {
[strongSelf.delegate appClient:strongSelf didError:error];
return;
}
+ NSError *registerError =
+ [[strongSelf class] errorForRegisterResultType:response.result];
+ if (registerError) {
+ NSLog(@"Failed to register with room server.");
+ [strongSelf disconnect];
+ [strongSelf.delegate appClient:strongSelf didError:registerError];
+ return;
+ }
NSLog(@"Registered with room server.");
strongSelf.roomId = response.roomId;
strongSelf.clientId = response.clientId;
@@ -191,14 +190,15 @@
return;
}
if (self.isRegisteredWithRoomServer) {
- [self unregisterWithRoomServer];
+ [_roomServerClient deregisterForRoomId:_roomId
+ clientId:_clientId
+ completionHandler:nil];
}
if (_channel) {
- if (_channel.state == kARDWebSocketChannelStateRegistered) {
+ if (_channel.state == kARDSignalingChannelStateRegistered) {
// Tell the other client we're hanging up.
ARDByeMessage *byeMessage = [[ARDByeMessage alloc] init];
- NSData *byeData = [byeMessage JSONData];
- [_channel sendData:byeData];
+ [_channel sendMessage:byeMessage];
}
// Disconnect from collider.
_channel = nil;
@@ -212,9 +212,9 @@
self.state = kARDAppClientStateDisconnected;
}
-#pragma mark - ARDWebSocketChannelDelegate
+#pragma mark - ARDSignalingChannelDelegate
-- (void)channel:(ARDWebSocketChannel *)channel
+- (void)channel:(id<ARDSignalingChannel>)channel
didReceiveMessage:(ARDSignalingMessage *)message {
switch (message.type) {
case kARDSignalingMessageTypeOffer:
@@ -232,15 +232,15 @@
[self drainMessageQueueIfReady];
}
-- (void)channel:(ARDWebSocketChannel *)channel
- didChangeState:(ARDWebSocketChannelState)state {
+- (void)channel:(id<ARDSignalingChannel>)channel
+ didChangeState:(ARDSignalingChannelState)state {
switch (state) {
- case kARDWebSocketChannelStateOpen:
+ case kARDSignalingChannelStateOpen:
break;
- case kARDWebSocketChannelStateRegistered:
+ case kARDSignalingChannelStateRegistered:
break;
- case kARDWebSocketChannelStateClosed:
- case kARDWebSocketChannelStateError:
+ case kARDSignalingChannelStateClosed:
+ case kARDSignalingChannelStateError:
// TODO(tkchin): reconnection scenarios. Right now we just disconnect
// completely if the websocket connection fails.
[self disconnect];
@@ -281,6 +281,9 @@
- (void)peerConnection:(RTCPeerConnection *)peerConnection
iceConnectionChanged:(RTCICEConnectionState)newState {
NSLog(@"ICE state changed: %d", newState);
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [_delegate appClient:self didChangeConnectionState:newState];
+ });
}
- (void)peerConnection:(RTCPeerConnection *)peerConnection
@@ -430,9 +433,26 @@
- (void)sendSignalingMessage:(ARDSignalingMessage *)message {
if (_isInitiator) {
- [self sendSignalingMessageToRoomServer:message completionHandler:nil];
+ __weak ARDAppClient *weakSelf = self;
+ [_roomServerClient sendMessage:message
+ forRoomId:_roomId
+ clientId:_clientId
+ completionHandler:^(ARDMessageResponse *response,
+ NSError *error) {
+ ARDAppClient *strongSelf = weakSelf;
+ if (error) {
+ [strongSelf.delegate appClient:strongSelf didError:error];
+ return;
+ }
+ NSError *messageError =
+ [[strongSelf class] errorForMessageResultType:response.result];
+ if (messageError) {
+ [strongSelf.delegate appClient:strongSelf didError:messageError];
+ return;
+ }
+ }];
} else {
- [self sendSignalingMessageToCollider:message];
+ [_channel sendMessage:message];
}
}
@@ -473,142 +493,6 @@
return localStream;
}
-- (void)requestTURNServersWithURL:(NSURL *)requestURL
- completionHandler:(void (^)(NSArray *turnServers))completionHandler {
- NSParameterAssert([requestURL absoluteString].length);
- NSMutableURLRequest *request =
- [NSMutableURLRequest requestWithURL:requestURL];
- // We need to set origin because TURN provider whitelists requests based on
- // origin.
- [request addValue:@"Mozilla/5.0" forHTTPHeaderField:@"user-agent"];
- [request addValue:kARDRoomServerHostUrl forHTTPHeaderField:@"origin"];
- [NSURLConnection sendAsyncRequest:request
- completionHandler:^(NSURLResponse *response,
- NSData *data,
- NSError *error) {
- NSArray *turnServers = [NSArray array];
- if (error) {
- NSLog(@"Unable to get TURN server.");
- completionHandler(turnServers);
- return;
- }
- NSDictionary *dict = [NSDictionary dictionaryWithJSONData:data];
- turnServers = [RTCICEServer serversFromCEODJSONDictionary:dict];
- completionHandler(turnServers);
- }];
-}
-
-#pragma mark - Room server methods
-
-- (void)registerWithRoomServerForRoomId:(NSString *)roomId
- completionHandler:(void (^)(ARDRegisterResponse *))completionHandler {
- NSString *urlString =
- [NSString stringWithFormat:kARDRoomServerRegisterFormat, roomId];
- NSURL *roomURL = [NSURL URLWithString:urlString];
- NSLog(@"Registering with room server.");
- __weak ARDAppClient *weakSelf = self;
- [NSURLConnection sendAsyncPostToURL:roomURL
- withData:nil
- completionHandler:^(BOOL succeeded, NSData *data) {
- ARDAppClient *strongSelf = weakSelf;
- if (!succeeded) {
- NSError *error = [self roomServerNetworkError];
- [strongSelf.delegate appClient:strongSelf didError:error];
- completionHandler(nil);
- return;
- }
- ARDRegisterResponse *response =
- [ARDRegisterResponse responseFromJSONData:data];
- completionHandler(response);
- }];
-}
-
-- (void)sendSignalingMessageToRoomServer:(ARDSignalingMessage *)message
- completionHandler:(void (^)(ARDMessageResponse *))completionHandler {
- NSData *data = [message JSONData];
- NSString *urlString =
- [NSString stringWithFormat:
- kARDRoomServerMessageFormat, _roomId, _clientId];
- NSURL *url = [NSURL URLWithString:urlString];
- NSLog(@"C->RS POST: %@", message);
- __weak ARDAppClient *weakSelf = self;
- [NSURLConnection sendAsyncPostToURL:url
- withData:data
- completionHandler:^(BOOL succeeded, NSData *data) {
- ARDAppClient *strongSelf = weakSelf;
- if (!succeeded) {
- NSError *error = [self roomServerNetworkError];
- [strongSelf.delegate appClient:strongSelf didError:error];
- return;
- }
- ARDMessageResponse *response =
- [ARDMessageResponse responseFromJSONData:data];
- NSError *error = nil;
- switch (response.result) {
- case kARDMessageResultTypeSuccess:
- break;
- case kARDMessageResultTypeUnknown:
- error =
- [[NSError alloc] initWithDomain:kARDAppClientErrorDomain
- code:kARDAppClientErrorUnknown
- userInfo:@{
- NSLocalizedDescriptionKey: @"Unknown error.",
- }];
- case kARDMessageResultTypeInvalidClient:
- error =
- [[NSError alloc] initWithDomain:kARDAppClientErrorDomain
- code:kARDAppClientErrorInvalidClient
- userInfo:@{
- NSLocalizedDescriptionKey: @"Invalid client.",
- }];
- break;
- case kARDMessageResultTypeInvalidRoom:
- error =
- [[NSError alloc] initWithDomain:kARDAppClientErrorDomain
- code:kARDAppClientErrorInvalidRoom
- userInfo:@{
- NSLocalizedDescriptionKey: @"Invalid room.",
- }];
- break;
- };
- if (error) {
- [strongSelf.delegate appClient:strongSelf didError:error];
- }
- if (completionHandler) {
- completionHandler(response);
- }
- }];
-}
-
-- (void)unregisterWithRoomServer {
- NSString *urlString =
- [NSString stringWithFormat:kARDRoomServerByeFormat, _roomId, _clientId];
- NSURL *url = [NSURL URLWithString:urlString];
- NSURLRequest *request = [NSURLRequest requestWithURL:url];
- NSURLResponse *response = nil;
- // We want a synchronous request so that we know that we're unregistered from
- // room server before we do any further unregistration.
- NSLog(@"C->RS: BYE");
- NSError *error = nil;
- [NSURLConnection sendSynchronousRequest:request
- returningResponse:&response
- error:&error];
- if (error) {
- NSLog(@"Error unregistering from room server: %@", error);
- }
- NSLog(@"Unregistered from room server.");
-}
-
-- (NSError *)roomServerNetworkError {
- NSError *error =
- [[NSError alloc] initWithDomain:kARDAppClientErrorDomain
- code:kARDAppClientErrorNetwork
- userInfo:@{
- NSLocalizedDescriptionKey: @"Room server network error",
- }];
- return error;
-}
-
#pragma mark - Collider methods
- (void)registerWithColliderIfReady {
@@ -616,18 +500,15 @@
return;
}
// Open WebSocket connection.
- _channel =
- [[ARDWebSocketChannel alloc] initWithURL:_websocketURL
- restURL:_websocketRestURL
- delegate:self];
+ if (!_channel) {
+ _channel =
+ [[ARDWebSocketChannel alloc] initWithURL:_websocketURL
+ restURL:_websocketRestURL
+ delegate:self];
+ }
[_channel registerForRoomId:_roomId clientId:_clientId];
}
-- (void)sendSignalingMessageToCollider:(ARDSignalingMessage *)message {
- NSData *data = [message JSONData];
- [_channel sendData:data];
-}
-
#pragma mark - Defaults
- (RTCMediaConstraints *)defaultMediaStreamConstraints {
@@ -655,6 +536,9 @@
}
- (RTCMediaConstraints *)defaultPeerConnectionConstraints {
+ if (_defaultPeerConnectionConstraints) {
+ return _defaultPeerConnectionConstraints;
+ }
NSArray *optionalConstraints = @[
[[RTCPair alloc] initWithKey:@"DtlsSrtpKeyAgreement" value:@"true"]
];
@@ -672,4 +556,61 @@
password:@""];
}
+#pragma mark - Errors
+
++ (NSError *)errorForRegisterResultType:(ARDRegisterResultType)resultType {
+ NSError *error = nil;
+ switch (resultType) {
+ case kARDRegisterResultTypeSuccess:
+ break;
+ case kARDRegisterResultTypeUnknown: {
+ error = [[NSError alloc] initWithDomain:kARDAppClientErrorDomain
+ code:kARDAppClientErrorUnknown
+ userInfo:@{
+ NSLocalizedDescriptionKey: @"Unknown error.",
+ }];
+ break;
+ }
+ case kARDRegisterResultTypeFull: {
+ error = [[NSError alloc] initWithDomain:kARDAppClientErrorDomain
+ code:kARDAppClientErrorRoomFull
+ userInfo:@{
+ NSLocalizedDescriptionKey: @"Room is full.",
+ }];
+ break;
+ }
+ }
+ return error;
+}
+
++ (NSError *)errorForMessageResultType:(ARDMessageResultType)resultType {
+ NSError *error = nil;
+ switch (resultType) {
+ case kARDMessageResultTypeSuccess:
+ break;
+ case kARDMessageResultTypeUnknown:
+ error = [[NSError alloc] initWithDomain:kARDAppClientErrorDomain
+ code:kARDAppClientErrorUnknown
+ userInfo:@{
+ NSLocalizedDescriptionKey: @"Unknown error.",
+ }];
+ break;
+ case kARDMessageResultTypeInvalidClient:
+ error = [[NSError alloc] initWithDomain:kARDAppClientErrorDomain
+ code:kARDAppClientErrorInvalidClient
+ userInfo:@{
+ NSLocalizedDescriptionKey: @"Invalid client.",
+ }];
+ break;
+ case kARDMessageResultTypeInvalidRoom:
+ error = [[NSError alloc] initWithDomain:kARDAppClientErrorDomain
+ code:kARDAppClientErrorInvalidRoom
+ userInfo:@{
+ NSLocalizedDescriptionKey: @"Invalid room.",
+ }];
+ break;
+ }
+ return error;
+}
+
@end
diff --git a/talk/examples/objc/AppRTCDemo/ARDAppEngineClient.h b/talk/examples/objc/AppRTCDemo/ARDAppEngineClient.h
new file mode 100644
index 0000000..2ec2ef8
--- /dev/null
+++ b/talk/examples/objc/AppRTCDemo/ARDAppEngineClient.h
@@ -0,0 +1,31 @@
+/*
+ * 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 "ARDRoomServerClient.h"
+
+@interface ARDAppEngineClient : NSObject <ARDRoomServerClient>
+@end
diff --git a/talk/examples/objc/AppRTCDemo/ARDAppEngineClient.m b/talk/examples/objc/AppRTCDemo/ARDAppEngineClient.m
new file mode 100644
index 0000000..44d3801
--- /dev/null
+++ b/talk/examples/objc/AppRTCDemo/ARDAppEngineClient.m
@@ -0,0 +1,178 @@
+/*
+ * 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 "ARDAppEngineClient.h"
+
+#import "ARDMessageResponse.h"
+#import "ARDRegisterResponse.h"
+#import "ARDSignalingMessage.h"
+#import "ARDUtilities.h"
+
+// TODO(tkchin): move these to a configuration object.
+static NSString *kARDRoomServerHostUrl =
+ @"https://apprtc.appspot.com";
+static NSString *kARDRoomServerRegisterFormat =
+ @"https://apprtc.appspot.com/register/%@";
+static NSString *kARDRoomServerMessageFormat =
+ @"https://apprtc.appspot.com/message/%@/%@";
+static NSString *kARDRoomServerByeFormat =
+ @"https://apprtc.appspot.com/bye/%@/%@";
+
+static NSString *kARDAppEngineClientErrorDomain = @"ARDAppEngineClient";
+static NSInteger kARDAppEngineClientErrorBadResponse = -1;
+
+@implementation ARDAppEngineClient
+
+#pragma mark - ARDRoomServerClient
+
+- (void)registerForRoomId:(NSString *)roomId
+ completionHandler:(void (^)(ARDRegisterResponse *response,
+ NSError *error))completionHandler {
+ NSParameterAssert(roomId.length);
+
+ NSString *urlString =
+ [NSString stringWithFormat:kARDRoomServerRegisterFormat, roomId];
+ NSURL *roomURL = [NSURL URLWithString:urlString];
+ NSLog(@"Registering with room server.");
+ NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:roomURL];
+ request.HTTPMethod = @"POST";
+ __weak ARDAppEngineClient *weakSelf = self;
+ [NSURLConnection sendAsyncRequest:request
+ completionHandler:^(NSURLResponse *response,
+ NSData *data,
+ NSError *error) {
+ ARDAppEngineClient *strongSelf = weakSelf;
+ if (error) {
+ if (completionHandler) {
+ completionHandler(nil, error);
+ }
+ return;
+ }
+ ARDRegisterResponse *registerResponse =
+ [ARDRegisterResponse responseFromJSONData:data];
+ if (!registerResponse) {
+ if (completionHandler) {
+ NSError *error = [[self class] badResponseError];
+ completionHandler(nil, error);
+ }
+ return;
+ }
+ if (completionHandler) {
+ completionHandler(registerResponse, nil);
+ }
+ }];
+}
+
+- (void)sendMessage:(ARDSignalingMessage *)message
+ forRoomId:(NSString *)roomId
+ clientId:(NSString *)clientId
+ completionHandler:(void (^)(ARDMessageResponse *response,
+ NSError *error))completionHandler {
+ NSParameterAssert(message);
+ NSParameterAssert(roomId.length);
+ NSParameterAssert(clientId.length);
+
+ NSData *data = [message JSONData];
+ NSString *urlString =
+ [NSString stringWithFormat:
+ kARDRoomServerMessageFormat, roomId, clientId];
+ NSURL *url = [NSURL URLWithString:urlString];
+ NSLog(@"C->RS POST: %@", message);
+ NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
+ request.HTTPMethod = @"POST";
+ request.HTTPBody = data;
+ __weak ARDAppEngineClient *weakSelf = self;
+ [NSURLConnection sendAsyncRequest:request
+ completionHandler:^(NSURLResponse *response,
+ NSData *data,
+ NSError *error) {
+ ARDAppEngineClient *strongSelf = weakSelf;
+ if (error) {
+ if (completionHandler) {
+ completionHandler(nil, error);
+ }
+ return;
+ }
+ ARDMessageResponse *messageResponse =
+ [ARDMessageResponse responseFromJSONData:data];
+ if (!messageResponse) {
+ if (completionHandler) {
+ NSError *error = [[self class] badResponseError];
+ completionHandler(nil, error);
+ }
+ return;
+ }
+ if (completionHandler) {
+ completionHandler(messageResponse, nil);
+ }
+ }];
+}
+
+- (void)deregisterForRoomId:(NSString *)roomId
+ clientId:(NSString *)clientId
+ completionHandler:(void (^)(NSError *error))completionHandler {
+ NSParameterAssert(roomId.length);
+ NSParameterAssert(clientId.length);
+
+ NSString *urlString =
+ [NSString stringWithFormat:kARDRoomServerByeFormat, roomId, clientId];
+ NSURL *url = [NSURL URLWithString:urlString];
+ NSURLRequest *request = [NSURLRequest requestWithURL:url];
+ NSURLResponse *response = nil;
+ NSError *error = nil;
+ // We want a synchronous request so that we know that we're unregistered from
+ // room server before we do any further unregistration.
+ NSLog(@"C->RS: BYE");
+ [NSURLConnection sendSynchronousRequest:request
+ returningResponse:&response
+ error:&error];
+ if (error) {
+ NSLog(@"Error unregistering from room server: %@", error);
+ if (completionHandler) {
+ completionHandler(error);
+ }
+ return;
+ }
+ NSLog(@"Unregistered from room server.");
+ if (completionHandler) {
+ completionHandler(nil);
+ }
+}
+
+#pragma mark - Private
+
++ (NSError *)badResponseError {
+ NSError *error =
+ [[NSError alloc] initWithDomain:kARDAppEngineClientErrorDomain
+ code:kARDAppEngineClientErrorBadResponse
+ userInfo:@{
+ NSLocalizedDescriptionKey: @"Error parsing response.",
+ }];
+ return error;
+}
+
+@end
diff --git a/talk/examples/objc/AppRTCDemo/ARDCEODTURNClient.h b/talk/examples/objc/AppRTCDemo/ARDCEODTURNClient.h
new file mode 100644
index 0000000..81be9e8
--- /dev/null
+++ b/talk/examples/objc/AppRTCDemo/ARDCEODTURNClient.h
@@ -0,0 +1,35 @@
+/*
+ * 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 "ARDTURNClient.h"
+
+// Requests TURN server urls from compute engine on demand.
+@interface ARDCEODTURNClient : NSObject <ARDTURNClient>
+
+- (instancetype)initWithURL:(NSURL *)url;
+
+@end
diff --git a/talk/examples/objc/AppRTCDemo/ARDCEODTURNClient.m b/talk/examples/objc/AppRTCDemo/ARDCEODTURNClient.m
new file mode 100644
index 0000000..f63a289
--- /dev/null
+++ b/talk/examples/objc/AppRTCDemo/ARDCEODTURNClient.m
@@ -0,0 +1,83 @@
+/*
+ * 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 "ARDCEODTURNClient.h"
+
+#import "ARDUtilities.h"
+#import "RTCICEServer+JSON.h"
+
+// TODO(tkchin): move this to a configuration object.
+static NSString *kTURNOriginURLString = @"https://apprtc.appspot.com";
+static NSString *kARDCEODTURNClientErrorDomain = @"ARDCEODTURNClient";
+static NSInteger kARDCEODTURNClientErrorBadResponse = -1;
+
+@implementation ARDCEODTURNClient {
+ NSURL *_url;
+}
+
+- (instancetype)initWithURL:(NSURL *)url {
+ NSParameterAssert([url absoluteString].length);
+ if (self = [super init]) {
+ _url = url;
+ }
+ return self;
+}
+
+- (void)requestServersWithCompletionHandler:
+ (void (^)(NSArray *turnServers,
+ NSError *error))completionHandler {
+ NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:_url];
+ // We need to set origin because TURN provider whitelists requests based on
+ // origin.
+ [request addValue:@"Mozilla/5.0" forHTTPHeaderField:@"user-agent"];
+ [request addValue:kTURNOriginURLString forHTTPHeaderField:@"origin"];
+ [NSURLConnection sendAsyncRequest:request
+ completionHandler:^(NSURLResponse *response,
+ NSData *data,
+ NSError *error) {
+ NSArray *turnServers = [NSArray array];
+ if (error) {
+ completionHandler(turnServers, error);
+ return;
+ }
+ NSDictionary *dict = [NSDictionary dictionaryWithJSONData:data];
+ turnServers = [RTCICEServer serversFromCEODJSONDictionary:dict];
+ if (!turnServers) {
+ NSError *responseError =
+ [[NSError alloc] initWithDomain:kARDCEODTURNClientErrorDomain
+ code:kARDCEODTURNClientErrorBadResponse
+ userInfo:@{
+ NSLocalizedDescriptionKey: @"Bad TURN response.",
+ }];
+ completionHandler(turnServers, responseError);
+ return;
+ }
+ completionHandler(turnServers, nil);
+ }];
+}
+
+@end
diff --git a/talk/examples/objc/AppRTCDemo/ARDMessageResponse+Internal.h b/talk/examples/objc/AppRTCDemo/ARDMessageResponse+Internal.h
new file mode 100644
index 0000000..e214ff3
--- /dev/null
+++ b/talk/examples/objc/AppRTCDemo/ARDMessageResponse+Internal.h
@@ -0,0 +1,34 @@
+/*
+ * 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 "ARDMessageResponse.h"
+
+@interface ARDMessageResponse ()
+
+@property(nonatomic, assign) ARDMessageResultType result;
+
+@end
diff --git a/talk/examples/objc/AppRTCDemo/ARDMessageResponse.m b/talk/examples/objc/AppRTCDemo/ARDMessageResponse.m
index c6ab1d4..496a068 100644
--- a/talk/examples/objc/AppRTCDemo/ARDMessageResponse.m
+++ b/talk/examples/objc/AppRTCDemo/ARDMessageResponse.m
@@ -25,18 +25,12 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#import "ARDMessageResponse.h"
+#import "ARDMessageResponse+Internal.h"
#import "ARDUtilities.h"
static NSString const *kARDMessageResultKey = @"result";
-@interface ARDMessageResponse ()
-
-@property(nonatomic, assign) ARDMessageResultType result;
-
-@end
-
@implementation ARDMessageResponse
@synthesize result = _result;
diff --git a/talk/examples/objc/AppRTCDemo/ARDRegisterResponse+Internal.h b/talk/examples/objc/AppRTCDemo/ARDRegisterResponse+Internal.h
new file mode 100644
index 0000000..eb2b0b3
--- /dev/null
+++ b/talk/examples/objc/AppRTCDemo/ARDRegisterResponse+Internal.h
@@ -0,0 +1,40 @@
+/*
+ * 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 "ARDRegisterResponse.h"
+
+@interface ARDRegisterResponse ()
+
+@property(nonatomic, assign) ARDRegisterResultType result;
+@property(nonatomic, assign) BOOL isInitiator;
+@property(nonatomic, strong) NSString *roomId;
+@property(nonatomic, strong) NSString *clientId;
+@property(nonatomic, strong) NSArray *messages;
+@property(nonatomic, strong) NSURL *webSocketURL;
+@property(nonatomic, strong) NSURL *webSocketRestURL;
+
+@end
diff --git a/talk/examples/objc/AppRTCDemo/ARDRegisterResponse.m b/talk/examples/objc/AppRTCDemo/ARDRegisterResponse.m
index 76eb15c..55c467e 100644
--- a/talk/examples/objc/AppRTCDemo/ARDRegisterResponse.m
+++ b/talk/examples/objc/AppRTCDemo/ARDRegisterResponse.m
@@ -25,7 +25,7 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#import "ARDRegisterResponse.h"
+#import "ARDRegisterResponse+Internal.h"
#import "ARDSignalingMessage.h"
#import "ARDUtilities.h"
@@ -40,18 +40,6 @@
static NSString const *kARDRegisterWebSocketURLKey = @"wss_url";
static NSString const *kARDRegisterWebSocketRestURLKey = @"wss_post_url";
-@interface ARDRegisterResponse ()
-
-@property(nonatomic, assign) ARDRegisterResultType result;
-@property(nonatomic, assign) BOOL isInitiator;
-@property(nonatomic, strong) NSString *roomId;
-@property(nonatomic, strong) NSString *clientId;
-@property(nonatomic, strong) NSArray *messages;
-@property(nonatomic, strong) NSURL *webSocketURL;
-@property(nonatomic, strong) NSURL *webSocketRestURL;
-
-@end
-
@implementation ARDRegisterResponse
@synthesize result = _result;
diff --git a/talk/examples/objc/AppRTCDemo/ARDRoomServerClient.h b/talk/examples/objc/AppRTCDemo/ARDRoomServerClient.h
new file mode 100644
index 0000000..a650187
--- /dev/null
+++ b/talk/examples/objc/AppRTCDemo/ARDRoomServerClient.h
@@ -0,0 +1,50 @@
+/*
+ * 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>
+
+@class ARDMessageResponse;
+@class ARDRegisterResponse;
+@class ARDSignalingMessage;
+
+@protocol ARDRoomServerClient <NSObject>
+
+- (void)registerForRoomId:(NSString *)roomId
+ completionHandler:(void (^)(ARDRegisterResponse *response,
+ NSError *error))completionHandler;
+
+- (void)sendMessage:(ARDSignalingMessage *)message
+ forRoomId:(NSString *)roomId
+ clientId:(NSString *)clientId
+ completionHandler:(void (^)(ARDMessageResponse *response,
+ NSError *error))completionHandler;
+
+- (void)deregisterForRoomId:(NSString *)roomId
+ clientId:(NSString *)clientId
+ completionHandler:(void (^)(NSError *error))completionHandler;
+
+@end
diff --git a/talk/examples/objc/AppRTCDemo/ARDSignalingChannel.h b/talk/examples/objc/AppRTCDemo/ARDSignalingChannel.h
new file mode 100644
index 0000000..aedbb42
--- /dev/null
+++ b/talk/examples/objc/AppRTCDemo/ARDSignalingChannel.h
@@ -0,0 +1,69 @@
+/*
+ * 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>
+
+#import "ARDSignalingMessage.h"
+
+typedef NS_ENUM(NSInteger, ARDSignalingChannelState) {
+ // State when disconnected.
+ kARDSignalingChannelStateClosed,
+ // State when connection is established but not ready for use.
+ kARDSignalingChannelStateOpen,
+ // State when connection is established and registered.
+ kARDSignalingChannelStateRegistered,
+ // State when connection encounters a fatal error.
+ kARDSignalingChannelStateError
+};
+
+@protocol ARDSignalingChannel;
+@protocol ARDSignalingChannelDelegate <NSObject>
+
+- (void)channel:(id<ARDSignalingChannel>)channel
+ didChangeState:(ARDSignalingChannelState)state;
+
+- (void)channel:(id<ARDSignalingChannel>)channel
+ didReceiveMessage:(ARDSignalingMessage *)message;
+
+@end
+
+@protocol ARDSignalingChannel <NSObject>
+
+@property(nonatomic, readonly) NSString *roomId;
+@property(nonatomic, readonly) NSString *clientId;
+@property(nonatomic, readonly) ARDSignalingChannelState state;
+@property(nonatomic, weak) id<ARDSignalingChannelDelegate> delegate;
+
+// Registers the channel for the given room and client id.
+- (void)registerForRoomId:(NSString *)roomId
+ clientId:(NSString *)clientId;
+
+// Sends signaling message over the channel.
+- (void)sendMessage:(ARDSignalingMessage *)message;
+
+@end
+
diff --git a/talk/examples/objc/AppRTCDemo/ARDTURNClient.h b/talk/examples/objc/AppRTCDemo/ARDTURNClient.h
new file mode 100644
index 0000000..96856ea
--- /dev/null
+++ b/talk/examples/objc/AppRTCDemo/ARDTURNClient.h
@@ -0,0 +1,37 @@
+/*
+ * 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>
+
+@protocol ARDTURNClient <NSObject>
+
+// Returns TURN server urls if successful.
+- (void)requestServersWithCompletionHandler:
+ (void (^)(NSArray *turnServers,
+ NSError *error))completionHandler;
+
+@end
diff --git a/talk/examples/objc/AppRTCDemo/ARDWebSocketChannel.h b/talk/examples/objc/AppRTCDemo/ARDWebSocketChannel.h
index 06c6520..c3af1d4 100644
--- a/talk/examples/objc/AppRTCDemo/ARDWebSocketChannel.h
+++ b/talk/examples/objc/AppRTCDemo/ARDWebSocketChannel.h
@@ -27,49 +27,22 @@
#import <Foundation/Foundation.h>
-#import "ARDSignalingMessage.h"
-
-typedef NS_ENUM(NSInteger, ARDWebSocketChannelState) {
- // State when disconnected.
- kARDWebSocketChannelStateClosed,
- // State when connection is established but not ready for use.
- kARDWebSocketChannelStateOpen,
- // State when connection is established and registered.
- kARDWebSocketChannelStateRegistered,
- // State when connection encounters a fatal error.
- kARDWebSocketChannelStateError
-};
-
-@class ARDWebSocketChannel;
-@protocol ARDWebSocketChannelDelegate <NSObject>
-
-- (void)channel:(ARDWebSocketChannel *)channel
- didChangeState:(ARDWebSocketChannelState)state;
-
-- (void)channel:(ARDWebSocketChannel *)channel
- didReceiveMessage:(ARDSignalingMessage *)message;
-
-@end
+#import "ARDSignalingChannel.h"
// Wraps a WebSocket connection to the AppRTC WebSocket server.
-@interface ARDWebSocketChannel : NSObject
-
-@property(nonatomic, readonly) NSString *roomId;
-@property(nonatomic, readonly) NSString *clientId;
-@property(nonatomic, readonly) ARDWebSocketChannelState state;
-@property(nonatomic, weak) id<ARDWebSocketChannelDelegate> delegate;
+@interface ARDWebSocketChannel : NSObject <ARDSignalingChannel>
- (instancetype)initWithURL:(NSURL *)url
restURL:(NSURL *)restURL
- delegate:(id<ARDWebSocketChannelDelegate>)delegate;
+ delegate:(id<ARDSignalingChannelDelegate>)delegate;
// Registers with the WebSocket server for the given room and client id once
// the web socket connection is open.
- (void)registerForRoomId:(NSString *)roomId
clientId:(NSString *)clientId;
-// Sends data over the WebSocket connection if registered, otherwise POSTs to
+// Sends message over the WebSocket connection if registered, otherwise POSTs to
// the web socket server instead.
-- (void)sendData:(NSData *)data;
+- (void)sendMessage:(ARDSignalingMessage *)message;
@end
diff --git a/talk/examples/objc/AppRTCDemo/ARDWebSocketChannel.m b/talk/examples/objc/AppRTCDemo/ARDWebSocketChannel.m
index 1707201..688f66d 100644
--- a/talk/examples/objc/AppRTCDemo/ARDWebSocketChannel.m
+++ b/talk/examples/objc/AppRTCDemo/ARDWebSocketChannel.m
@@ -50,7 +50,7 @@
- (instancetype)initWithURL:(NSURL *)url
restURL:(NSURL *)restURL
- delegate:(id<ARDWebSocketChannelDelegate>)delegate {
+ delegate:(id<ARDSignalingChannelDelegate>)delegate {
if (self = [super init]) {
_url = url;
_restURL = restURL;
@@ -67,7 +67,7 @@
[self disconnect];
}
-- (void)setState:(ARDWebSocketChannelState)state {
+- (void)setState:(ARDSignalingChannelState)state {
if (_state == state) {
return;
}
@@ -81,15 +81,16 @@
NSParameterAssert(clientId.length);
_roomId = roomId;
_clientId = clientId;
- if (_state == kARDWebSocketChannelStateOpen) {
+ if (_state == kARDSignalingChannelStateOpen) {
[self registerWithCollider];
}
}
-- (void)sendData:(NSData *)data {
+- (void)sendMessage:(ARDSignalingMessage *)message {
NSParameterAssert(_clientId.length);
NSParameterAssert(_roomId.length);
- if (_state == kARDWebSocketChannelStateRegistered) {
+ NSData *data = [message JSONData];
+ if (_state == kARDSignalingChannelStateRegistered) {
NSString *payload =
[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSDictionary *message = @{
@@ -120,8 +121,8 @@
}
- (void)disconnect {
- if (_state == kARDWebSocketChannelStateClosed ||
- _state == kARDWebSocketChannelStateError) {
+ if (_state == kARDSignalingChannelStateClosed ||
+ _state == kARDSignalingChannelStateError) {
return;
}
[_socket close];
@@ -140,7 +141,7 @@
- (void)webSocketDidOpen:(SRWebSocket *)webSocket {
NSLog(@"WebSocket connection opened.");
- self.state = kARDWebSocketChannelStateOpen;
+ self.state = kARDSignalingChannelStateOpen;
if (_roomId.length && _clientId.length) {
[self registerWithCollider];
}
@@ -171,7 +172,7 @@
- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error {
NSLog(@"WebSocket error: %@", error);
- self.state = kARDWebSocketChannelStateError;
+ self.state = kARDSignalingChannelStateError;
}
- (void)webSocket:(SRWebSocket *)webSocket
@@ -180,14 +181,14 @@
wasClean:(BOOL)wasClean {
NSLog(@"WebSocket closed with code: %ld reason:%@ wasClean:%d",
(long)code, reason, wasClean);
- NSParameterAssert(_state != kARDWebSocketChannelStateError);
- self.state = kARDWebSocketChannelStateClosed;
+ NSParameterAssert(_state != kARDSignalingChannelStateError);
+ self.state = kARDSignalingChannelStateClosed;
}
#pragma mark - Private
- (void)registerWithCollider {
- if (_state == kARDWebSocketChannelStateRegistered) {
+ if (_state == kARDSignalingChannelStateRegistered) {
return;
}
NSParameterAssert(_roomId.length);
@@ -207,7 +208,7 @@
// Registration can fail if server rejects it. For example, if the room is
// full.
[_socket send:messageString];
- self.state = kARDWebSocketChannelStateRegistered;
+ self.state = kARDSignalingChannelStateRegistered;
}
@end
diff --git a/talk/examples/objc/AppRTCDemo/ios/APPRTCViewController.m b/talk/examples/objc/AppRTCDemo/ios/APPRTCViewController.m
index 3d60ee7..e6e19b0 100644
--- a/talk/examples/objc/AppRTCDemo/ios/APPRTCViewController.m
+++ b/talk/examples/objc/AppRTCDemo/ios/APPRTCViewController.m
@@ -108,6 +108,10 @@
}
- (void)appClient:(ARDAppClient *)client
+ didChangeConnectionState:(RTCICEConnectionState)state {
+}
+
+- (void)appClient:(ARDAppClient *)client
didReceiveLocalVideoTrack:(RTCVideoTrack *)localVideoTrack {
_localVideoTrack = localVideoTrack;
[_localVideoTrack addRenderer:self.localVideoView];
diff --git a/talk/examples/objc/AppRTCDemo/mac/APPRTCViewController.m b/talk/examples/objc/AppRTCDemo/mac/APPRTCViewController.m
index 40d1307..41bfd35 100644
--- a/talk/examples/objc/AppRTCDemo/mac/APPRTCViewController.m
+++ b/talk/examples/objc/AppRTCDemo/mac/APPRTCViewController.m
@@ -267,6 +267,10 @@
}
- (void)appClient:(ARDAppClient *)client
+ didChangeConnectionState:(RTCICEConnectionState)state {
+}
+
+- (void)appClient:(ARDAppClient *)client
didReceiveLocalVideoTrack:(RTCVideoTrack *)localVideoTrack {
_localVideoTrack = localVideoTrack;
}
diff --git a/talk/examples/objc/AppRTCDemo/tests/ARDAppClientTest.mm b/talk/examples/objc/AppRTCDemo/tests/ARDAppClientTest.mm
new file mode 100644
index 0000000..171d244
--- /dev/null
+++ b/talk/examples/objc/AppRTCDemo/tests/ARDAppClientTest.mm
@@ -0,0 +1,323 @@
+/*
+ * 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>
+#import <OCMock/OCMock.h>
+
+#import "ARDAppClient+Internal.h"
+#import "ARDRegisterResponse+Internal.h"
+#import "ARDMessageResponse+Internal.h"
+#import "RTCMediaConstraints.h"
+#import "RTCPeerConnectionFactory.h"
+
+#include "webrtc/base/gunit.h"
+#include "webrtc/base/ssladapter.h"
+
+// These classes mimic XCTest APIs, to make eventual conversion to XCTest
+// easier. Conversion will happen once XCTest is supported well on build bots.
+@interface ARDTestExpectation : NSObject
+
+@property(nonatomic, readonly) NSString *description;
+@property(nonatomic, readonly) BOOL isFulfilled;
+
+- (instancetype)initWithDescription:(NSString *)description;
+- (void)fulfill;
+
+@end
+
+@implementation ARDTestExpectation
+
+@synthesize description = _description;
+@synthesize isFulfilled = _isFulfilled;
+
+- (instancetype)initWithDescription:(NSString *)description {
+ if (self = [super init]) {
+ _description = description;
+ }
+ return self;
+}
+
+- (void)fulfill {
+ _isFulfilled = YES;
+}
+
+@end
+
+@interface ARDTestCase : NSObject
+
+- (ARDTestExpectation *)expectationWithDescription:(NSString *)description;
+- (void)waitForExpectationsWithTimeout:(NSTimeInterval)timeout
+ handler:(void (^)(NSError *error))handler;
+
+@end
+
+@implementation ARDTestCase {
+ NSMutableArray *_expectations;
+}
+
+- (instancetype)init {
+ if (self = [super init]) {
+ _expectations = [NSMutableArray array];
+ }
+ return self;
+}
+
+- (ARDTestExpectation *)expectationWithDescription:(NSString *)description {
+ ARDTestExpectation *expectation =
+ [[ARDTestExpectation alloc] initWithDescription:description];
+ [_expectations addObject:expectation];
+ return expectation;
+}
+
+- (void)waitForExpectationsWithTimeout:(NSTimeInterval)timeout
+ handler:(void (^)(NSError *error))handler {
+ NSDate *startDate = [NSDate date];
+ while (![self areExpectationsFulfilled]) {
+ NSTimeInterval duration = [[NSDate date] timeIntervalSinceDate:startDate];
+ if (duration > timeout) {
+ NSAssert(NO, @"Expectation timed out.");
+ break;
+ }
+ [[NSRunLoop currentRunLoop]
+ runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
+ }
+ handler(nil);
+}
+
+- (BOOL)areExpectationsFulfilled {
+ for (ARDTestExpectation *expectation in _expectations) {
+ if (!expectation.isFulfilled) {
+ return NO;
+ }
+ }
+ return YES;
+}
+
+@end
+
+@interface ARDAppClientTest : ARDTestCase
+@end
+
+@implementation ARDAppClientTest
+
+#pragma mark - Mock helpers
+
+- (id)mockRoomServerClientForRoomId:(NSString *)roomId
+ clientId:(NSString *)clientId
+ isInitiator:(BOOL)isInitiator
+ messages:(NSArray *)messages
+ messageHandler:
+ (void (^)(ARDSignalingMessage *))messageHandler {
+ id mockRoomServerClient =
+ [OCMockObject mockForProtocol:@protocol(ARDRoomServerClient)];
+
+ // Successful register response.
+ ARDRegisterResponse *registerResponse = [[ARDRegisterResponse alloc] init];
+ registerResponse.result = kARDRegisterResultTypeSuccess;
+ registerResponse.roomId = roomId;
+ registerResponse.clientId = clientId;
+ registerResponse.isInitiator = isInitiator;
+ registerResponse.messages = messages;
+
+ // Successful message response.
+ ARDMessageResponse *messageResponse = [[ARDMessageResponse alloc] init];
+ messageResponse.result = kARDMessageResultTypeSuccess;
+
+ // Return register response from above on register.
+ [[[mockRoomServerClient stub] andDo:^(NSInvocation *invocation) {
+ __unsafe_unretained void (^completionHandler)(ARDRegisterResponse *response,
+ NSError *error);
+ [invocation getArgument:&completionHandler atIndex:3];
+ completionHandler(registerResponse, nil);
+ }] registerForRoomId:roomId completionHandler:[OCMArg any]];
+
+ // Return message response from above on register.
+ [[[mockRoomServerClient stub] andDo:^(NSInvocation *invocation) {
+ __unsafe_unretained ARDSignalingMessage *message;
+ __unsafe_unretained void (^completionHandler)(ARDMessageResponse *response,
+ NSError *error);
+ [invocation getArgument:&message atIndex:2];
+ [invocation getArgument:&completionHandler atIndex:5];
+ messageHandler(message);
+ completionHandler(messageResponse, nil);
+ }] sendMessage:[OCMArg any]
+ forRoomId:roomId
+ clientId:clientId
+ completionHandler:[OCMArg any]];
+
+ // Do nothing on deregister.
+ [[[mockRoomServerClient stub] andDo:^(NSInvocation *invocation) {
+ __unsafe_unretained void (^completionHandler)(NSError *error);
+ [invocation getArgument:&completionHandler atIndex:4];
+ if (completionHandler) {
+ completionHandler(nil);
+ }
+ }] deregisterForRoomId:roomId
+ clientId:clientId
+ completionHandler:[OCMArg any]];
+
+ return mockRoomServerClient;
+}
+
+- (id)mockSignalingChannelForRoomId:(NSString *)roomId
+ clientId:(NSString *)clientId
+ messageHandler:
+ (void (^)(ARDSignalingMessage *message))messageHandler {
+ id mockSignalingChannel =
+ [OCMockObject niceMockForProtocol:@protocol(ARDSignalingChannel)];
+ [[mockSignalingChannel stub] registerForRoomId:roomId clientId:clientId];
+ [[[mockSignalingChannel stub] andDo:^(NSInvocation *invocation) {
+ __unsafe_unretained ARDSignalingMessage *message;
+ [invocation getArgument:&message atIndex:2];
+ messageHandler(message);
+ }] sendMessage:[OCMArg any]];
+ return mockSignalingChannel;
+}
+
+- (id)mockTURNClient {
+ id mockTURNClient =
+ [OCMockObject mockForProtocol:@protocol(ARDTURNClient)];
+ [[[mockTURNClient stub] andDo:^(NSInvocation *invocation) {
+ // Don't return anything in TURN response.
+ __unsafe_unretained void (^completionHandler)(NSArray *turnServers,
+ NSError *error);
+ [invocation getArgument:&completionHandler atIndex:2];
+ completionHandler([NSArray array], nil);
+ }] requestServersWithCompletionHandler:[OCMArg any]];
+ return mockTURNClient;
+}
+
+- (ARDAppClient *)createAppClientForRoomId:(NSString *)roomId
+ clientId:(NSString *)clientId
+ isInitiator:(BOOL)isInitiator
+ messages:(NSArray *)messages
+ messageHandler:
+ (void (^)(ARDSignalingMessage *message))messageHandler
+ connectedHandler:(void (^)(void))connectedHandler {
+ id turnClient = [self mockTURNClient];
+ id signalingChannel = [self mockSignalingChannelForRoomId:roomId
+ clientId:clientId
+ messageHandler:messageHandler];
+ id roomServerClient =
+ [self mockRoomServerClientForRoomId:roomId
+ clientId:clientId
+ isInitiator:isInitiator
+ messages:messages
+ messageHandler:messageHandler];
+ id delegate =
+ [OCMockObject niceMockForProtocol:@protocol(ARDAppClientDelegate)];
+ [[[delegate stub] andDo:^(NSInvocation *invocation) {
+ connectedHandler();
+ }] appClient:[OCMArg any] didChangeConnectionState:RTCICEConnectionConnected];
+
+ return [[ARDAppClient alloc] initWithRoomServerClient:roomServerClient
+ signalingChannel:signalingChannel
+ turnClient:turnClient
+ delegate:delegate];
+}
+
+// Tests that an ICE connection is established between two ARDAppClient objects
+// where one is set up as a caller and the other the answerer. Network
+// components are mocked out and messages are relayed directly from object to
+// object. It's expected that both clients reach the RTCICEConnectionConnected
+// state within a reasonable amount of time.
+- (void)testSession {
+ // Need block arguments here because we're setting up a callbacks before we
+ // create the clients.
+ ARDAppClient *caller = nil;
+ ARDAppClient *answerer = nil;
+ __block __weak ARDAppClient *weakCaller = nil;
+ __block __weak ARDAppClient *weakAnswerer = nil;
+ NSString *roomId = @"testRoom";
+ NSString *callerId = @"testCallerId";
+ NSString *answererId = @"testAnswererId";
+
+ ARDTestExpectation *callerConnectionExpectation =
+ [self expectationWithDescription:@"Caller PC connected."];
+ ARDTestExpectation *answererConnectionExpectation =
+ [self expectationWithDescription:@"Answerer PC connected."];
+
+ caller = [self createAppClientForRoomId:roomId
+ clientId:callerId
+ isInitiator:YES
+ messages:[NSArray array]
+ messageHandler:^(ARDSignalingMessage *message) {
+ ARDAppClient *strongAnswerer = weakAnswerer;
+ [strongAnswerer channel:strongAnswerer.channel didReceiveMessage:message];
+ } connectedHandler:^{
+ [callerConnectionExpectation fulfill];
+ }];
+ // TODO(tkchin): Figure out why DTLS-SRTP constraint causes thread assertion
+ // crash in Debug.
+ caller.defaultPeerConnectionConstraints = [[RTCMediaConstraints alloc] init];
+ weakCaller = caller;
+
+ answerer = [self createAppClientForRoomId:roomId
+ clientId:answererId
+ isInitiator:NO
+ messages:[NSArray array]
+ messageHandler:^(ARDSignalingMessage *message) {
+ ARDAppClient *strongCaller = weakCaller;
+ [strongCaller channel:strongCaller.channel didReceiveMessage:message];
+ } connectedHandler:^{
+ [answererConnectionExpectation fulfill];
+ }];
+ // TODO(tkchin): Figure out why DTLS-SRTP constraint causes thread assertion
+ // crash in Debug.
+ answerer.defaultPeerConnectionConstraints =
+ [[RTCMediaConstraints alloc] init];
+ weakAnswerer = answerer;
+
+ // Kick off connection.
+ [caller connectToRoomWithId:roomId options:nil];
+ [answerer connectToRoomWithId:roomId options:nil];
+ [self waitForExpectationsWithTimeout:20 handler:^(NSError *error) {
+ if (error) {
+ NSLog(@"Expectations error: %@", error);
+ }
+ }];
+}
+
+@end
+
+class SignalingTest : public ::testing::Test {
+ protected:
+ static void SetUpTestCase() {
+ rtc::InitializeSSL();
+ }
+ static void TearDownTestCase() {
+ rtc::CleanupSSL();
+ }
+};
+
+TEST_F(SignalingTest, SessionTest) {
+ @autoreleasepool {
+ ARDAppClientTest *test = [[ARDAppClientTest alloc] init];
+ [test testSession];
+ }
+}
diff --git a/talk/libjingle.gyp b/talk/libjingle.gyp
index 56d29af..29a23bd 100755
--- a/talk/libjingle.gyp
+++ b/talk/libjingle.gyp
@@ -278,6 +278,11 @@
'-lstdc++',
],
},
+ 'all_dependent_settings': {
+ 'xcode_settings': {
+ 'CLANG_ENABLE_OBJC_ARC': 'YES',
+ },
+ },
'xcode_settings': {
'CLANG_ENABLE_OBJC_ARC': 'YES',
# common.gypi enables this for mac but we want this to be disabled
diff --git a/talk/libjingle_examples.gyp b/talk/libjingle_examples.gyp
index aba386b..a94610f 100755
--- a/talk/libjingle_examples.gyp
+++ b/talk/libjingle_examples.gyp
@@ -148,14 +148,70 @@
['OS=="ios" or (OS=="mac" and target_arch!="ia32" and mac_sdk>="10.8")', {
'targets': [
+ { 'target_name': 'apprtc_signaling',
+ 'type': 'static_library',
+ 'dependencies': [
+ 'libjingle.gyp:libjingle_peerconnection_objc',
+ 'socketrocket',
+ ],
+ 'sources': [
+ 'examples/objc/AppRTCDemo/ARDAppClient.h',
+ 'examples/objc/AppRTCDemo/ARDAppClient.m',
+ 'examples/objc/AppRTCDemo/ARDAppClient+Internal.h',
+ 'examples/objc/AppRTCDemo/ARDAppEngineClient.h',
+ 'examples/objc/AppRTCDemo/ARDAppEngineClient.m',
+ 'examples/objc/AppRTCDemo/ARDCEODTURNClient.h',
+ 'examples/objc/AppRTCDemo/ARDCEODTURNClient.m',
+ 'examples/objc/AppRTCDemo/ARDMessageResponse.h',
+ 'examples/objc/AppRTCDemo/ARDMessageResponse.m',
+ 'examples/objc/AppRTCDemo/ARDMessageResponse+Internal.h',
+ 'examples/objc/AppRTCDemo/ARDRegisterResponse.h',
+ 'examples/objc/AppRTCDemo/ARDRegisterResponse.m',
+ 'examples/objc/AppRTCDemo/ARDRegisterResponse+Internal.h',
+ 'examples/objc/AppRTCDemo/ARDRoomServerClient.h',
+ 'examples/objc/AppRTCDemo/ARDSignalingChannel.h',
+ 'examples/objc/AppRTCDemo/ARDSignalingMessage.h',
+ 'examples/objc/AppRTCDemo/ARDSignalingMessage.m',
+ 'examples/objc/AppRTCDemo/ARDTURNClient.h',
+ 'examples/objc/AppRTCDemo/ARDUtilities.h',
+ 'examples/objc/AppRTCDemo/ARDUtilities.m',
+ 'examples/objc/AppRTCDemo/ARDWebSocketChannel.h',
+ 'examples/objc/AppRTCDemo/ARDWebSocketChannel.m',
+ 'examples/objc/AppRTCDemo/RTCICECandidate+JSON.h',
+ 'examples/objc/AppRTCDemo/RTCICECandidate+JSON.m',
+ 'examples/objc/AppRTCDemo/RTCICEServer+JSON.h',
+ 'examples/objc/AppRTCDemo/RTCICEServer+JSON.m',
+ 'examples/objc/AppRTCDemo/RTCMediaConstraints+JSON.h',
+ 'examples/objc/AppRTCDemo/RTCMediaConstraints+JSON.m',
+ 'examples/objc/AppRTCDemo/RTCSessionDescription+JSON.h',
+ 'examples/objc/AppRTCDemo/RTCSessionDescription+JSON.m',
+ ],
+ 'include_dirs': [
+ 'examples/objc/APPRTCDemo',
+ ],
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ 'examples/objc/APPRTCDemo',
+ ],
+ },
+ 'export_dependent_settings': [
+ 'libjingle.gyp:libjingle_peerconnection_objc',
+ ],
+ 'conditions': [
+ ['OS=="mac"', {
+ 'xcode_settings': {
+ 'MACOSX_DEPLOYMENT_TARGET' : '10.8',
+ },
+ }],
+ ],
+ },
{
'target_name': 'AppRTCDemo',
'type': 'executable',
'product_name': 'AppRTCDemo',
'mac_bundle': 1,
'dependencies': [
- 'libjingle.gyp:libjingle_peerconnection_objc',
- 'socketrocket',
+ 'apprtc_signaling',
],
'conditions': [
['OS=="ios"', {
@@ -199,34 +255,6 @@
],
}],
],
- 'include_dirs': [
- 'examples/objc/APPRTCDemo',
- ],
- 'sources': [
- 'examples/objc/AppRTCDemo/ARDAppClient.h',
- 'examples/objc/AppRTCDemo/ARDAppClient.m',
- 'examples/objc/AppRTCDemo/ARDMessageResponse.h',
- 'examples/objc/AppRTCDemo/ARDMessageResponse.m',
- 'examples/objc/AppRTCDemo/ARDRegisterResponse.h',
- 'examples/objc/AppRTCDemo/ARDRegisterResponse.m',
- 'examples/objc/AppRTCDemo/ARDSignalingMessage.h',
- 'examples/objc/AppRTCDemo/ARDSignalingMessage.m',
- 'examples/objc/AppRTCDemo/ARDUtilities.h',
- 'examples/objc/AppRTCDemo/ARDUtilities.m',
- 'examples/objc/AppRTCDemo/ARDWebSocketChannel.h',
- 'examples/objc/AppRTCDemo/ARDWebSocketChannel.m',
- 'examples/objc/AppRTCDemo/RTCICECandidate+JSON.h',
- 'examples/objc/AppRTCDemo/RTCICECandidate+JSON.m',
- 'examples/objc/AppRTCDemo/RTCICEServer+JSON.h',
- 'examples/objc/AppRTCDemo/RTCICEServer+JSON.m',
- 'examples/objc/AppRTCDemo/RTCMediaConstraints+JSON.h',
- 'examples/objc/AppRTCDemo/RTCMediaConstraints+JSON.m',
- 'examples/objc/AppRTCDemo/RTCSessionDescription+JSON.h',
- 'examples/objc/AppRTCDemo/RTCSessionDescription+JSON.m',
- ],
- 'xcode_settings': {
- 'CLANG_ENABLE_OBJC_ARC': 'YES',
- },
}, # target AppRTCDemo
{
# TODO(tkchin): move this into the real third party location and
diff --git a/talk/libjingle_tests.gyp b/talk/libjingle_tests.gyp
index c8d78c2..ff120f3 100755
--- a/talk/libjingle_tests.gyp
+++ b/talk/libjingle_tests.gyp
@@ -72,7 +72,7 @@
{
'target_name': 'libjingle_unittest',
'type': 'executable',
- 'includes': [ 'build/ios_tests.gypi', ],
+ 'includes': [ 'build/objc_app.gypi', ],
'dependencies': [
'<(webrtc_root)/base/base.gyp:rtc_base',
'<(webrtc_root)/base/base_tests.gyp:rtc_base_tests_utils',
@@ -341,7 +341,7 @@
{
'target_name': 'libjingle_peerconnection_objc_test',
'type': 'executable',
- 'includes': [ 'build/ios_tests.gypi', ],
+ 'includes': [ 'build/objc_app.gypi' ],
'dependencies': [
'<(webrtc_root)/base/base_tests.gyp:rtc_base_tests_utils',
'libjingle.gyp:libjingle_peerconnection_objc',
@@ -356,46 +356,40 @@
# needs a GUI driver.
'app/webrtc/objctests/mac/main.mm',
],
- 'FRAMEWORK_SEARCH_PATHS': [
- '$(inherited)',
- '$(SDKROOT)/Developer/Library/Frameworks',
- '$(DEVELOPER_LIBRARY_DIR)/Frameworks',
- ],
-
- # TODO(fischman): there is duplication here with
- # build/ios_tests.gypi, because for historical reasons the
- # mac x64 bots expect this unittest to be in a bundle
- # directory (.app). Once the bots don't expect this
- # anymore, remove this duplication.
- 'variables': {
- 'infoplist_file': 'build/ios_test.plist',
- },
- 'mac_bundle': 1,
- 'mac_bundle_resources': [
- '<(infoplist_file)',
- ],
- # The plist is listed above so that it appears in XCode's file list,
- # but we don't actually want to bundle it.
- 'mac_bundle_resources!': [
- '<(infoplist_file)',
- ],
- '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',
+ # 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',
},
}],
],
}, # target libjingle_peerconnection_objc_test
+ {
+ 'target_name': 'apprtc_signaling_gunit_test',
+ 'type': 'executable',
+ 'includes': [ 'build/objc_app.gypi' ],
+ 'dependencies': [
+ '<(webrtc_root)/base/base_tests.gyp:rtc_base_tests_utils',
+ '<(DEPTH)/third_party/ocmock/ocmock.gyp:ocmock',
+ 'libjingle_examples.gyp:apprtc_signaling',
+ ],
+ 'sources': [
+ 'app/webrtc/objctests/mac/main.mm',
+ 'examples/objc/AppRTCDemo/tests/ARDAppClientTest.mm',
+ ],
+ 'conditions': [
+ ['OS=="mac"', {
+ 'xcode_settings': {
+ 'MACOSX_DEPLOYMENT_TARGET' : '10.8',
+ },
+ }],
+ ],
+ }, # target apprtc_signaling_gunit_test
],
}],
['test_isolation_mode != "noop"', {