| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2016 The WebRTC Project Authors. All rights reserved. | 2 * Copyright 2016 The WebRTC Project Authors. All rights reserved. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ | 9 */ |
| 10 | 10 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 28 /** | 28 /** |
| 29 * Implementation of AppRTCClient that uses direct TCP connection as the signali
ng channel. | 29 * Implementation of AppRTCClient that uses direct TCP connection as the signali
ng channel. |
| 30 * This eliminates the need for an external server. This class does not support
loopback | 30 * This eliminates the need for an external server. This class does not support
loopback |
| 31 * connections. | 31 * connections. |
| 32 */ | 32 */ |
| 33 public class DirectRTCClient implements AppRTCClient, TCPChannelClient.TCPChanne
lEvents { | 33 public class DirectRTCClient implements AppRTCClient, TCPChannelClient.TCPChanne
lEvents { |
| 34 private static final String TAG = "DirectRTCClient"; | 34 private static final String TAG = "DirectRTCClient"; |
| 35 private static final int DEFAULT_PORT = 8888; | 35 private static final int DEFAULT_PORT = 8888; |
| 36 | 36 |
| 37 // Regex pattern used for checking if room id looks like an IP. | 37 // Regex pattern used for checking if room id looks like an IP. |
| 38 static final Pattern IP_PATTERN = Pattern.compile( | 38 static final Pattern IP_PATTERN = Pattern.compile("(" |
| 39 "(" | 39 // IPv4 |
| 40 // IPv4 | 40 + "((\\d+\\.){3}\\d+)|" |
| 41 + "((\\d+\\.){3}\\d+)|" | 41 // IPv6 |
| 42 // IPv6 | 42 + "\\[((([0-9a-fA-F]{1,4}:)*[0-9a-fA-F]{1,4})?::" |
| 43 + "\\[((([0-9a-fA-F]{1,4}:)*[0-9a-fA-F]{1,4})?::" | 43 + "(([0-9a-fA-F]{1,4}:)*[0-9a-fA-F]{1,4})?)\\]|" |
| 44 + "(([0-9a-fA-F]{1,4}:)*[0-9a-fA-F]{1,4})?)\\]|" | 44 + "\\[(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4})\\]|" |
| 45 + "\\[(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4})\\]|" | 45 // IPv6 without [] |
| 46 // IPv6 without [] | 46 + "((([0-9a-fA-F]{1,4}:)*[0-9a-fA-F]{1,4})?::(([0-9a-fA-F]{1,4}:)*[0-9a-fA
-F]{1,4})?)|" |
| 47 + "((([0-9a-fA-F]{1,4}:)*[0-9a-fA-F]{1,4})?::(([0-9a-fA-F]{1,4}:)*[0-9a-
fA-F]{1,4})?)|" | 47 + "(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4})|" |
| 48 + "(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4})|" | 48 // Literals |
| 49 // Literals | 49 + "localhost" |
| 50 + "localhost" | |
| 51 + ")" | 50 + ")" |
| 52 // Optional port number | 51 // Optional port number |
| 53 + "(:(\\d+))?" | 52 + "(:(\\d+))?"); |
| 54 ); | |
| 55 | 53 |
| 56 private final ExecutorService executor; | 54 private final ExecutorService executor; |
| 57 private final SignalingEvents events; | 55 private final SignalingEvents events; |
| 58 private TCPChannelClient tcpClient; | 56 private TCPChannelClient tcpClient; |
| 59 private RoomConnectionParameters connectionParameters; | 57 private RoomConnectionParameters connectionParameters; |
| 60 | 58 |
| 61 private enum ConnectionState { | 59 private enum ConnectionState { NEW, CONNECTED, CLOSED, ERROR } |
| 62 NEW, CONNECTED, CLOSED, ERROR | |
| 63 }; | |
| 64 | 60 |
| 65 // All alterations of the room state should be done from inside the looper thr
ead. | 61 // All alterations of the room state should be done from inside the looper thr
ead. |
| 66 private ConnectionState roomState; | 62 private ConnectionState roomState; |
| 67 | 63 |
| 68 public DirectRTCClient(SignalingEvents events) { | 64 public DirectRTCClient(SignalingEvents events) { |
| 69 this.events = events; | 65 this.events = events; |
| 70 | 66 |
| 71 executor = Executors.newSingleThreadExecutor(); | 67 executor = Executors.newSingleThreadExecutor(); |
| 72 roomState = ConnectionState.NEW; | 68 roomState = ConnectionState.NEW; |
| 73 } | 69 } |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 202 } | 198 } |
| 203 | 199 |
| 204 /** Send removed Ice candidates to the other participant. */ | 200 /** Send removed Ice candidates to the other participant. */ |
| 205 @Override | 201 @Override |
| 206 public void sendLocalIceCandidateRemovals(final IceCandidate[] candidates) { | 202 public void sendLocalIceCandidateRemovals(final IceCandidate[] candidates) { |
| 207 executor.execute(new Runnable() { | 203 executor.execute(new Runnable() { |
| 208 @Override | 204 @Override |
| 209 public void run() { | 205 public void run() { |
| 210 JSONObject json = new JSONObject(); | 206 JSONObject json = new JSONObject(); |
| 211 jsonPut(json, "type", "remove-candidates"); | 207 jsonPut(json, "type", "remove-candidates"); |
| 212 JSONArray jsonArray = new JSONArray(); | 208 JSONArray jsonArray = new JSONArray(); |
| 213 for (final IceCandidate candidate : candidates) { | 209 for (final IceCandidate candidate : candidates) { |
| 214 jsonArray.put(toJsonCandidate(candidate)); | 210 jsonArray.put(toJsonCandidate(candidate)); |
| 215 } | 211 } |
| 216 jsonPut(json, "candidates", jsonArray); | 212 jsonPut(json, "candidates", jsonArray); |
| 217 | 213 |
| 218 if (roomState != ConnectionState.CONNECTED) { | 214 if (roomState != ConnectionState.CONNECTED) { |
| 219 reportError("Sending ICE candidate removals in non connected state."); | 215 reportError("Sending ICE candidate removals in non connected state."); |
| 220 return; | 216 return; |
| 221 } | 217 } |
| 222 sendMessage(json.toString()); | 218 sendMessage(json.toString()); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 237 | 233 |
| 238 SignalingParameters parameters = new SignalingParameters( | 234 SignalingParameters parameters = new SignalingParameters( |
| 239 // Ice servers are not needed for direct connections. | 235 // Ice servers are not needed for direct connections. |
| 240 new LinkedList<PeerConnection.IceServer>(), | 236 new LinkedList<PeerConnection.IceServer>(), |
| 241 isServer, // Server side acts as the initiator on direct connections. | 237 isServer, // Server side acts as the initiator on direct connections. |
| 242 null, // clientId | 238 null, // clientId |
| 243 null, // wssUrl | 239 null, // wssUrl |
| 244 null, // wwsPostUrl | 240 null, // wwsPostUrl |
| 245 null, // offerSdp | 241 null, // offerSdp |
| 246 null // iceCandidates | 242 null // iceCandidates |
| 247 ); | 243 ); |
| 248 events.onConnectedToRoom(parameters); | 244 events.onConnectedToRoom(parameters); |
| 249 } | 245 } |
| 250 } | 246 } |
| 251 | 247 |
| 252 @Override | 248 @Override |
| 253 public void onTCPMessage(String msg) { | 249 public void onTCPMessage(String msg) { |
| 254 try { | 250 try { |
| 255 JSONObject json = new JSONObject(msg); | 251 JSONObject json = new JSONObject(msg); |
| 256 String type = json.optString("type"); | 252 String type = json.optString("type"); |
| 257 if (type.equals("candidate")) { | 253 if (type.equals("candidate")) { |
| 258 events.onRemoteIceCandidate(toJavaCandidate(json)); | 254 events.onRemoteIceCandidate(toJavaCandidate(json)); |
| 259 } else if (type.equals("remove-candidates")) { | 255 } else if (type.equals("remove-candidates")) { |
| 260 JSONArray candidateArray = json.getJSONArray("candidates"); | 256 JSONArray candidateArray = json.getJSONArray("candidates"); |
| 261 IceCandidate[] candidates = new IceCandidate[candidateArray.length()]; | 257 IceCandidate[] candidates = new IceCandidate[candidateArray.length()]; |
| 262 for (int i = 0; i < candidateArray.length(); ++i) { | 258 for (int i = 0; i < candidateArray.length(); ++i) { |
| 263 candidates[i] = toJavaCandidate(candidateArray.getJSONObject(i)); | 259 candidates[i] = toJavaCandidate(candidateArray.getJSONObject(i)); |
| 264 } | 260 } |
| 265 events.onRemoteIceCandidatesRemoved(candidates); | 261 events.onRemoteIceCandidatesRemoved(candidates); |
| 266 } else if (type.equals("answer")) { | 262 } else if (type.equals("answer")) { |
| 267 SessionDescription sdp = new SessionDescription( | 263 SessionDescription sdp = new SessionDescription( |
| 268 SessionDescription.Type.fromCanonicalForm(type), | 264 SessionDescription.Type.fromCanonicalForm(type), json.getString("sdp
")); |
| 269 json.getString("sdp")); | |
| 270 events.onRemoteDescription(sdp); | 265 events.onRemoteDescription(sdp); |
| 271 } else if (type.equals("offer")) { | 266 } else if (type.equals("offer")) { |
| 272 SessionDescription sdp = new SessionDescription( | 267 SessionDescription sdp = new SessionDescription( |
| 273 SessionDescription.Type.fromCanonicalForm(type), | 268 SessionDescription.Type.fromCanonicalForm(type), json.getString("sdp
")); |
| 274 json.getString("sdp")); | |
| 275 | 269 |
| 276 SignalingParameters parameters = new SignalingParameters( | 270 SignalingParameters parameters = new SignalingParameters( |
| 277 // Ice servers are not needed for direct connections. | 271 // Ice servers are not needed for direct connections. |
| 278 new LinkedList<PeerConnection.IceServer>(), | 272 new LinkedList<PeerConnection.IceServer>(), |
| 279 false, // This code will only be run on the client side. So, we are
not the initiator. | 273 false, // This code will only be run on the client side. So, we are
not the initiator. |
| 280 null, // clientId | 274 null, // clientId |
| 281 null, // wssUrl | 275 null, // wssUrl |
| 282 null, // wssPostUrl | 276 null, // wssPostUrl |
| 283 sdp, // offerSdp | 277 sdp, // offerSdp |
| 284 null // iceCandidates | 278 null // iceCandidates |
| 285 ); | 279 ); |
| 286 roomState = ConnectionState.CONNECTED; | 280 roomState = ConnectionState.CONNECTED; |
| 287 events.onConnectedToRoom(parameters); | 281 events.onConnectedToRoom(parameters); |
| 288 } else { | 282 } else { |
| 289 reportError("Unexpected TCP message: " + msg); | 283 reportError("Unexpected TCP message: " + msg); |
| 290 } | 284 } |
| 291 } catch (JSONException e) { | 285 } catch (JSONException e) { |
| 292 reportError("TCP message JSON parsing error: " + e.toString()); | 286 reportError("TCP message JSON parsing error: " + e.toString()); |
| 293 } | 287 } |
| 294 } | 288 } |
| 295 | 289 |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 340 private static JSONObject toJsonCandidate(final IceCandidate candidate) { | 334 private static JSONObject toJsonCandidate(final IceCandidate candidate) { |
| 341 JSONObject json = new JSONObject(); | 335 JSONObject json = new JSONObject(); |
| 342 jsonPut(json, "label", candidate.sdpMLineIndex); | 336 jsonPut(json, "label", candidate.sdpMLineIndex); |
| 343 jsonPut(json, "id", candidate.sdpMid); | 337 jsonPut(json, "id", candidate.sdpMid); |
| 344 jsonPut(json, "candidate", candidate.sdp); | 338 jsonPut(json, "candidate", candidate.sdp); |
| 345 return json; | 339 return json; |
| 346 } | 340 } |
| 347 | 341 |
| 348 // Converts a JSON candidate to a Java object. | 342 // Converts a JSON candidate to a Java object. |
| 349 private static IceCandidate toJavaCandidate(JSONObject json) throws JSONExcept
ion { | 343 private static IceCandidate toJavaCandidate(JSONObject json) throws JSONExcept
ion { |
| 350 return new IceCandidate(json.getString("id"), | 344 return new IceCandidate( |
| 351 json.getInt("label"), | 345 json.getString("id"), json.getInt("label"), json.getString("candidate"))
; |
| 352 json.getString("candidate")); | |
| 353 } | 346 } |
| 354 } | 347 } |
| OLD | NEW |