OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright 2014 The WebRTC Project Authors. All rights reserved. | |
3 * | |
4 * 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. | |
9 */ | |
10 | |
11 #import "ARDWebSocketChannel.h" | |
12 | |
13 #import "WebRTC/RTCLogging.h" | |
14 #import "SRWebSocket.h" | |
15 | |
16 #import "ARDSignalingMessage.h" | |
17 #import "ARDUtilities.h" | |
18 | |
19 // TODO(tkchin): move these to a configuration object. | |
20 static NSString const *kARDWSSMessageErrorKey = @"error"; | |
21 static 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 | |
39 delegate:(id<ARDSignalingChannelDelegate>)delegate { | |
40 if (self = [super init]) { | |
41 _url = url; | |
42 _restURL = restURL; | |
43 _delegate = delegate; | |
44 _socket = [[SRWebSocket alloc] initWithURL:url]; | |
45 _socket.delegate = self; | |
46 RTCLog(@"Opening WebSocket."); | |
47 [_socket open]; | |
48 } | |
49 return self; | |
50 } | |
51 | |
52 - (void)dealloc { | |
53 [self disconnect]; | |
54 } | |
55 | |
56 - (void)setState:(ARDSignalingChannelState)state { | |
57 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; | |
70 if (_state == kARDSignalingChannelStateOpen) { | |
71 [self registerWithCollider]; | |
72 } | |
73 } | |
74 | |
75 - (void)sendMessage:(ARDSignalingMessage *)message { | |
76 NSParameterAssert(_clientId.length); | |
77 NSParameterAssert(_roomId.length); | |
78 NSData *data = [message JSONData]; | |
79 if (_state == kARDSignalingChannelStateRegistered) { | |
80 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]; | |
93 RTCLog(@"C->WSS: %@", messageString); | |
94 [_socket send:messageString]; | |
95 } else { | |
96 NSString *dataString = | |
97 [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; | |
98 RTCLog(@"C->WSS POST: %@", dataString); | |
99 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 { | |
110 if (_state == kARDSignalingChannelStateClosed || | |
111 _state == kARDSignalingChannelStateError) { | |
112 return; | |
113 } | |
114 [_socket close]; | |
115 RTCLog(@"C->WSS DELETE rid:%@ cid:%@", _roomId, _clientId); | |
116 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 { | |
129 RTCLog(@"WebSocket connection opened."); | |
130 self.state = kARDSignalingChannelStateOpen; | |
131 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]]) { | |
143 RTCLogError(@"Unexpected message: %@", jsonObject); | |
144 return; | |
145 } | |
146 NSDictionary *wssMessage = jsonObject; | |
147 NSString *errorString = wssMessage[kARDWSSMessageErrorKey]; | |
148 if (errorString.length) { | |
149 RTCLogError(@"WSS error: %@", errorString); | |
150 return; | |
151 } | |
152 NSString *payload = wssMessage[kARDWSSMessagePayloadKey]; | |
153 ARDSignalingMessage *signalingMessage = | |
154 [ARDSignalingMessage messageFromJSONString:payload]; | |
155 RTCLog(@"WSS->C: %@", payload); | |
156 [_delegate channel:self didReceiveMessage:signalingMessage]; | |
157 } | |
158 | |
159 - (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error { | |
160 RTCLogError(@"WebSocket error: %@", error); | |
161 self.state = kARDSignalingChannelStateError; | |
162 } | |
163 | |
164 - (void)webSocket:(SRWebSocket *)webSocket | |
165 didCloseWithCode:(NSInteger)code | |
166 reason:(NSString *)reason | |
167 wasClean:(BOOL)wasClean { | |
168 RTCLog(@"WebSocket closed with code: %ld reason:%@ wasClean:%d", | |
169 (long)code, reason, wasClean); | |
170 NSParameterAssert(_state != kARDSignalingChannelStateError); | |
171 self.state = kARDSignalingChannelStateClosed; | |
172 } | |
173 | |
174 #pragma mark - Private | |
175 | |
176 - (void)registerWithCollider { | |
177 if (_state == kARDSignalingChannelStateRegistered) { | |
178 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]; | |
193 RTCLog(@"Registering on WSS for rid:%@ cid:%@", _roomId, _clientId); | |
194 // Registration can fail if server rejects it. For example, if the room is | |
195 // full. | |
196 [_socket send:messageString]; | |
197 self.state = kARDSignalingChannelStateRegistered; | |
198 } | |
199 | |
200 @end | |
201 | |
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; | |
221 NSString *dsc = description.sdp; | |
222 dsc = [dsc stringByReplacingOccurrencesOfString:@"offer" | |
223 withString:@"answer"]; | |
224 RTCSessionDescription *answerDescription = | |
225 [[RTCSessionDescription alloc] initWithType:RTCSdpTypeAnswer sdp:dsc]; | |
226 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 case kARDSignalingMessageTypeCandidateRemoval: | |
237 // Send back to server. | |
238 [self sendMessage:message]; | |
239 break; | |
240 case kARDSignalingMessageTypeBye: | |
241 // Nothing to do. | |
242 return; | |
243 } | |
244 } | |
245 | |
246 - (void)channel:(id<ARDSignalingChannel>)channel | |
247 didChangeState:(ARDSignalingChannelState)state { | |
248 } | |
249 | |
250 @end | |
251 | |
OLD | NEW |