blob: bbb0bf87f87e0ec93d675e9b3de6d2ec0f65f6b1 [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
Mirko Bonadei19640aa2020-10-19 16:12:43 +020013#import "sdk/objc/base/RTCLogging.h"
14
tkchin@webrtc.org87776a82014-12-09 19:32:35 +000015#import "SRWebSocket.h"
16
haysc913e6452015-10-02 11:44:03 -070017#import "ARDSignalingMessage.h"
tkchinc3f46a92015-07-23 12:50:55 -070018#import "ARDUtilities.h"
19
tkchin@webrtc.org87776a82014-12-09 19:32:35 +000020// TODO(tkchin): move these to a configuration object.
21static NSString const *kARDWSSMessageErrorKey = @"error";
22static NSString const *kARDWSSMessagePayloadKey = @"msg";
23
24@interface ARDWebSocketChannel () <SRWebSocketDelegate>
25@end
26
27@implementation ARDWebSocketChannel {
28 NSURL *_url;
29 NSURL *_restURL;
30 SRWebSocket *_socket;
31}
32
33@synthesize delegate = _delegate;
34@synthesize state = _state;
35@synthesize roomId = _roomId;
36@synthesize clientId = _clientId;
37
38- (instancetype)initWithURL:(NSURL *)url
39 restURL:(NSURL *)restURL
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +000040 delegate:(id<ARDSignalingChannelDelegate>)delegate {
tkchin@webrtc.org87776a82014-12-09 19:32:35 +000041 if (self = [super init]) {
42 _url = url;
43 _restURL = restURL;
44 _delegate = delegate;
45 _socket = [[SRWebSocket alloc] initWithURL:url];
46 _socket.delegate = self;
tkchinc3f46a92015-07-23 12:50:55 -070047 RTCLog(@"Opening WebSocket.");
tkchin@webrtc.org87776a82014-12-09 19:32:35 +000048 [_socket open];
49 }
50 return self;
51}
52
53- (void)dealloc {
54 [self disconnect];
55}
56
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +000057- (void)setState:(ARDSignalingChannelState)state {
tkchin@webrtc.org87776a82014-12-09 19:32:35 +000058 if (_state == state) {
59 return;
60 }
61 _state = state;
62 [_delegate channel:self didChangeState:_state];
63}
64
65- (void)registerForRoomId:(NSString *)roomId
66 clientId:(NSString *)clientId {
67 NSParameterAssert(roomId.length);
68 NSParameterAssert(clientId.length);
69 _roomId = roomId;
70 _clientId = clientId;
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +000071 if (_state == kARDSignalingChannelStateOpen) {
tkchin@webrtc.org87776a82014-12-09 19:32:35 +000072 [self registerWithCollider];
73 }
74}
75
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +000076- (void)sendMessage:(ARDSignalingMessage *)message {
tkchin@webrtc.org87776a82014-12-09 19:32:35 +000077 NSParameterAssert(_clientId.length);
78 NSParameterAssert(_roomId.length);
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +000079 NSData *data = [message JSONData];
80 if (_state == kARDSignalingChannelStateRegistered) {
tkchin@webrtc.org87776a82014-12-09 19:32:35 +000081 NSString *payload =
82 [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
83 NSDictionary *message = @{
84 @"cmd": @"send",
85 @"msg": payload,
86 };
87 NSData *messageJSONObject =
88 [NSJSONSerialization dataWithJSONObject:message
89 options:NSJSONWritingPrettyPrinted
90 error:nil];
91 NSString *messageString =
92 [[NSString alloc] initWithData:messageJSONObject
93 encoding:NSUTF8StringEncoding];
tkchinc3f46a92015-07-23 12:50:55 -070094 RTCLog(@"C->WSS: %@", messageString);
tkchin@webrtc.org87776a82014-12-09 19:32:35 +000095 [_socket send:messageString];
96 } else {
97 NSString *dataString =
98 [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
tkchinc3f46a92015-07-23 12:50:55 -070099 RTCLog(@"C->WSS POST: %@", dataString);
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000100 NSString *urlString =
101 [NSString stringWithFormat:@"%@/%@/%@",
102 [_restURL absoluteString], _roomId, _clientId];
103 NSURL *url = [NSURL URLWithString:urlString];
104 [NSURLConnection sendAsyncPostToURL:url
105 withData:data
106 completionHandler:nil];
107 }
108}
109
110- (void)disconnect {
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000111 if (_state == kARDSignalingChannelStateClosed ||
112 _state == kARDSignalingChannelStateError) {
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000113 return;
114 }
115 [_socket close];
tkchinc3f46a92015-07-23 12:50:55 -0700116 RTCLog(@"C->WSS DELETE rid:%@ cid:%@", _roomId, _clientId);
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000117 NSString *urlString =
118 [NSString stringWithFormat:@"%@/%@/%@",
119 [_restURL absoluteString], _roomId, _clientId];
120 NSURL *url = [NSURL URLWithString:urlString];
121 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
122 request.HTTPMethod = @"DELETE";
123 request.HTTPBody = nil;
124 [NSURLConnection sendAsyncRequest:request completionHandler:nil];
125}
126
127#pragma mark - SRWebSocketDelegate
128
129- (void)webSocketDidOpen:(SRWebSocket *)webSocket {
tkchinc3f46a92015-07-23 12:50:55 -0700130 RTCLog(@"WebSocket connection opened.");
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000131 self.state = kARDSignalingChannelStateOpen;
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000132 if (_roomId.length && _clientId.length) {
133 [self registerWithCollider];
134 }
135}
136
137- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message {
138 NSString *messageString = message;
139 NSData *messageData = [messageString dataUsingEncoding:NSUTF8StringEncoding];
140 id jsonObject = [NSJSONSerialization JSONObjectWithData:messageData
141 options:0
142 error:nil];
143 if (![jsonObject isKindOfClass:[NSDictionary class]]) {
tkchinc3f46a92015-07-23 12:50:55 -0700144 RTCLogError(@"Unexpected message: %@", jsonObject);
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000145 return;
146 }
147 NSDictionary *wssMessage = jsonObject;
148 NSString *errorString = wssMessage[kARDWSSMessageErrorKey];
149 if (errorString.length) {
tkchinc3f46a92015-07-23 12:50:55 -0700150 RTCLogError(@"WSS error: %@", errorString);
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000151 return;
152 }
153 NSString *payload = wssMessage[kARDWSSMessagePayloadKey];
154 ARDSignalingMessage *signalingMessage =
155 [ARDSignalingMessage messageFromJSONString:payload];
tkchinc3f46a92015-07-23 12:50:55 -0700156 RTCLog(@"WSS->C: %@", payload);
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000157 [_delegate channel:self didReceiveMessage:signalingMessage];
158}
159
160- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error {
tkchinc3f46a92015-07-23 12:50:55 -0700161 RTCLogError(@"WebSocket error: %@", error);
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000162 self.state = kARDSignalingChannelStateError;
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000163}
164
165- (void)webSocket:(SRWebSocket *)webSocket
166 didCloseWithCode:(NSInteger)code
167 reason:(NSString *)reason
168 wasClean:(BOOL)wasClean {
tkchinc3f46a92015-07-23 12:50:55 -0700169 RTCLog(@"WebSocket closed with code: %ld reason:%@ wasClean:%d",
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000170 (long)code, reason, wasClean);
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000171 NSParameterAssert(_state != kARDSignalingChannelStateError);
172 self.state = kARDSignalingChannelStateClosed;
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000173}
174
175#pragma mark - Private
176
177- (void)registerWithCollider {
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000178 if (_state == kARDSignalingChannelStateRegistered) {
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000179 return;
180 }
181 NSParameterAssert(_roomId.length);
182 NSParameterAssert(_clientId.length);
183 NSDictionary *registerMessage = @{
184 @"cmd": @"register",
185 @"roomid" : _roomId,
186 @"clientid" : _clientId,
187 };
188 NSData *message =
189 [NSJSONSerialization dataWithJSONObject:registerMessage
190 options:NSJSONWritingPrettyPrinted
191 error:nil];
192 NSString *messageString =
193 [[NSString alloc] initWithData:message encoding:NSUTF8StringEncoding];
tkchinc3f46a92015-07-23 12:50:55 -0700194 RTCLog(@"Registering on WSS for rid:%@ cid:%@", _roomId, _clientId);
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000195 // Registration can fail if server rejects it. For example, if the room is
196 // full.
197 [_socket send:messageString];
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000198 self.state = kARDSignalingChannelStateRegistered;
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000199}
200
201@end
haysc913e6452015-10-02 11:44:03 -0700202
203@interface ARDLoopbackWebSocketChannel () <ARDSignalingChannelDelegate>
204@end
205
206@implementation ARDLoopbackWebSocketChannel
207
208- (instancetype)initWithURL:(NSURL *)url restURL:(NSURL *)restURL {
209 return [super initWithURL:url restURL:restURL delegate:self];
210}
211
212#pragma mark - ARDSignalingChannelDelegate
213
214- (void)channel:(id<ARDSignalingChannel>)channel
215 didReceiveMessage:(ARDSignalingMessage *)message {
216 switch (message.type) {
217 case kARDSignalingMessageTypeOffer: {
218 // Change message to answer, send back to server.
219 ARDSessionDescriptionMessage *sdpMessage =
220 (ARDSessionDescriptionMessage *)message;
Mirko Bonadeia81e9c82020-05-04 16:14:32 +0200221 RTC_OBJC_TYPE(RTCSessionDescription) *description = sdpMessage.sessionDescription;
hjon79858f82016-03-13 22:08:26 -0700222 NSString *dsc = description.sdp;
haysc913e6452015-10-02 11:44:03 -0700223 dsc = [dsc stringByReplacingOccurrencesOfString:@"offer"
224 withString:@"answer"];
Mirko Bonadeia81e9c82020-05-04 16:14:32 +0200225 RTC_OBJC_TYPE(RTCSessionDescription) *answerDescription =
226 [[RTC_OBJC_TYPE(RTCSessionDescription) alloc] initWithType:RTCSdpTypeAnswer sdp:dsc];
haysc913e6452015-10-02 11:44:03 -0700227 ARDSignalingMessage *answer =
228 [[ARDSessionDescriptionMessage alloc]
229 initWithDescription:answerDescription];
230 [self sendMessage:answer];
231 break;
232 }
233 case kARDSignalingMessageTypeAnswer:
234 // Should not receive answer in loopback scenario.
235 break;
236 case kARDSignalingMessageTypeCandidate:
Honghai Zhangda2ba4d2016-05-23 11:53:14 -0700237 case kARDSignalingMessageTypeCandidateRemoval:
haysc913e6452015-10-02 11:44:03 -0700238 // Send back to server.
239 [self sendMessage:message];
240 break;
241 case kARDSignalingMessageTypeBye:
242 // Nothing to do.
243 return;
244 }
245}
246
247- (void)channel:(id<ARDSignalingChannel>)channel
248 didChangeState:(ARDSignalingChannelState)state {
249}
250
251@end
252