Improve AppRTCDemo connection speed by sending all

http POST requests asynchronously.

R=jiayl@webrtc.org, tkchin@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/33499004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@7820 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
glaznev@webrtc.org 2014-12-05 20:11:06 +00:00
parent bd8cc0b914
commit e2a9261f3e

View File

@ -26,7 +26,6 @@
*/ */
package org.appspot.apprtc; package org.appspot.apprtc;
import android.os.AsyncTask;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.util.Log; import android.util.Log;
@ -36,7 +35,6 @@ import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.URL; import java.net.URL;
import java.util.LinkedList;
import java.util.Scanner; import java.util.Scanner;
import org.appspot.apprtc.RoomParametersFetcher.RoomParametersFetcherEvents; import org.appspot.apprtc.RoomParametersFetcher.RoomParametersFetcherEvents;
@ -64,6 +62,9 @@ public class WebSocketRTCClient implements AppRTCClient,
private enum ConnectionState { private enum ConnectionState {
NEW, CONNECTED, CLOSED, ERROR NEW, CONNECTED, CLOSED, ERROR
}; };
private enum MessageType {
MESSAGE, BYE
};
private final Handler uiHandler; private final Handler uiHandler;
private boolean loopback; private boolean loopback;
private boolean initiator; private boolean initiator;
@ -71,14 +72,12 @@ public class WebSocketRTCClient implements AppRTCClient,
private WebSocketChannelClient wsClient; private WebSocketChannelClient wsClient;
private RoomParametersFetcher fetcher; private RoomParametersFetcher fetcher;
private ConnectionState roomState; private ConnectionState roomState;
private LinkedList<PostMessage> postQueue;
private String postMessageUrl; private String postMessageUrl;
private String byeMessageUrl; private String byeMessageUrl;
public WebSocketRTCClient(SignalingEvents events) { public WebSocketRTCClient(SignalingEvents events) {
this.events = events; this.events = events;
uiHandler = new Handler(Looper.getMainLooper()); uiHandler = new Handler(Looper.getMainLooper());
postQueue = new LinkedList<PostMessage>();
} }
// -------------------------------------------------------------------- // --------------------------------------------------------------------
@ -222,8 +221,9 @@ public class WebSocketRTCClient implements AppRTCClient,
Log.d(TAG, "Disconnect. Room state: " + roomState); Log.d(TAG, "Disconnect. Room state: " + roomState);
if (roomState == ConnectionState.CONNECTED) { if (roomState == ConnectionState.CONNECTED) {
Log.d(TAG, "Closing room."); Log.d(TAG, "Closing room.");
sendGAEMessage(byeMessageUrl, ""); sendPostMessage(MessageType.BYE, byeMessageUrl, "");
} }
roomState = ConnectionState.CLOSED;
if (wsClient != null) { if (wsClient != null) {
wsClient.disconnect(); wsClient.disconnect();
} }
@ -236,10 +236,14 @@ public class WebSocketRTCClient implements AppRTCClient,
// we might want to filter elsewhere. // we might want to filter elsewhere.
@Override @Override
public void sendOfferSdp(final SessionDescription sdp) { public void sendOfferSdp(final SessionDescription sdp) {
if (roomState != ConnectionState.CONNECTED) {
reportError("Sending offer SDP in non connected state.");
return;
}
JSONObject json = new JSONObject(); JSONObject json = new JSONObject();
jsonPut(json, "sdp", sdp.description); jsonPut(json, "sdp", sdp.description);
jsonPut(json, "type", "offer"); jsonPut(json, "type", "offer");
sendGAEMessage(postMessageUrl, json.toString()); sendPostMessage(MessageType.MESSAGE, postMessageUrl, json.toString());
if (loopback) { if (loopback) {
// In loopback mode rename this offer to answer and route it back. // In loopback mode rename this offer to answer and route it back.
SessionDescription sdpAnswer = new SessionDescription( SessionDescription sdpAnswer = new SessionDescription(
@ -279,7 +283,7 @@ public class WebSocketRTCClient implements AppRTCClient,
reportError("Sending ICE candidate in non connected state."); reportError("Sending ICE candidate in non connected state.");
return; return;
} }
sendGAEMessage(postMessageUrl, json.toString()); sendPostMessage(MessageType.MESSAGE, postMessageUrl, json.toString());
if (loopback) { if (loopback) {
events.onRemoteIceCandidate(candidate); events.onRemoteIceCandidate(candidate);
} }
@ -317,88 +321,73 @@ public class WebSocketRTCClient implements AppRTCClient,
} }
private class PostMessage { private class PostMessage {
PostMessage(String postUrl, String message) { PostMessage(MessageType type, String postUrl, String message) {
this.messageType = type;
this.postUrl = postUrl; this.postUrl = postUrl;
this.message = message; this.message = message;
} }
public final MessageType messageType;
public final String postUrl; public final String postUrl;
public final String message; public final String message;
} }
// Queue a message for sending to the room and send it if already connected. // Queue a message for sending to the room and send it if already connected.
private synchronized void sendGAEMessage(String url, String message) { private synchronized void sendPostMessage(
synchronized (postQueue) { MessageType messageType, String url, String message) {
postQueue.add(new PostMessage(url, message)); final PostMessage postMessage = new PostMessage(messageType, url, message);
} Runnable runDrain = new Runnable() {
(new AsyncTask<Void, Void, Void>() { public void run() {
public Void doInBackground(Void... unused) { sendPostMessageAsync(postMessage);
maybeDrainGAEPostQueue();
return null;
} }
}).execute(); };
new Thread(runDrain).start();
} }
// Send all queued messages if connected to the room. // Send all queued POST messages to app engine server.
private void maybeDrainGAEPostQueue() { private void sendPostMessageAsync(PostMessage postMessage) {
if (roomState != ConnectionState.CONNECTED) { if (postMessage.messageType == MessageType.BYE) {
return; Log.d(TAG, "C->GAE: " + postMessage.postUrl);
} else {
Log.d(TAG, "C->GAE: " + postMessage.message);
} }
PostMessage postMessage = null; try {
while (true) { // Get connection.
synchronized (postQueue) { HttpURLConnection connection =
postMessage = postQueue.poll(); (HttpURLConnection) new URL(postMessage.postUrl).openConnection();
byte[] postData = postMessage.message.getBytes("UTF-8");
connection.setUseCaches(false);
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setRequestMethod("POST");
connection.setFixedLengthStreamingMode(postData.length);
connection.setRequestProperty(
"content-type", "text/plain; charset=utf-8");
// Send POST request.
OutputStream outStream = connection.getOutputStream();
outStream.write(postData);
outStream.close();
// Get response.
int responseCode = connection.getResponseCode();
if (responseCode != 200) {
reportError("Non-200 response to POST: " +
connection.getHeaderField(null));
} }
if (postMessage == null) { InputStream responseStream = connection.getInputStream();
break; String response = drainStream(responseStream);
} responseStream.close();
try { if (postMessage.messageType == MessageType.MESSAGE) {
JSONObject roomJson = new JSONObject(response);
// Check if this is 'bye' message and update room connection state. String result = roomJson.getString("result");
if (postMessage.postUrl.contains("bye")) { if (!result.equals("SUCCESS")) {
roomState = ConnectionState.CLOSED; reportError("Room POST error: " + result);
Log.d(TAG, "C->GAE: " + postMessage.postUrl); }
} else {
Log.d(TAG, "C->GAE: " + postMessage.message);
}
// Get connection.
HttpURLConnection connection =
(HttpURLConnection) new URL(postMessage.postUrl).openConnection();
byte[] postData = postMessage.message.getBytes("UTF-8");
connection.setUseCaches(false);
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setRequestMethod("POST");
connection.setFixedLengthStreamingMode(postData.length);
connection.setRequestProperty(
"content-type", "text/plain; charset=utf-8");
// Send POST request.
OutputStream outStream = connection.getOutputStream();
outStream.write(postData);
outStream.close();
// Get response.
int responseCode = connection.getResponseCode();
if (responseCode != 200) {
reportError("Non-200 response to POST: " +
connection.getHeaderField(null));
}
InputStream responseStream = connection.getInputStream();
String response = drainStream(responseStream);
responseStream.close();
if (roomState != ConnectionState.CLOSED) {
JSONObject roomJson = new JSONObject(response);
String result = roomJson.getString("result");
if (!result.equals("SUCCESS")) {
reportError("Room POST error: " + result);
}
}
} catch (IOException e) {
reportError("GAE POST error: " + e.getMessage());
} catch (JSONException e) {
reportError("GAE POST JSON error: " + e.getMessage());
} }
} catch (IOException e) {
reportError("GAE POST error: " + e.getMessage());
} catch (JSONException e) {
reportError("GAE POST JSON error: " + e.getMessage());
} }
} }