blob: 20e708de351d5f31320368fb4e56261f7393ca78 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
2 * libjingle
3 * Copyright 2013, Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +000028#if !defined(__has_feature) || !__has_feature(objc_arc)
29#error "This file requires ARC support."
30#endif
31
henrike@webrtc.org28e20752013-07-10 00:45:36 +000032#import "APPRTCAppClient.h"
33
34#import <dispatch/dispatch.h>
35
tkchin@webrtc.org3e9ad262014-11-27 00:52:38 +000036#import "ARDSignalingParams.h"
37#import "ARDUtilities.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000038#import "GAEChannelClient.h"
fischman@webrtc.org1bc19542013-08-01 18:29:45 +000039#import "RTCICEServer.h"
tkchin@webrtc.org3e9ad262014-11-27 00:52:38 +000040#import "RTCICEServer+JSON.h"
henrike@webrtc.orgd3d6bce2014-03-10 20:41:22 +000041#import "RTCMediaConstraints.h"
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +000042#import "RTCPair.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000043
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +000044@implementation APPRTCAppClient {
45 dispatch_queue_t _backgroundQueue;
tkchin@webrtc.org013bdf82014-06-06 22:29:10 +000046 GAEChannelClient* _gaeChannel;
47 NSURL* _postMessageURL;
48 BOOL _verboseLogging;
49 __weak id<GAEMessageHandler> _messageHandler;
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +000050}
henrike@webrtc.org28e20752013-07-10 00:45:36 +000051
tkchin@webrtc.org013bdf82014-06-06 22:29:10 +000052- (instancetype)initWithDelegate:(id<APPRTCAppClientDelegate>)delegate
53 messageHandler:(id<GAEMessageHandler>)handler {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000054 if (self = [super init]) {
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +000055 _delegate = delegate;
fischman@webrtc.org7fa1fcb2014-03-25 00:11:56 +000056 _messageHandler = handler;
fischman@webrtc.org7c82ada2014-04-30 00:17:47 +000057 _backgroundQueue = dispatch_queue_create("RTCBackgroundQueue",
58 DISPATCH_QUEUE_SERIAL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +000059 // Uncomment to see Request/Response logging.
fischman@webrtc.org1bc19542013-08-01 18:29:45 +000060 // _verboseLogging = YES;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000061 }
62 return self;
63}
64
fischman@webrtc.org7fa1fcb2014-03-25 00:11:56 +000065- (void)connectToRoom:(NSURL*)url {
tkchin@webrtc.org3e9ad262014-11-27 00:52:38 +000066 NSString *urlString =
tkchin@webrtc.org013bdf82014-06-06 22:29:10 +000067 [[url absoluteString] stringByAppendingString:@"&t=json"];
tkchin@webrtc.org3e9ad262014-11-27 00:52:38 +000068 NSURL *requestURL = [NSURL URLWithString:urlString];
69 NSURLRequest *request = [NSURLRequest requestWithURL:requestURL];
70 [NSURLConnection sendAsynchronousRequest:request
71 completionHandler:^(NSURLResponse *response,
72 NSData *data,
73 NSError *error) {
74 NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
tkchin@webrtc.org013bdf82014-06-06 22:29:10 +000075 int statusCode = [httpResponse statusCode];
76 [self logVerbose:[NSString stringWithFormat:
77 @"Response received\nURL\n%@\nStatus [%d]\nHeaders\n%@",
78 [httpResponse URL],
79 statusCode,
80 [httpResponse allHeaderFields]]];
81 NSAssert(statusCode == 200,
82 @"Invalid response of %d received while connecting to: %@",
83 statusCode,
84 urlString);
85 if (statusCode != 200) {
86 return;
87 }
tkchin@webrtc.org3e9ad262014-11-27 00:52:38 +000088 [self handleResponseData:data forRoomRequest:request];
tkchin@webrtc.org013bdf82014-06-06 22:29:10 +000089 }];
henrike@webrtc.org28e20752013-07-10 00:45:36 +000090}
91
fischman@webrtc.org7fa1fcb2014-03-25 00:11:56 +000092- (void)sendData:(NSData*)data {
tkchin@webrtc.org013bdf82014-06-06 22:29:10 +000093 NSParameterAssert([data length] > 0);
tkchin@webrtc.org3e9ad262014-11-27 00:52:38 +000094 NSString *message = [NSString stringWithUTF8String:[data bytes]];
tkchin@webrtc.org013bdf82014-06-06 22:29:10 +000095 [self logVerbose:[NSString stringWithFormat:@"Send message:\n%@", message]];
96 if (!_postMessageURL) {
97 return;
98 }
tkchin@webrtc.org3e9ad262014-11-27 00:52:38 +000099 NSMutableURLRequest *request =
tkchin@webrtc.org013bdf82014-06-06 22:29:10 +0000100 [NSMutableURLRequest requestWithURL:_postMessageURL];
101 request.HTTPMethod = @"POST";
102 [request setHTTPBody:data];
tkchin@webrtc.org3e9ad262014-11-27 00:52:38 +0000103 [NSURLConnection sendAsynchronousRequest:request
104 completionHandler:^(NSURLResponse *response,
105 NSData *data,
106 NSError *error) {
107 NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
tkchin@webrtc.org013bdf82014-06-06 22:29:10 +0000108 int status = [httpResponse statusCode];
tkchin@webrtc.org3e9ad262014-11-27 00:52:38 +0000109 NSString *responseString = [data length] > 0 ?
110 [NSString stringWithUTF8String:[data bytes]] :
tkchin@webrtc.org013bdf82014-06-06 22:29:10 +0000111 nil;
112 NSAssert(status == 200,
113 @"Bad response [%d] to message: %@\n\n%@",
114 status,
115 message,
tkchin@webrtc.org3e9ad262014-11-27 00:52:38 +0000116 responseString);
tkchin@webrtc.org013bdf82014-06-06 22:29:10 +0000117 }];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000118}
119
tkchin@webrtc.org013bdf82014-06-06 22:29:10 +0000120#pragma mark - Private
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000121
tkchin@webrtc.org3e9ad262014-11-27 00:52:38 +0000122- (void)logVerbose:(NSString *)message {
tkchin@webrtc.org013bdf82014-06-06 22:29:10 +0000123 if (_verboseLogging) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000124 NSLog(@"%@", message);
125 }
126}
127
tkchin@webrtc.org3e9ad262014-11-27 00:52:38 +0000128- (void)handleResponseData:(NSData *)responseData
129 forRoomRequest:(NSURLRequest *)request {
130 ARDSignalingParams *params =
131 [ARDSignalingParams paramsFromJSONData:responseData];
132 if (params.errorMessages.count > 0) {
133 NSMutableString *message = [NSMutableString string];
134 for (NSString *errorMessage in params.errorMessages) {
tkchin@webrtc.org013bdf82014-06-06 22:29:10 +0000135 [message appendFormat:@"%@\n", errorMessage];
136 }
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +0000137 [self.delegate appClient:self didErrorWithMessage:message];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000138 return;
139 }
tkchin@webrtc.org3e9ad262014-11-27 00:52:38 +0000140 [self requestTURNServerForICEServers:params.iceServers
141 turnServerUrl:[params.turnRequestURL absoluteString]];
142 NSString *token = params.channelToken;
tkchin@webrtc.org013bdf82014-06-06 22:29:10 +0000143 [self logVerbose:
144 [NSString stringWithFormat:@"About to open GAE with token: %@",
145 token]];
146 _gaeChannel =
147 [[GAEChannelClient alloc] initWithToken:token
148 delegate:_messageHandler];
tkchin@webrtc.org3e9ad262014-11-27 00:52:38 +0000149 _params = params;
150 // Generate URL for posting data.
151 NSDictionary *roomJSON = [NSDictionary dictionaryWithJSONData:responseData];
152 _postMessageURL = [self parsePostMessageURLForRoomJSON:roomJSON
153 request:request];
154 [self logVerbose:[NSString stringWithFormat:@"POST message URL:\n%@",
155 _postMessageURL]];
tkchin@webrtc.org013bdf82014-06-06 22:29:10 +0000156}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000157
tkchin@webrtc.org013bdf82014-06-06 22:29:10 +0000158- (NSURL*)parsePostMessageURLForRoomJSON:(NSDictionary*)roomJSON
159 request:(NSURLRequest*)request {
160 NSString* requestUrl = [[request URL] absoluteString];
161 NSRange queryRange = [requestUrl rangeOfString:@"?"];
162 NSString* baseUrl = [requestUrl substringToIndex:queryRange.location];
163 NSString* roomKey = roomJSON[@"room_key"];
164 NSParameterAssert([roomKey length] > 0);
165 NSString* me = roomJSON[@"me"];
166 NSParameterAssert([me length] > 0);
167 NSString* postMessageUrl =
168 [NSString stringWithFormat:@"%@/message?r=%@&u=%@", baseUrl, roomKey, me];
169 return [NSURL URLWithString:postMessageUrl];
170}
171
tkchin@webrtc.org3e9ad262014-11-27 00:52:38 +0000172- (void)requestTURNServerWithUrl:(NSString *)turnServerUrl
tkchin@webrtc.org013bdf82014-06-06 22:29:10 +0000173 completionHandler:
tkchin@webrtc.org3e9ad262014-11-27 00:52:38 +0000174 (void (^)(RTCICEServer *turnServer))completionHandler {
175 NSURL *turnServerURL = [NSURL URLWithString:turnServerUrl];
176 NSMutableURLRequest *request =
tkchin@webrtc.org013bdf82014-06-06 22:29:10 +0000177 [NSMutableURLRequest requestWithURL:turnServerURL];
178 [request addValue:@"Mozilla/5.0" forHTTPHeaderField:@"user-agent"];
179 [request addValue:@"https://apprtc.appspot.com"
180 forHTTPHeaderField:@"origin"];
tkchin@webrtc.org3e9ad262014-11-27 00:52:38 +0000181 [NSURLConnection sendAsynchronousRequest:request
182 completionHandler:^(NSURLResponse *response,
183 NSData *data,
184 NSError *error) {
tkchin@webrtc.org013bdf82014-06-06 22:29:10 +0000185 if (error) {
186 NSLog(@"Unable to get TURN server.");
187 completionHandler(nil);
188 return;
189 }
tkchin@webrtc.org3e9ad262014-11-27 00:52:38 +0000190 NSDictionary *json = [NSDictionary dictionaryWithJSONData:data];
191 RTCICEServer *turnServer = [RTCICEServer serverFromCEODJSONDictionary:json];
tkchin@webrtc.org013bdf82014-06-06 22:29:10 +0000192 completionHandler(turnServer);
193 }];
194}
195
196- (void)requestTURNServerForICEServers:(NSArray*)iceServers
197 turnServerUrl:(NSString*)turnServerUrl {
198 BOOL isTurnPresent = NO;
199 for (RTCICEServer* iceServer in iceServers) {
200 if ([[iceServer.URI scheme] isEqualToString:@"turn"]) {
201 isTurnPresent = YES;
202 break;
203 }
204 }
205 if (!isTurnPresent) {
206 [self requestTURNServerWithUrl:turnServerUrl
207 completionHandler:^(RTCICEServer* turnServer) {
208 NSArray* servers = iceServers;
209 if (turnServer) {
210 servers = [servers arrayByAddingObject:turnServer];
211 }
212 NSLog(@"ICE servers:\n%@", servers);
213 [self.delegate appClient:self didReceiveICEServers:servers];
214 }];
215 } else {
216 NSLog(@"ICE servers:\n%@", iceServers);
217 dispatch_async(dispatch_get_main_queue(), ^{
218 [self.delegate appClient:self didReceiveICEServers:iceServers];
219 });
220 }
221}
222
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000223@end