blob: 87a690ebeb0a22f69978d7163f5697d1f8e175a0 [file] [log] [blame]
tkchin@webrtc.org87776a82014-12-09 19:32:35 +00001/*
Donald E Curtisa8736442015-08-05 15:48:13 -07002 * Copyright 2014 The WebRTC Project Authors. All rights reserved.
tkchin@webrtc.org87776a82014-12-09 19:32:35 +00003 *
Donald E Curtisa8736442015-08-05 15:48:13 -07004 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
tkchin@webrtc.org87776a82014-12-09 19:32:35 +00009 */
10
11#import "ARDWebSocketChannel.h"
12
tkchin9eeb6242016-04-27 01:54:20 -070013#import "WebRTC/RTCLogging.h"
tkchin@webrtc.org87776a82014-12-09 19:32:35 +000014#import "SRWebSocket.h"
15
haysc913e6452015-10-02 11:44:03 -070016#import "ARDSignalingMessage.h"
tkchinc3f46a92015-07-23 12:50:55 -070017#import "ARDUtilities.h"
18
tkchin@webrtc.org87776a82014-12-09 19:32:35 +000019// TODO(tkchin): move these to a configuration object.
20static NSString const *kARDWSSMessageErrorKey = @"error";
21static NSString const *kARDWSSMessagePayloadKey = @"msg";
22
23@interface ARDWebSocketChannel () <SRWebSocketDelegate>
24@end
25
26@implementation ARDWebSocketChannel {
27 NSURL *_url;
28 NSURL *_restURL;
29 SRWebSocket *_socket;
30}
31
32@synthesize delegate = _delegate;
33@synthesize state = _state;
34@synthesize roomId = _roomId;
35@synthesize clientId = _clientId;
36
37- (instancetype)initWithURL:(NSURL *)url
38 restURL:(NSURL *)restURL
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +000039 delegate:(id<ARDSignalingChannelDelegate>)delegate {
tkchin@webrtc.org87776a82014-12-09 19:32:35 +000040 if (self = [super init]) {
41 _url = url;
42 _restURL = restURL;
43 _delegate = delegate;
44 _socket = [[SRWebSocket alloc] initWithURL:url];
45 _socket.delegate = self;
tkchinc3f46a92015-07-23 12:50:55 -070046 RTCLog(@"Opening WebSocket.");
tkchin@webrtc.org87776a82014-12-09 19:32:35 +000047 [_socket open];
48 }
49 return self;
50}
51
52- (void)dealloc {
53 [self disconnect];
54}
55
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +000056- (void)setState:(ARDSignalingChannelState)state {
tkchin@webrtc.org87776a82014-12-09 19:32:35 +000057 if (_state == state) {
58 return;
59 }
60 _state = state;
61 [_delegate channel:self didChangeState:_state];
62}
63
64- (void)registerForRoomId:(NSString *)roomId
65 clientId:(NSString *)clientId {
66 NSParameterAssert(roomId.length);
67 NSParameterAssert(clientId.length);
68 _roomId = roomId;
69 _clientId = clientId;
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +000070 if (_state == kARDSignalingChannelStateOpen) {
tkchin@webrtc.org87776a82014-12-09 19:32:35 +000071 [self registerWithCollider];
72 }
73}
74
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +000075- (void)sendMessage:(ARDSignalingMessage *)message {
tkchin@webrtc.org87776a82014-12-09 19:32:35 +000076 NSParameterAssert(_clientId.length);
77 NSParameterAssert(_roomId.length);
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +000078 NSData *data = [message JSONData];
79 if (_state == kARDSignalingChannelStateRegistered) {
tkchin@webrtc.org87776a82014-12-09 19:32:35 +000080 NSString *payload =
81 [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
82 NSDictionary *message = @{
83 @"cmd": @"send",
84 @"msg": payload,
85 };
86 NSData *messageJSONObject =
87 [NSJSONSerialization dataWithJSONObject:message
88 options:NSJSONWritingPrettyPrinted
89 error:nil];
90 NSString *messageString =
91 [[NSString alloc] initWithData:messageJSONObject
92 encoding:NSUTF8StringEncoding];
tkchinc3f46a92015-07-23 12:50:55 -070093 RTCLog(@"C->WSS: %@", messageString);
tkchin@webrtc.org87776a82014-12-09 19:32:35 +000094 [_socket send:messageString];
95 } else {
96 NSString *dataString =
97 [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
tkchinc3f46a92015-07-23 12:50:55 -070098 RTCLog(@"C->WSS POST: %@", dataString);
tkchin@webrtc.org87776a82014-12-09 19:32:35 +000099 NSString *urlString =
100 [NSString stringWithFormat:@"%@/%@/%@",
101 [_restURL absoluteString], _roomId, _clientId];
102 NSURL *url = [NSURL URLWithString:urlString];
103 [NSURLConnection sendAsyncPostToURL:url
104 withData:data
105 completionHandler:nil];
106 }
107}
108
109- (void)disconnect {
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000110 if (_state == kARDSignalingChannelStateClosed ||
111 _state == kARDSignalingChannelStateError) {
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000112 return;
113 }
114 [_socket close];
tkchinc3f46a92015-07-23 12:50:55 -0700115 RTCLog(@"C->WSS DELETE rid:%@ cid:%@", _roomId, _clientId);
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000116 NSString *urlString =
117 [NSString stringWithFormat:@"%@/%@/%@",
118 [_restURL absoluteString], _roomId, _clientId];
119 NSURL *url = [NSURL URLWithString:urlString];
120 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
121 request.HTTPMethod = @"DELETE";
122 request.HTTPBody = nil;
123 [NSURLConnection sendAsyncRequest:request completionHandler:nil];
124}
125
126#pragma mark - SRWebSocketDelegate
127
128- (void)webSocketDidOpen:(SRWebSocket *)webSocket {
tkchinc3f46a92015-07-23 12:50:55 -0700129 RTCLog(@"WebSocket connection opened.");
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000130 self.state = kARDSignalingChannelStateOpen;
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000131 if (_roomId.length && _clientId.length) {
132 [self registerWithCollider];
133 }
134}
135
136- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message {
137 NSString *messageString = message;
138 NSData *messageData = [messageString dataUsingEncoding:NSUTF8StringEncoding];
139 id jsonObject = [NSJSONSerialization JSONObjectWithData:messageData
140 options:0
141 error:nil];
142 if (![jsonObject isKindOfClass:[NSDictionary class]]) {
tkchinc3f46a92015-07-23 12:50:55 -0700143 RTCLogError(@"Unexpected message: %@", jsonObject);
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000144 return;
145 }
146 NSDictionary *wssMessage = jsonObject;
147 NSString *errorString = wssMessage[kARDWSSMessageErrorKey];
148 if (errorString.length) {
tkchinc3f46a92015-07-23 12:50:55 -0700149 RTCLogError(@"WSS error: %@", errorString);
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000150 return;
151 }
152 NSString *payload = wssMessage[kARDWSSMessagePayloadKey];
153 ARDSignalingMessage *signalingMessage =
154 [ARDSignalingMessage messageFromJSONString:payload];
tkchinc3f46a92015-07-23 12:50:55 -0700155 RTCLog(@"WSS->C: %@", payload);
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000156 [_delegate channel:self didReceiveMessage:signalingMessage];
157}
158
159- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error {
tkchinc3f46a92015-07-23 12:50:55 -0700160 RTCLogError(@"WebSocket error: %@", error);
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000161 self.state = kARDSignalingChannelStateError;
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000162}
163
164- (void)webSocket:(SRWebSocket *)webSocket
165 didCloseWithCode:(NSInteger)code
166 reason:(NSString *)reason
167 wasClean:(BOOL)wasClean {
tkchinc3f46a92015-07-23 12:50:55 -0700168 RTCLog(@"WebSocket closed with code: %ld reason:%@ wasClean:%d",
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000169 (long)code, reason, wasClean);
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000170 NSParameterAssert(_state != kARDSignalingChannelStateError);
171 self.state = kARDSignalingChannelStateClosed;
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000172}
173
174#pragma mark - Private
175
176- (void)registerWithCollider {
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000177 if (_state == kARDSignalingChannelStateRegistered) {
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000178 return;
179 }
180 NSParameterAssert(_roomId.length);
181 NSParameterAssert(_clientId.length);
182 NSDictionary *registerMessage = @{
183 @"cmd": @"register",
184 @"roomid" : _roomId,
185 @"clientid" : _clientId,
186 };
187 NSData *message =
188 [NSJSONSerialization dataWithJSONObject:registerMessage
189 options:NSJSONWritingPrettyPrinted
190 error:nil];
191 NSString *messageString =
192 [[NSString alloc] initWithData:message encoding:NSUTF8StringEncoding];
tkchinc3f46a92015-07-23 12:50:55 -0700193 RTCLog(@"Registering on WSS for rid:%@ cid:%@", _roomId, _clientId);
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000194 // Registration can fail if server rejects it. For example, if the room is
195 // full.
196 [_socket send:messageString];
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000197 self.state = kARDSignalingChannelStateRegistered;
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000198}
199
200@end
haysc913e6452015-10-02 11:44:03 -0700201
202@interface ARDLoopbackWebSocketChannel () <ARDSignalingChannelDelegate>
203@end
204
205@implementation ARDLoopbackWebSocketChannel
206
207- (instancetype)initWithURL:(NSURL *)url restURL:(NSURL *)restURL {
208 return [super initWithURL:url restURL:restURL delegate:self];
209}
210
211#pragma mark - ARDSignalingChannelDelegate
212
213- (void)channel:(id<ARDSignalingChannel>)channel
214 didReceiveMessage:(ARDSignalingMessage *)message {
215 switch (message.type) {
216 case kARDSignalingMessageTypeOffer: {
217 // Change message to answer, send back to server.
218 ARDSessionDescriptionMessage *sdpMessage =
219 (ARDSessionDescriptionMessage *)message;
220 RTCSessionDescription *description = sdpMessage.sessionDescription;
hjon79858f82016-03-13 22:08:26 -0700221 NSString *dsc = description.sdp;
haysc913e6452015-10-02 11:44:03 -0700222 dsc = [dsc stringByReplacingOccurrencesOfString:@"offer"
223 withString:@"answer"];
224 RTCSessionDescription *answerDescription =
hjon79858f82016-03-13 22:08:26 -0700225 [[RTCSessionDescription alloc] initWithType:RTCSdpTypeAnswer sdp:dsc];
haysc913e6452015-10-02 11:44:03 -0700226 ARDSignalingMessage *answer =
227 [[ARDSessionDescriptionMessage alloc]
228 initWithDescription:answerDescription];
229 [self sendMessage:answer];
230 break;
231 }
232 case kARDSignalingMessageTypeAnswer:
233 // Should not receive answer in loopback scenario.
234 break;
235 case kARDSignalingMessageTypeCandidate:
236 // Send back to server.
237 [self sendMessage:message];
238 break;
239 case kARDSignalingMessageTypeBye:
240 // Nothing to do.
241 return;
242 }
243}
244
245- (void)channel:(id<ARDSignalingChannel>)channel
246 didChangeState:(ARDSignalingChannelState)state {
247}
248
249@end
250