Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1139)

Side by Side Diff: talk/examples/android/src/org/appspot/apprtc/WebSocketChannelClient.java

Issue 1235563006: Move talk/examples/* to webrtc/examples. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: 201508051337 Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * libjingle
3 * Copyright 2014 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
28 package org.appspot.apprtc;
29
30 import org.appspot.apprtc.util.AsyncHttpURLConnection;
31 import org.appspot.apprtc.util.AsyncHttpURLConnection.AsyncHttpEvents;
32 import org.appspot.apprtc.util.LooperExecutor;
33
34 import android.util.Log;
35
36 import de.tavendo.autobahn.WebSocket.WebSocketConnectionObserver;
37 import de.tavendo.autobahn.WebSocketConnection;
38 import de.tavendo.autobahn.WebSocketException;
39
40 import org.json.JSONException;
41 import org.json.JSONObject;
42
43 import java.net.URI;
44 import java.net.URISyntaxException;
45 import java.util.LinkedList;
46
47 /**
48 * WebSocket client implementation.
49 *
50 * <p>All public methods should be called from a looper executor thread
51 * passed in a constructor, otherwise exception will be thrown.
52 * All events are dispatched on the same thread.
53 */
54
55 public class WebSocketChannelClient {
56 private static final String TAG = "WSChannelRTCClient";
57 private static final int CLOSE_TIMEOUT = 1000;
58 private final WebSocketChannelEvents events;
59 private final LooperExecutor executor;
60 private WebSocketConnection ws;
61 private WebSocketObserver wsObserver;
62 private String wsServerUrl;
63 private String postServerUrl;
64 private String roomID;
65 private String clientID;
66 private WebSocketConnectionState state;
67 private final Object closeEventLock = new Object();
68 private boolean closeEvent;
69 // WebSocket send queue. Messages are added to the queue when WebSocket
70 // client is not registered and are consumed in register() call.
71 private final LinkedList<String> wsSendQueue;
72
73 /**
74 * Possible WebSocket connection states.
75 */
76 public enum WebSocketConnectionState {
77 NEW, CONNECTED, REGISTERED, CLOSED, ERROR
78 };
79
80 /**
81 * Callback interface for messages delivered on WebSocket.
82 * All events are dispatched from a looper executor thread.
83 */
84 public interface WebSocketChannelEvents {
85 public void onWebSocketMessage(final String message);
86 public void onWebSocketClose();
87 public void onWebSocketError(final String description);
88 }
89
90 public WebSocketChannelClient(LooperExecutor executor, WebSocketChannelEvents events) {
91 this.executor = executor;
92 this.events = events;
93 roomID = null;
94 clientID = null;
95 wsSendQueue = new LinkedList<String>();
96 state = WebSocketConnectionState.NEW;
97 }
98
99 public WebSocketConnectionState getState() {
100 return state;
101 }
102
103 public void connect(final String wsUrl, final String postUrl) {
104 checkIfCalledOnValidThread();
105 if (state != WebSocketConnectionState.NEW) {
106 Log.e(TAG, "WebSocket is already connected.");
107 return;
108 }
109 wsServerUrl = wsUrl;
110 postServerUrl = postUrl;
111 closeEvent = false;
112
113 Log.d(TAG, "Connecting WebSocket to: " + wsUrl + ". Post URL: " + postUrl);
114 ws = new WebSocketConnection();
115 wsObserver = new WebSocketObserver();
116 try {
117 ws.connect(new URI(wsServerUrl), wsObserver);
118 } catch (URISyntaxException e) {
119 reportError("URI error: " + e.getMessage());
120 } catch (WebSocketException e) {
121 reportError("WebSocket connection error: " + e.getMessage());
122 }
123 }
124
125 public void register(final String roomID, final String clientID) {
126 checkIfCalledOnValidThread();
127 this.roomID = roomID;
128 this.clientID = clientID;
129 if (state != WebSocketConnectionState.CONNECTED) {
130 Log.w(TAG, "WebSocket register() in state " + state);
131 return;
132 }
133 Log.d(TAG, "Registering WebSocket for room " + roomID + ". CLientID: " + cli entID);
134 JSONObject json = new JSONObject();
135 try {
136 json.put("cmd", "register");
137 json.put("roomid", roomID);
138 json.put("clientid", clientID);
139 Log.d(TAG, "C->WSS: " + json.toString());
140 ws.sendTextMessage(json.toString());
141 state = WebSocketConnectionState.REGISTERED;
142 // Send any previously accumulated messages.
143 for (String sendMessage : wsSendQueue) {
144 send(sendMessage);
145 }
146 wsSendQueue.clear();
147 } catch (JSONException e) {
148 reportError("WebSocket register JSON error: " + e.getMessage());
149 }
150 }
151
152 public void send(String message) {
153 checkIfCalledOnValidThread();
154 switch (state) {
155 case NEW:
156 case CONNECTED:
157 // Store outgoing messages and send them after websocket client
158 // is registered.
159 Log.d(TAG, "WS ACC: " + message);
160 wsSendQueue.add(message);
161 return;
162 case ERROR:
163 case CLOSED:
164 Log.e(TAG, "WebSocket send() in error or closed state : " + message);
165 return;
166 case REGISTERED:
167 JSONObject json = new JSONObject();
168 try {
169 json.put("cmd", "send");
170 json.put("msg", message);
171 message = json.toString();
172 Log.d(TAG, "C->WSS: " + message);
173 ws.sendTextMessage(message);
174 } catch (JSONException e) {
175 reportError("WebSocket send JSON error: " + e.getMessage());
176 }
177 break;
178 }
179 return;
180 }
181
182 // This call can be used to send WebSocket messages before WebSocket
183 // connection is opened.
184 public void post(String message) {
185 checkIfCalledOnValidThread();
186 sendWSSMessage("POST", message);
187 }
188
189 public void disconnect(boolean waitForComplete) {
190 checkIfCalledOnValidThread();
191 Log.d(TAG, "Disonnect WebSocket. State: " + state);
192 if (state == WebSocketConnectionState.REGISTERED) {
193 // Send "bye" to WebSocket server.
194 send("{\"type\": \"bye\"}");
195 state = WebSocketConnectionState.CONNECTED;
196 // Send http DELETE to http WebSocket server.
197 sendWSSMessage("DELETE", "");
198 }
199 // Close WebSocket in CONNECTED or ERROR states only.
200 if (state == WebSocketConnectionState.CONNECTED
201 || state == WebSocketConnectionState.ERROR) {
202 ws.disconnect();
203 state = WebSocketConnectionState.CLOSED;
204
205 // Wait for websocket close event to prevent websocket library from
206 // sending any pending messages to deleted looper thread.
207 if (waitForComplete) {
208 synchronized (closeEventLock) {
209 while (!closeEvent) {
210 try {
211 closeEventLock.wait(CLOSE_TIMEOUT);
212 break;
213 } catch (InterruptedException e) {
214 Log.e(TAG, "Wait error: " + e.toString());
215 }
216 }
217 }
218 }
219 }
220 Log.d(TAG, "Disonnecting WebSocket done.");
221 }
222
223 private void reportError(final String errorMessage) {
224 Log.e(TAG, errorMessage);
225 executor.execute(new Runnable() {
226 @Override
227 public void run() {
228 if (state != WebSocketConnectionState.ERROR) {
229 state = WebSocketConnectionState.ERROR;
230 events.onWebSocketError(errorMessage);
231 }
232 }
233 });
234 }
235
236 // Asynchronously send POST/DELETE to WebSocket server.
237 private void sendWSSMessage(final String method, final String message) {
238 String postUrl = postServerUrl + "/" + roomID + "/" + clientID;
239 Log.d(TAG, "WS " + method + " : " + postUrl + " : " + message);
240 AsyncHttpURLConnection httpConnection = new AsyncHttpURLConnection(
241 method, postUrl, message, new AsyncHttpEvents() {
242 @Override
243 public void onHttpError(String errorMessage) {
244 reportError("WS " + method + " error: " + errorMessage);
245 }
246
247 @Override
248 public void onHttpComplete(String response) {
249 }
250 });
251 httpConnection.send();
252 }
253
254 // Helper method for debugging purposes. Ensures that WebSocket method is
255 // called on a looper thread.
256 private void checkIfCalledOnValidThread() {
257 if (!executor.checkOnLooperThread()) {
258 throw new IllegalStateException(
259 "WebSocket method is not called on valid thread");
260 }
261 }
262
263 private class WebSocketObserver implements WebSocketConnectionObserver {
264 @Override
265 public void onOpen() {
266 Log.d(TAG, "WebSocket connection opened to: " + wsServerUrl);
267 executor.execute(new Runnable() {
268 @Override
269 public void run() {
270 state = WebSocketConnectionState.CONNECTED;
271 // Check if we have pending register request.
272 if (roomID != null && clientID != null) {
273 register(roomID, clientID);
274 }
275 }
276 });
277 }
278
279 @Override
280 public void onClose(WebSocketCloseNotification code, String reason) {
281 Log.d(TAG, "WebSocket connection closed. Code: " + code
282 + ". Reason: " + reason + ". State: " + state);
283 synchronized (closeEventLock) {
284 closeEvent = true;
285 closeEventLock.notify();
286 }
287 executor.execute(new Runnable() {
288 @Override
289 public void run() {
290 if (state != WebSocketConnectionState.CLOSED) {
291 state = WebSocketConnectionState.CLOSED;
292 events.onWebSocketClose();
293 }
294 }
295 });
296 }
297
298 @Override
299 public void onTextMessage(String payload) {
300 Log.d(TAG, "WSS->C: " + payload);
301 final String message = payload;
302 executor.execute(new Runnable() {
303 @Override
304 public void run() {
305 if (state == WebSocketConnectionState.CONNECTED
306 || state == WebSocketConnectionState.REGISTERED) {
307 events.onWebSocketMessage(message);
308 }
309 }
310 });
311 }
312
313 @Override
314 public void onRawTextMessage(byte[] payload) {
315 }
316
317 @Override
318 public void onBinaryMessage(byte[] payload) {
319 }
320 }
321
322 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698