15976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org/*
25976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * libjingle
35976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * Copyright 2013, Google Inc.
45976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *
55976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * Redistribution and use in source and binary forms, with or without
65976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * modification, are permitted provided that the following conditions are met:
75976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *
85976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *  1. Redistributions of source code must retain the above copyright notice,
95976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *     this list of conditions and the following disclaimer.
105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *  2. Redistributions in binary form must reproduce the above copyright notice,
115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *     this list of conditions and the following disclaimer in the documentation
125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *     and/or other materials provided with the distribution.
135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *  3. The name of the author may not be used to endorse or promote products
145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *     derived from this software without specific prior written permission.
155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *
165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org */
275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#import "APPRTCAppDelegate.h"
295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#import "APPRTCViewController.h"
31c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org#import "RTCICECandidate.h"
32c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org#import "RTCICEServer.h"
335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#import "RTCMediaConstraints.h"
345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#import "RTCMediaStream.h"
355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#import "RTCPair.h"
365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#import "RTCPeerConnection.h"
375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#import "RTCPeerConnectionDelegate.h"
385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#import "RTCPeerConnectionFactory.h"
395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#import "RTCSessionDescription.h"
405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org@interface PCObserver : NSObject<RTCPeerConnectionDelegate>
425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org- (id)initWithDelegate:(id<APPRTCSendMessage>)delegate;
445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org@end
465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org@implementation PCObserver {
485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  id<APPRTCSendMessage> _delegate;
495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org- (id)initWithDelegate:(id<APPRTCSendMessage>)delegate {
525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (self = [super init]) {
535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    _delegate = delegate;
545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return self;
565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org- (void)peerConnectionOnError:(RTCPeerConnection *)peerConnection {
595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  NSLog(@"PCO onError.");
605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  NSAssert(NO, @"PeerConnection failed.");
615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org- (void)peerConnection:(RTCPeerConnection *)peerConnection
64c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    signalingStateChanged:(RTCSignalingState)stateChanged {
655751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org  NSLog(@"PCO onSignalingStateChange: %d", stateChanged);
665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org- (void)peerConnection:(RTCPeerConnection *)peerConnection
69c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org             addedStream:(RTCMediaStream *)stream {
705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  NSLog(@"PCO onAddStream.");
715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  dispatch_async(dispatch_get_main_queue(), ^(void) {
725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    NSAssert([stream.audioTracks count] >= 1,
735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org             @"Expected at least 1 audio stream");
745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    //NSAssert([stream.videoTracks count] >= 1,
755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    //         @"Expected at least 1 video stream");
765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // TODO(hughv): Add video support
775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  });
785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org- (void)peerConnection:(RTCPeerConnection *)peerConnection
81c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org         removedStream:(RTCMediaStream *)stream {
825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  NSLog(@"PCO onRemoveStream.");
835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // TODO(hughv): Remove video track.
845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org- (void)
875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    peerConnectionOnRenegotiationNeeded:(RTCPeerConnection *)peerConnection {
885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  NSLog(@"PCO onRenegotiationNeeded.");
895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // TODO(hughv): Handle this.
905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org- (void)peerConnection:(RTCPeerConnection *)peerConnection
93c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org       gotICECandidate:(RTCICECandidate *)candidate {
94c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  NSLog(@"PCO onICECandidate.\n  Mid[%@] Index[%d] Sdp[%@]",
955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        candidate.sdpMid,
965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        candidate.sdpMLineIndex,
975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        candidate.sdp);
985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  NSDictionary *json =
995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      @{ @"type" : @"candidate",
1005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org         @"label" : [NSNumber numberWithInt:candidate.sdpMLineIndex],
1015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org         @"id" : candidate.sdpMid,
1025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org         @"candidate" : candidate.sdp };
1035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  NSError *error;
1045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  NSData *data =
1055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      [NSJSONSerialization dataWithJSONObject:json options:0 error:&error];
1065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (!error) {
1075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    [_delegate sendData:data];
1085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  } else {
1095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    NSAssert(NO, @"Unable to serialize JSON object with error: %@",
1105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org             error.localizedDescription);
1115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
1125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
1135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org- (void)peerConnection:(RTCPeerConnection *)peerConnection
115c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    iceGatheringChanged:(RTCICEGatheringState)newState {
1165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  NSLog(@"PCO onIceGatheringChange. %d", newState);
1175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
1185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org- (void)peerConnection:(RTCPeerConnection *)peerConnection
120c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    iceConnectionChanged:(RTCICEConnectionState)newState {
1215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  NSLog(@"PCO onIceConnectionChange. %d", newState);
1225751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org  if (newState == RTCICEConnectionConnected)
1235751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org    [self displayLogMessage:@"ICE Connection Connected."];
1245751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org  NSAssert(newState != RTCICEConnectionFailed, @"ICE Connection failed!");
1255751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org}
1265751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org
1275751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org- (void)displayLogMessage:(NSString *)message {
1285751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org  [_delegate displayLogMessage:message];
1295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
1305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org@end
1325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org@interface APPRTCAppDelegate ()
1345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org@property(nonatomic, strong) APPRTCAppClient *client;
1365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org@property(nonatomic, strong) PCObserver *pcObserver;
1375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org@property(nonatomic, strong) RTCPeerConnection *peerConnection;
1385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org@property(nonatomic, strong) RTCPeerConnectionFactory *peerConnectionFactory;
1395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org@property(nonatomic, strong) NSMutableArray *queuedRemoteCandidates;
1405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org@end
1425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org@implementation APPRTCAppDelegate
1445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
145582fe818e571fa2571267f5e369715188472f352wu@webrtc.org@synthesize window = _window;
146582fe818e571fa2571267f5e369715188472f352wu@webrtc.org@synthesize viewController = _viewController;
147582fe818e571fa2571267f5e369715188472f352wu@webrtc.org@synthesize client = _client;
148582fe818e571fa2571267f5e369715188472f352wu@webrtc.org@synthesize pcObserver = _pcObserver;
149582fe818e571fa2571267f5e369715188472f352wu@webrtc.org@synthesize peerConnection = _peerConnection;
150582fe818e571fa2571267f5e369715188472f352wu@webrtc.org@synthesize peerConnectionFactory = _peerConnectionFactory;
151582fe818e571fa2571267f5e369715188472f352wu@webrtc.org@synthesize queuedRemoteCandidates = _queuedRemoteCandidates;
152582fe818e571fa2571267f5e369715188472f352wu@webrtc.org
1535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#pragma mark - UIApplicationDelegate methods
1545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org- (BOOL)application:(UIApplication *)application
1565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
157c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  [RTCPeerConnectionFactory initializeSSL];
1585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
1595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  self.viewController =
160c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org      [[APPRTCViewController alloc] initWithNibName:@"APPRTCViewController"
1615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                             bundle:nil];
1625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  self.window.rootViewController = self.viewController;
1635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  [self.window makeKeyAndVisible];
1645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return YES;
1655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
1665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org- (void)applicationWillResignActive:(UIApplication *)application {
1685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  [self displayLogMessage:@"Application lost focus, connection broken."];
1695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  [self disconnect];
1705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  [self.viewController resetUI];
1715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
1725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org- (void)applicationDidEnterBackground:(UIApplication *)application {
1745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
1755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org- (void)applicationWillEnterForeground:(UIApplication *)application {
1775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
1785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org- (void)applicationDidBecomeActive:(UIApplication *)application {
1805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
1815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org- (void)applicationWillTerminate:(UIApplication *)application {
1835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
1845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org- (BOOL)application:(UIApplication *)application
1865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org              openURL:(NSURL *)url
1875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    sourceApplication:(NSString *)sourceApplication
1885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org           annotation:(id)annotation {
1895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (self.client) {
1905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return NO;
1915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
1925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  self.client = [[APPRTCAppClient alloc] init];
193c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  self.client.ICEServerDelegate = self;
1945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  self.client.messageHandler = self;
1955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  [self.client connectToRoom:url];
1965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return YES;
1975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
1985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org- (void)displayLogMessage:(NSString *)message {
2005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  NSLog(@"%@", message);
2015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  [self.viewController displayText:message];
2025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
2035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#pragma mark - RTCSendMessage method
2055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org- (void)sendData:(NSData *)data {
2075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  [self.client sendData:data];
2085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
2095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
210c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org#pragma mark - ICEServerDelegate method
2115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
212c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org- (void)onICEServers:(NSArray *)servers {
2135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  self.queuedRemoteCandidates = [NSMutableArray array];
2145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  self.peerConnectionFactory = [[RTCPeerConnectionFactory alloc] init];
2155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  RTCMediaConstraints *constraints = [[RTCMediaConstraints alloc] init];
2165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  self.pcObserver = [[PCObserver alloc] initWithDelegate:self];
2175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  self.peerConnection =
218c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org      [self.peerConnectionFactory peerConnectionWithICEServers:servers
2195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                                   constraints:constraints
2205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                                      delegate:self.pcObserver];
2215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  RTCMediaStream *lms =
2225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      [self.peerConnectionFactory mediaStreamWithLabel:@"ARDAMS"];
2235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // TODO(hughv): Add video.
224c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  [lms addAudioTrack:[self.peerConnectionFactory audioTrackWithID:@"ARDAMSa0"]];
225c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  [self.peerConnection addStream:lms constraints:constraints];
226c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  [self displayLogMessage:@"onICEServers - add local stream."];
2275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
2285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#pragma mark - GAEMessageHandler methods
2305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org- (void)onOpen {
2325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  [self displayLogMessage:@"GAE onOpen - create offer."];
2335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  RTCPair *audio =
2345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      [[RTCPair alloc] initWithKey:@"OfferToReceiveAudio" value:@"true"];
2355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // TODO(hughv): Add video.
2365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  //  RTCPair *video = [[RTCPair alloc] initWithKey:@"OfferToReceiveVideo"
2375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  //                                          value:@"true"];
2385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  NSArray *mandatory = @[ audio /*, video*/ ];
2395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  RTCMediaConstraints *constraints =
2405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      [[RTCMediaConstraints alloc] initWithMandatoryConstraints:mandatory
2415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                            optionalConstraints:nil];
2425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  [self.peerConnection createOfferWithDelegate:self constraints:constraints];
2435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  [self displayLogMessage:@"PC - createOffer."];
2445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
2455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org- (void)onMessage:(NSString *)data {
2475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  NSString *message = [self unHTMLifyString:data];
2485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  NSError *error;
2495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  NSDictionary *objects = [NSJSONSerialization
2505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      JSONObjectWithData:[message dataUsingEncoding:NSUTF8StringEncoding]
2515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                 options:0
2525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                   error:&error];
2535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  NSAssert(!error,
2545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org           @"%@",
2555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org           [NSString stringWithFormat:@"Error: %@", error.description]);
2565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  NSAssert([objects count] > 0, @"Invalid JSON object");
2575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  NSString *value = [objects objectForKey:@"type"];
2585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  [self displayLogMessage:
2595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          [NSString stringWithFormat:@"GAE onMessage type - %@", value]];
2605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if ([value compare:@"candidate"] == NSOrderedSame) {
2615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    NSString *mid = [objects objectForKey:@"id"];
2625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    NSNumber *sdpLineIndex = [objects objectForKey:@"label"];
2635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    NSString *sdp = [objects objectForKey:@"candidate"];
264c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    RTCICECandidate *candidate =
265c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org        [[RTCICECandidate alloc] initWithMid:mid
2665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                       index:sdpLineIndex.intValue
2675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                         sdp:sdp];
2685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (self.queuedRemoteCandidates) {
2695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      [self.queuedRemoteCandidates addObject:candidate];
2705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    } else {
271c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org      [self.peerConnection addICECandidate:candidate];
2725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
2735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  } else if (([value compare:@"offer"] == NSOrderedSame) ||
2745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org             ([value compare:@"answer"] == NSOrderedSame)) {
2755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    NSString *sdpString = [objects objectForKey:@"sdp"];
2765751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org    RTCSessionDescription *sdp = [[RTCSessionDescription alloc]
2775751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org        initWithType:value sdp:[APPRTCAppDelegate preferISAC:sdpString]];
2785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    [self.peerConnection setRemoteDescriptionWithDelegate:self
2795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                       sessionDescription:sdp];
2805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    [self displayLogMessage:@"PC - setRemoteDescription."];
2815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  } else if ([value compare:@"bye"] == NSOrderedSame) {
2825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    [self disconnect];
2835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  } else {
2845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    NSAssert(NO, @"Invalid message: %@", data);
2855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
2865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
2875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org- (void)onClose {
2895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  [self displayLogMessage:@"GAE onClose."];
2905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  [self disconnect];
2915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
2925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org- (void)onError:(int)code withDescription:(NSString *)description {
2945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  [self displayLogMessage:
2955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          [NSString stringWithFormat:@"GAE onError:  %@", description]];
2965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  [self disconnect];
2975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
2985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#pragma mark - RTCSessionDescriptonDelegate methods
3005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3015751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org// Match |pattern| to |string| and return the first group of the first
3025751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org// match, or nil if no match was found.
3035751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org+ (NSString *)firstMatch:(NSRegularExpression *)pattern
3045751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org              withString:(NSString *)string {
3055751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org  NSTextCheckingResult* result =
3065751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org    [pattern firstMatchInString:string
3075751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org                        options:0
3085751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org                          range:NSMakeRange(0, [string length])];
3095751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org  if (!result)
3105751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org    return nil;
3115751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org  return [string substringWithRange:[result rangeAtIndex:1]];
3125751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org}
3135751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org
3145751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org// Mangle |origSDP| to prefer the ISAC/16k audio codec.
3155751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org+ (NSString *)preferISAC:(NSString *)origSDP {
3165751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org  int mLineIndex = -1;
3175751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org  NSString* isac16kRtpMap = nil;
3185751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org  NSArray* lines = [origSDP componentsSeparatedByString:@"\n"];
3195751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org  NSRegularExpression* isac16kRegex = [NSRegularExpression
3205751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org      regularExpressionWithPattern:@"^a=rtpmap:(\\d+) ISAC/16000[\r]?$"
3215751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org                           options:0
3225751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org                             error:nil];
3235751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org  for (int i = 0;
3245751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org       (i < [lines count]) && (mLineIndex == -1 || isac16kRtpMap == nil);
3255751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org       ++i) {
3265751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org    NSString* line = [lines objectAtIndex:i];
3275751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org    if ([line hasPrefix:@"m=audio "]) {
3285751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org      mLineIndex = i;
3295751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org      continue;
3305751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org    }
3315751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org    isac16kRtpMap = [self firstMatch:isac16kRegex withString:line];
3325751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org  }
3335751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org  if (mLineIndex == -1) {
3345751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org    NSLog(@"No m=audio line, so can't prefer iSAC");
3355751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org    return origSDP;
3365751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org  }
3375751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org  if (isac16kRtpMap == nil) {
3385751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org    NSLog(@"No ISAC/16000 line, so can't prefer iSAC");
3395751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org    return origSDP;
3405751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org  }
3415751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org  NSArray* origMLineParts =
3425751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org      [[lines objectAtIndex:mLineIndex] componentsSeparatedByString:@" "];
3435751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org  NSMutableArray* newMLine =
3445751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org      [NSMutableArray arrayWithCapacity:[origMLineParts count]];
3455751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org  int origPartIndex = 0;
3465751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org  // Format is: m=<media> <port> <proto> <fmt> ...
3475751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org  [newMLine addObject:[origMLineParts objectAtIndex:origPartIndex++]];
3485751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org  [newMLine addObject:[origMLineParts objectAtIndex:origPartIndex++]];
3495751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org  [newMLine addObject:[origMLineParts objectAtIndex:origPartIndex++]];
3505751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org  [newMLine addObject:isac16kRtpMap];
3515751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org  for (; origPartIndex < [origMLineParts count]; ++origPartIndex) {
3525751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org    if ([isac16kRtpMap compare:[origMLineParts objectAtIndex:origPartIndex]]
3535751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org        != NSOrderedSame) {
3545751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org      [newMLine addObject:[origMLineParts objectAtIndex:origPartIndex]];
3555751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org    }
3565751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org  }
3575751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org  NSMutableArray* newLines = [NSMutableArray arrayWithCapacity:[lines count]];
3585751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org  [newLines addObjectsFromArray:lines];
3595751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org  [newLines replaceObjectAtIndex:mLineIndex
3605751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org                      withObject:[newMLine componentsJoinedByString:@" "]];
3615751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org  return [newLines componentsJoinedByString:@"\n"];
3625751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org}
3635751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org
3645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org- (void)peerConnection:(RTCPeerConnection *)peerConnection
3655751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org    didCreateSessionDescription:(RTCSessionDescription *)origSdp
366c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org                          error:(NSError *)error {
3675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (error) {
3685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    [self displayLogMessage:@"SDP onFailure."];
3695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    NSAssert(NO, error.description);
3705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return;
3715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
3725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  [self displayLogMessage:@"SDP onSuccess(SDP) - set local description."];
3745751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org  RTCSessionDescription* sdp =
3755751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org      [[RTCSessionDescription alloc]
3765751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org          initWithType:origSdp.type
3775751231c0308f2632caf502bf9f1db6eb3b679f6mikhal@webrtc.org                   sdp:[APPRTCAppDelegate preferISAC:origSdp.description]];
3785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  [self.peerConnection setLocalDescriptionWithDelegate:self
3795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                    sessionDescription:sdp];
3805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  [self displayLogMessage:@"PC setLocalDescription."];
3815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  dispatch_async(dispatch_get_main_queue(), ^(void) {
3825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    NSDictionary *json = @{ @"type" : sdp.type, @"sdp" : sdp.description };
3835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    NSError *error;
3845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    NSData *data =
3855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        [NSJSONSerialization dataWithJSONObject:json options:0 error:&error];
3865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    NSAssert(!error,
3875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org             @"%@",
3885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org             [NSString stringWithFormat:@"Error: %@", error.description]);
3895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    [self sendData:data];
3905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  });
3915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
3925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org- (void)peerConnection:(RTCPeerConnection *)peerConnection
394c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    didSetSessionDescriptionWithError:(NSError *)error {
3955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (error) {
3965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    [self displayLogMessage:@"SDP onFailure."];
3975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    NSAssert(NO, error.description);
3985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return;
3995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
4005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
4015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  [self displayLogMessage:@"SDP onSuccess() - possibly drain candidates"];
4025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  dispatch_async(dispatch_get_main_queue(), ^(void) {
4035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // TODO(hughv): Handle non-initiator case.  http://s10/46622051
4045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (self.peerConnection.remoteDescription) {
4055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      [self displayLogMessage:@"SDP onSuccess - drain candidates"];
4065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      [self drainRemoteCandidates];
4075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
4085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  });
4095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
4105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
4115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#pragma mark - internal methods
4125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
4135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org- (void)disconnect {
4145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  [self.client
4155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      sendData:[@"{\"type\": \"bye\"}" dataUsingEncoding:NSUTF8StringEncoding]];
4165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  self.peerConnection = nil;
4175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  self.peerConnectionFactory = nil;
4185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  self.pcObserver = nil;
419c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  self.client.ICEServerDelegate = nil;
4205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  self.client.messageHandler = nil;
4215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  self.client = nil;
422c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  [RTCPeerConnectionFactory deinitializeSSL];
4235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
4245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
4255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org- (void)drainRemoteCandidates {
426c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  for (RTCICECandidate *candidate in self.queuedRemoteCandidates) {
427c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    [self.peerConnection addICECandidate:candidate];
4285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
4295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  self.queuedRemoteCandidates = nil;
4305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
4315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
4325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org- (NSString *)unHTMLifyString:(NSString *)base {
4335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // TODO(hughv): Investigate why percent escapes are being added.  Removing
4345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // them isn't necessary on Android.
4355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // convert HTML escaped characters to UTF8.
4365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  NSString *removePercent =
4375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      [base stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
4385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // remove leading and trailing ".
4395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  NSRange range;
4405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  range.length = [removePercent length] - 2;
4415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  range.location = 1;
4425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  NSString *removeQuotes = [removePercent substringWithRange:range];
4435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // convert \" to ".
4445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  NSString *removeEscapedQuotes =
4455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      [removeQuotes stringByReplacingOccurrencesOfString:@"\\\""
4465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                              withString:@"\""];
4475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // convert \\ to \.
4485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  NSString *removeBackslash =
4495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      [removeEscapedQuotes stringByReplacingOccurrencesOfString:@"\\\\"
4505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                                     withString:@"\\"];
4515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return removeBackslash;
4525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
4535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
4545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org@end
455