Fix AppRTCDemo closing error for KK and JB Android devices.
- Do not allow connection output when sending http delete request to ws server - this causes IOException for KK and JB devices. - Avoid creating dialog box with error message when activity has been already closed / paused - this causes resource leak error message for KK devices. - Plus some code clean up to support async http messages in websocket channel wrapper and use Handler for running peerconnection client funcitons on UI thread. R=jiayl@webrtc.org, tkchin@webrtc.org Review URL: https://webrtc-codereview.appspot.com/31159004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@7836 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
		| @@ -90,6 +90,7 @@ public class AppRTCDemoActivity extends Activity | ||||
|   private ImageButton videoScalingButton; | ||||
|   private String roomName; | ||||
|   private boolean commandLineRun; | ||||
|   private boolean activityRunning; | ||||
|   private int runTimeMs; | ||||
|   private int startBitrate; | ||||
|   private boolean hwCodec; | ||||
| @@ -231,8 +232,8 @@ public class AppRTCDemoActivity extends Activity | ||||
|         } else { | ||||
|           roomNameView.setText(roomName); | ||||
|         } | ||||
|         // For command line execution run connection for <runTimeMs> and exit. | ||||
|         if (commandLineRun && runTimeMs > 0) { | ||||
|           // For command line execution run connection for <runTimeMs> and exit. | ||||
|           videoView.postDelayed(new Runnable() { | ||||
|             public void run() { | ||||
|               disconnect(); | ||||
| @@ -266,6 +267,7 @@ public class AppRTCDemoActivity extends Activity | ||||
|   public void onPause() { | ||||
|     super.onPause(); | ||||
|     videoView.onPause(); | ||||
|     activityRunning = false; | ||||
|     if (pc != null) { | ||||
|       pc.stopVideoSource(); | ||||
|     } | ||||
| @@ -275,6 +277,7 @@ public class AppRTCDemoActivity extends Activity | ||||
|   public void onResume() { | ||||
|     super.onResume(); | ||||
|     videoView.onResume(); | ||||
|     activityRunning = true; | ||||
|     if (pc != null) { | ||||
|       pc.startVideoSource(); | ||||
|     } | ||||
| @@ -284,6 +287,7 @@ public class AppRTCDemoActivity extends Activity | ||||
|   protected void onDestroy() { | ||||
|     disconnect(); | ||||
|     super.onDestroy(); | ||||
|     activityRunning = false; | ||||
|   } | ||||
|  | ||||
|   private void updateVideoView() { | ||||
| @@ -319,7 +323,7 @@ public class AppRTCDemoActivity extends Activity | ||||
|   } | ||||
|  | ||||
|   private void disconnectWithErrorMessage(final String errorMessage) { | ||||
|     if (commandLineRun) { | ||||
|     if (commandLineRun || !activityRunning) { | ||||
|       Log.e(TAG, "Critical error: " + errorMessage); | ||||
|       disconnect(); | ||||
|     } else { | ||||
| @@ -453,7 +457,7 @@ public class AppRTCDemoActivity extends Activity | ||||
|     if (audioManager != null) { | ||||
|       // Store existing audio settings and change audio mode to | ||||
|       // MODE_IN_COMMUNICATION for best possible VoIP performance. | ||||
|       logAndToast("Initializing the audio manager..."); | ||||
|       Log.d(TAG, "Initializing the audio manager..."); | ||||
|       audioManager.init(); | ||||
|     } | ||||
|     signalingParameters = params; | ||||
| @@ -461,7 +465,7 @@ public class AppRTCDemoActivity extends Activity | ||||
|       this, true, true, hwCodec, VideoRendererGui.getEGLContext()), | ||||
|         "Failed to initializeAndroidGlobals"); | ||||
|     logAndToast("Creating peer connection..."); | ||||
|     pc = new PeerConnectionClient( this, localRender, remoteRender, | ||||
|     pc = new PeerConnectionClient(localRender, remoteRender, | ||||
|         signalingParameters, this, startBitrate); | ||||
|     if (pc.isHDVideo()) { | ||||
|       setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); | ||||
|   | ||||
| @@ -27,7 +27,8 @@ | ||||
|  | ||||
| package org.appspot.apprtc; | ||||
|  | ||||
| import android.app.Activity; | ||||
| import android.os.Handler; | ||||
| import android.os.Looper; | ||||
| import android.util.Log; | ||||
|  | ||||
| import org.appspot.apprtc.AppRTCClient.SignalingParameters; | ||||
| @@ -57,7 +58,7 @@ public class PeerConnectionClient { | ||||
|   public static final String VIDEO_TRACK_ID = "ARDAMSv0"; | ||||
|   public static final String AUDIO_TRACK_ID = "ARDAMSa0"; | ||||
|  | ||||
|   private final Activity activity; | ||||
|   private final Handler uiHandler; | ||||
|   private PeerConnectionFactory factory; | ||||
|   private PeerConnection pc; | ||||
|   private VideoSource videoSource; | ||||
| @@ -80,17 +81,16 @@ public class PeerConnectionClient { | ||||
|   private MediaStream mediaStream = null; | ||||
|  | ||||
|   public PeerConnectionClient( | ||||
|       Activity activity, | ||||
|       VideoRenderer.Callbacks localRender, | ||||
|       VideoRenderer.Callbacks remoteRender, | ||||
|       SignalingParameters signalingParameters, | ||||
|       PeerConnectionEvents events, | ||||
|       int startBitrate) { | ||||
|     this.activity = activity; | ||||
|     this.localRender = localRender; | ||||
|     this.remoteRender = remoteRender; | ||||
|     this.events = events; | ||||
|     this.startBitrate = startBitrate; | ||||
|     uiHandler = new Handler(Looper.getMainLooper()); | ||||
|     isInitiator = signalingParameters.initiator; | ||||
|     queuedRemoteCandidates = new LinkedList<IceCandidate>(); | ||||
|  | ||||
| @@ -162,7 +162,7 @@ public class PeerConnectionClient { | ||||
|   } | ||||
|  | ||||
|   public void createOffer() { | ||||
|     activity.runOnUiThread(new Runnable() { | ||||
|     uiHandler.post(new Runnable() { | ||||
|       public void run() { | ||||
|         if (pc != null) { | ||||
|           isInitiator = true; | ||||
| @@ -173,7 +173,7 @@ public class PeerConnectionClient { | ||||
|   } | ||||
|  | ||||
|   public void createAnswer() { | ||||
|     activity.runOnUiThread(new Runnable() { | ||||
|     uiHandler.post(new Runnable() { | ||||
|       public void run() { | ||||
|         if (pc != null) { | ||||
|           isInitiator = false; | ||||
| @@ -184,7 +184,7 @@ public class PeerConnectionClient { | ||||
|   } | ||||
|  | ||||
|   public void addRemoteIceCandidate(final IceCandidate candidate) { | ||||
|     activity.runOnUiThread(new Runnable() { | ||||
|     uiHandler.post(new Runnable() { | ||||
|       public void run() { | ||||
|         if (pc != null) { | ||||
|           if (queuedRemoteCandidates != null) { | ||||
| @@ -198,7 +198,7 @@ public class PeerConnectionClient { | ||||
|   } | ||||
|  | ||||
|   public void setRemoteDescription(final SessionDescription sdp) { | ||||
|     activity.runOnUiThread(new Runnable() { | ||||
|     uiHandler.post(new Runnable() { | ||||
|       public void run() { | ||||
|         if (pc != null) { | ||||
|           String sdpDescription = preferISAC(sdp.description); | ||||
| @@ -231,7 +231,7 @@ public class PeerConnectionClient { | ||||
|   } | ||||
|  | ||||
|   public void close() { | ||||
|     activity.runOnUiThread(new Runnable() { | ||||
|     uiHandler.post(new Runnable() { | ||||
|       public void run() { | ||||
|         Log.d(TAG, "Closing peer connection."); | ||||
|         if (pc != null) { | ||||
| @@ -284,7 +284,7 @@ public class PeerConnectionClient { | ||||
|  | ||||
|   private void reportError(final String errorMessage) { | ||||
|     Log.e(TAG, "Peerconnection error: " + errorMessage); | ||||
|     activity.runOnUiThread(new Runnable() { | ||||
|     uiHandler.post(new Runnable() { | ||||
|       public void run() { | ||||
|         events.onPeerConnectionError(errorMessage); | ||||
|       } | ||||
| @@ -325,8 +325,7 @@ public class PeerConnectionClient { | ||||
|       videoSource.dispose(); | ||||
|     } | ||||
|  | ||||
|     videoSource = factory.createVideoSource( | ||||
|         capturer, videoConstraints); | ||||
|     videoSource = factory.createVideoSource(capturer, videoConstraints); | ||||
|     String trackExtension = frontFacing ? "frontFacing" : "backFacing"; | ||||
|     VideoTrack videoTrack = | ||||
|         factory.createVideoTrack(VIDEO_TRACK_ID + trackExtension, videoSource); | ||||
| @@ -480,7 +479,7 @@ public class PeerConnectionClient { | ||||
|   private class PCObserver implements PeerConnection.Observer { | ||||
|     @Override | ||||
|     public void onIceCandidate(final IceCandidate candidate){ | ||||
|       activity.runOnUiThread(new Runnable() { | ||||
|       uiHandler.post(new Runnable() { | ||||
|         public void run() { | ||||
|           events.onIceCandidate(candidate); | ||||
|         } | ||||
| @@ -498,13 +497,13 @@ public class PeerConnectionClient { | ||||
|         PeerConnection.IceConnectionState newState) { | ||||
|       Log.d(TAG, "IceConnectionState: " + newState); | ||||
|       if (newState == IceConnectionState.CONNECTED) { | ||||
|         activity.runOnUiThread(new Runnable() { | ||||
|         uiHandler.post(new Runnable() { | ||||
|           public void run() { | ||||
|             events.onIceConnected(); | ||||
|           } | ||||
|         }); | ||||
|       } else if (newState == IceConnectionState.DISCONNECTED) { | ||||
|         activity.runOnUiThread(new Runnable() { | ||||
|         uiHandler.post(new Runnable() { | ||||
|           public void run() { | ||||
|             events.onIceDisconnected(); | ||||
|           } | ||||
| @@ -522,7 +521,7 @@ public class PeerConnectionClient { | ||||
|  | ||||
|     @Override | ||||
|     public void onAddStream(final MediaStream stream){ | ||||
|       activity.runOnUiThread(new Runnable() { | ||||
|       uiHandler.post(new Runnable() { | ||||
|         public void run() { | ||||
|           abortUnless(stream.audioTracks.size() <= 1 && | ||||
|               stream.videoTracks.size() <= 1, | ||||
| @@ -537,7 +536,7 @@ public class PeerConnectionClient { | ||||
|  | ||||
|     @Override | ||||
|     public void onRemoveStream(final MediaStream stream){ | ||||
|       activity.runOnUiThread(new Runnable() { | ||||
|       uiHandler.post(new Runnable() { | ||||
|         public void run() { | ||||
|           stream.videoTracks.get(0).dispose(); | ||||
|         } | ||||
| @@ -566,7 +565,7 @@ public class PeerConnectionClient { | ||||
|       final SessionDescription sdp = new SessionDescription( | ||||
|           origSdp.type, preferISAC(origSdp.description)); | ||||
|       localSdp = sdp; | ||||
|       activity.runOnUiThread(new Runnable() { | ||||
|       uiHandler.post(new Runnable() { | ||||
|         public void run() { | ||||
|           if (pc != null) { | ||||
|             Log.d(TAG, "Set local SDP from " + sdp.type); | ||||
| @@ -578,7 +577,7 @@ public class PeerConnectionClient { | ||||
|  | ||||
|     @Override | ||||
|     public void onSetSuccess() { | ||||
|       activity.runOnUiThread(new Runnable() { | ||||
|       uiHandler.post(new Runnable() { | ||||
|         public void run() { | ||||
|           if (pc == null) { | ||||
|             return; | ||||
|   | ||||
| @@ -36,12 +36,10 @@ import de.tavendo.autobahn.WebSocketException; | ||||
| import de.tavendo.autobahn.WebSocket.WebSocketConnectionObserver; | ||||
|  | ||||
| import java.io.IOException; | ||||
| import java.io.UnsupportedEncodingException; | ||||
| import java.net.HttpURLConnection; | ||||
| import java.net.URI; | ||||
| import java.net.URISyntaxException; | ||||
| import java.net.URL; | ||||
| import java.net.URLEncoder; | ||||
| import java.util.LinkedList; | ||||
|  | ||||
| import org.json.JSONException; | ||||
| @@ -64,10 +62,6 @@ public class WebSocketChannelClient { | ||||
|   private String roomID; | ||||
|   private String clientID; | ||||
|   private WebSocketConnectionState state; | ||||
|   // Http post/delete message queue. Messages are added from UI thread in | ||||
|   // post() and disconnect() calls. Messages are consumed by AsyncTask's | ||||
|   // background thread. | ||||
|   private LinkedList<WsHttpMessage> wsHttpQueue; | ||||
|   // WebSocket send queue. Messages are added to the queue when WebSocket | ||||
|   // client is not registered and are consumed in register() call. | ||||
|   private LinkedList<String> wsSendQueue; | ||||
| @@ -92,7 +86,6 @@ public class WebSocketChannelClient { | ||||
|     uiHandler = new Handler(Looper.getMainLooper()); | ||||
|     roomID = null; | ||||
|     clientID = null; | ||||
|     wsHttpQueue = new LinkedList<WsHttpMessage>(); | ||||
|     wsSendQueue = new LinkedList<String>(); | ||||
|     state = WebSocketConnectionState.NEW; | ||||
|   } | ||||
| @@ -192,10 +185,7 @@ public class WebSocketChannelClient { | ||||
|   // send through websocket before SDP answer sent through http post will be | ||||
|   // resolved. | ||||
|   public void post(String message) { | ||||
|     synchronized (wsHttpQueue) { | ||||
|       wsHttpQueue.add(new WsHttpMessage("POST", message)); | ||||
|     } | ||||
|     requestHttpQueueDrainInBackground(); | ||||
|     sendWSSMessage("POST", message); | ||||
|   } | ||||
|  | ||||
|   public void disconnect() { | ||||
| @@ -210,11 +200,7 @@ public class WebSocketChannelClient { | ||||
|       ws.disconnect(); | ||||
|  | ||||
|       // Send DELETE to http WebSocket server. | ||||
|       synchronized (wsHttpQueue) { | ||||
|         wsHttpQueue.clear(); | ||||
|         wsHttpQueue.add(new WsHttpMessage("DELETE", "")); | ||||
|       } | ||||
|       requestHttpQueueDrainInBackground(); | ||||
|       sendWSSMessage("DELETE", ""); | ||||
|  | ||||
|       state = WebSocketConnectionState.CLOSED; | ||||
|     } | ||||
| @@ -241,67 +227,43 @@ public class WebSocketChannelClient { | ||||
|     public final String message; | ||||
|   } | ||||
|  | ||||
|   // TODO(glaznev): This is not good implementation due to discrepancy | ||||
|   // between JS encodeURIComponent() and Java URLEncoder.encode(). | ||||
|   // Remove this once WebSocket server will switch to a different encoding. | ||||
|   private String encodeURIComponent(String s) { | ||||
|     String result = null; | ||||
|     try { | ||||
|       result = URLEncoder.encode(s, "UTF-8") | ||||
|          .replaceAll("\\+", "%20") | ||||
|          .replaceAll("\\%21", "!") | ||||
|          .replaceAll("\\%27", "'") | ||||
|          .replaceAll("\\%28", "(") | ||||
|          .replaceAll("\\%29", ")") | ||||
|          .replaceAll("\\%7E", "~"); | ||||
|     } catch (UnsupportedEncodingException e) { | ||||
|       result = s; | ||||
|   // Asynchronously send POST/DELETE to WebSocket server. | ||||
|   private void sendWSSMessage(String method, String message) { | ||||
|     final WsHttpMessage wsHttpMessage = new WsHttpMessage(method, message); | ||||
|     Runnable runAsync = new Runnable() { | ||||
|       public void run() { | ||||
|         sendWSSMessageAsync(wsHttpMessage); | ||||
|       } | ||||
|     }; | ||||
|     new Thread(runAsync).start(); | ||||
|   } | ||||
|  | ||||
|   private void sendWSSMessageAsync(WsHttpMessage wsHttpMessage) { | ||||
|     if (roomID == null || clientID == null) { | ||||
|       return; | ||||
|     } | ||||
|     return result; | ||||
|   } | ||||
|  | ||||
|   // Request an attempt to drain the send queue, on a background thread. | ||||
|   private void requestHttpQueueDrainInBackground() { | ||||
|     (new AsyncTask<Void, Void, Void>() { | ||||
|       public Void doInBackground(Void... unused) { | ||||
|         maybeDrainWsHttpQueue(); | ||||
|         return null; | ||||
|     try { | ||||
|       // Send POST or DELETE request. | ||||
|       String postUrl = postServerUrl + "/" + roomID + "/" + clientID; | ||||
|       Log.d(TAG, "WS " + wsHttpMessage.method + " : " + postUrl + " : " + | ||||
|           wsHttpMessage.message); | ||||
|       HttpURLConnection connection = | ||||
|           (HttpURLConnection) new URL(postUrl).openConnection(); | ||||
|       connection.setRequestProperty( | ||||
|           "content-type", "text/plain; charset=utf-8"); | ||||
|       connection.setRequestMethod(wsHttpMessage.method); | ||||
|       if (wsHttpMessage.method.equals("POST")) { | ||||
|         connection.setDoOutput(true); | ||||
|         String message = wsHttpMessage.message; | ||||
|         connection.getOutputStream().write(message.getBytes("UTF-8")); | ||||
|       } | ||||
|     }).execute(); | ||||
|   } | ||||
|  | ||||
|   // Send all queued websocket messages. | ||||
|   private void maybeDrainWsHttpQueue() { | ||||
|     synchronized (wsHttpQueue) { | ||||
|       if (roomID == null || clientID == null) { | ||||
|         return; | ||||
|       int responseCode = connection.getResponseCode(); | ||||
|       if (responseCode != 200) { | ||||
|         reportError("Non-200 response to " + wsHttpMessage.method + " : " + | ||||
|             connection.getHeaderField(null)); | ||||
|       } | ||||
|       try { | ||||
|         for (WsHttpMessage wsHttpMessage : wsHttpQueue) { | ||||
|           // Send POST request. | ||||
|           String postUrl = postServerUrl + "/" + roomID + "/" + clientID; | ||||
|           Log.d(TAG, "WS " + wsHttpMessage.method + " : " + postUrl + " : " + | ||||
|               wsHttpMessage.message); | ||||
|           HttpURLConnection connection = | ||||
|               (HttpURLConnection) new URL(postUrl).openConnection(); | ||||
|           connection.setDoOutput(true); | ||||
|           connection.setRequestProperty( | ||||
|               "Content-type", "application/x-www-form-urlencoded"); | ||||
|           connection.setRequestMethod(wsHttpMessage.method); | ||||
|           if (wsHttpMessage.message.length() > 0) { | ||||
|             String message = "msg=" + encodeURIComponent(wsHttpMessage.message); | ||||
|             connection.getOutputStream().write(message.getBytes("UTF-8")); | ||||
|           } | ||||
|           String replyHeader = connection.getHeaderField(null); | ||||
|           if (!replyHeader.startsWith("HTTP/1.1 200 ")) { | ||||
|             reportError("Non-200 response to " + wsHttpMessage.method + " : " + | ||||
|                 connection.getHeaderField(null)); | ||||
|           } | ||||
|         } | ||||
|       } catch (IOException e) { | ||||
|         reportError("WS POST error: " + e.getMessage()); | ||||
|       } | ||||
|       wsHttpQueue.clear(); | ||||
|     } catch (IOException e) { | ||||
|       reportError("WS POST error: " + e.getMessage()); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 glaznev@webrtc.org
					glaznev@webrtc.org