OLD | NEW |
| (Empty) |
1 /* | |
2 * libjingle | |
3 * Copyright 2015 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.AppRTCClient.RoomConnectionParameters; | |
31 import org.appspot.apprtc.AppRTCClient.SignalingParameters; | |
32 import org.appspot.apprtc.PeerConnectionClient.PeerConnectionParameters; | |
33 import org.appspot.apprtc.util.LooperExecutor; | |
34 | |
35 import android.app.Activity; | |
36 import android.app.AlertDialog; | |
37 import android.app.FragmentTransaction; | |
38 import android.content.DialogInterface; | |
39 import android.content.Intent; | |
40 import android.content.pm.PackageManager; | |
41 import android.net.Uri; | |
42 import android.opengl.GLSurfaceView; | |
43 import android.os.Bundle; | |
44 import android.util.Log; | |
45 import android.view.View; | |
46 import android.view.Window; | |
47 import android.view.WindowManager.LayoutParams; | |
48 import android.widget.Toast; | |
49 | |
50 import org.webrtc.IceCandidate; | |
51 import org.webrtc.SessionDescription; | |
52 import org.webrtc.StatsReport; | |
53 import org.webrtc.VideoRenderer; | |
54 import org.webrtc.VideoRendererGui; | |
55 import org.webrtc.VideoRendererGui.ScalingType; | |
56 | |
57 /** | |
58 * Activity for peer connection call setup, call waiting | |
59 * and call view. | |
60 */ | |
61 public class CallActivity extends Activity | |
62 implements AppRTCClient.SignalingEvents, | |
63 PeerConnectionClient.PeerConnectionEvents, | |
64 CallFragment.OnCallEvents { | |
65 | |
66 public static final String EXTRA_ROOMID = | |
67 "org.appspot.apprtc.ROOMID"; | |
68 public static final String EXTRA_LOOPBACK = | |
69 "org.appspot.apprtc.LOOPBACK"; | |
70 public static final String EXTRA_VIDEO_CALL = | |
71 "org.appspot.apprtc.VIDEO_CALL"; | |
72 public static final String EXTRA_VIDEO_WIDTH = | |
73 "org.appspot.apprtc.VIDEO_WIDTH"; | |
74 public static final String EXTRA_VIDEO_HEIGHT = | |
75 "org.appspot.apprtc.VIDEO_HEIGHT"; | |
76 public static final String EXTRA_VIDEO_FPS = | |
77 "org.appspot.apprtc.VIDEO_FPS"; | |
78 public static final String EXTRA_VIDEO_BITRATE = | |
79 "org.appspot.apprtc.VIDEO_BITRATE"; | |
80 public static final String EXTRA_VIDEOCODEC = | |
81 "org.appspot.apprtc.VIDEOCODEC"; | |
82 public static final String EXTRA_HWCODEC_ENABLED = | |
83 "org.appspot.apprtc.HWCODEC"; | |
84 public static final String EXTRA_AUDIO_BITRATE = | |
85 "org.appspot.apprtc.AUDIO_BITRATE"; | |
86 public static final String EXTRA_AUDIOCODEC = | |
87 "org.appspot.apprtc.AUDIOCODEC"; | |
88 public static final String EXTRA_NOAUDIOPROCESSING_ENABLED = | |
89 "org.appspot.apprtc.NOAUDIOPROCESSING"; | |
90 public static final String EXTRA_CPUOVERUSE_DETECTION = | |
91 "org.appspot.apprtc.CPUOVERUSE_DETECTION"; | |
92 public static final String EXTRA_DISPLAY_HUD = | |
93 "org.appspot.apprtc.DISPLAY_HUD"; | |
94 public static final String EXTRA_CMDLINE = | |
95 "org.appspot.apprtc.CMDLINE"; | |
96 public static final String EXTRA_RUNTIME = | |
97 "org.appspot.apprtc.RUNTIME"; | |
98 private static final String TAG = "CallRTCClient"; | |
99 | |
100 // List of mandatory application permissions. | |
101 private static final String[] MANDATORY_PERMISSIONS = { | |
102 "android.permission.MODIFY_AUDIO_SETTINGS", | |
103 "android.permission.RECORD_AUDIO", | |
104 "android.permission.INTERNET" | |
105 }; | |
106 | |
107 // Peer connection statistics callback period in ms. | |
108 private static final int STAT_CALLBACK_PERIOD = 1000; | |
109 // Local preview screen position before call is connected. | |
110 private static final int LOCAL_X_CONNECTING = 0; | |
111 private static final int LOCAL_Y_CONNECTING = 0; | |
112 private static final int LOCAL_WIDTH_CONNECTING = 100; | |
113 private static final int LOCAL_HEIGHT_CONNECTING = 100; | |
114 // Local preview screen position after call is connected. | |
115 private static final int LOCAL_X_CONNECTED = 72; | |
116 private static final int LOCAL_Y_CONNECTED = 72; | |
117 private static final int LOCAL_WIDTH_CONNECTED = 25; | |
118 private static final int LOCAL_HEIGHT_CONNECTED = 25; | |
119 // Remote video screen position | |
120 private static final int REMOTE_X = 0; | |
121 private static final int REMOTE_Y = 0; | |
122 private static final int REMOTE_WIDTH = 100; | |
123 private static final int REMOTE_HEIGHT = 100; | |
124 | |
125 private PeerConnectionClient peerConnectionClient = null; | |
126 private AppRTCClient appRtcClient; | |
127 private SignalingParameters signalingParameters; | |
128 private AppRTCAudioManager audioManager = null; | |
129 private VideoRenderer.Callbacks localRender; | |
130 private VideoRenderer.Callbacks remoteRender; | |
131 private ScalingType scalingType; | |
132 private Toast logToast; | |
133 private boolean commandLineRun; | |
134 private int runTimeMs; | |
135 private boolean activityRunning; | |
136 private RoomConnectionParameters roomConnectionParameters; | |
137 private PeerConnectionParameters peerConnectionParameters; | |
138 private boolean iceConnected; | |
139 private boolean isError; | |
140 private boolean callControlFragmentVisible = true; | |
141 private long callStartedTimeMs = 0; | |
142 | |
143 // Controls | |
144 private GLSurfaceView videoView; | |
145 CallFragment callFragment; | |
146 HudFragment hudFragment; | |
147 | |
148 @Override | |
149 public void onCreate(Bundle savedInstanceState) { | |
150 super.onCreate(savedInstanceState); | |
151 Thread.setDefaultUncaughtExceptionHandler( | |
152 new UnhandledExceptionHandler(this)); | |
153 | |
154 // Set window styles for fullscreen-window size. Needs to be done before | |
155 // adding content. | |
156 requestWindowFeature(Window.FEATURE_NO_TITLE); | |
157 getWindow().addFlags( | |
158 LayoutParams.FLAG_FULLSCREEN | |
159 | LayoutParams.FLAG_KEEP_SCREEN_ON | |
160 | LayoutParams.FLAG_DISMISS_KEYGUARD | |
161 | LayoutParams.FLAG_SHOW_WHEN_LOCKED | |
162 | LayoutParams.FLAG_TURN_SCREEN_ON); | |
163 getWindow().getDecorView().setSystemUiVisibility( | |
164 View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | |
165 | View.SYSTEM_UI_FLAG_FULLSCREEN | |
166 | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); | |
167 setContentView(R.layout.activity_call); | |
168 | |
169 iceConnected = false; | |
170 signalingParameters = null; | |
171 scalingType = ScalingType.SCALE_ASPECT_FILL; | |
172 | |
173 // Create UI controls. | |
174 videoView = (GLSurfaceView) findViewById(R.id.glview_call); | |
175 callFragment = new CallFragment(); | |
176 hudFragment = new HudFragment(); | |
177 | |
178 // Create video renderers. | |
179 VideoRendererGui.setView(videoView, new Runnable() { | |
180 @Override | |
181 public void run() { | |
182 createPeerConnectionFactory(); | |
183 } | |
184 }); | |
185 remoteRender = VideoRendererGui.create( | |
186 REMOTE_X, REMOTE_Y, | |
187 REMOTE_WIDTH, REMOTE_HEIGHT, scalingType, false); | |
188 localRender = VideoRendererGui.create( | |
189 LOCAL_X_CONNECTING, LOCAL_Y_CONNECTING, | |
190 LOCAL_WIDTH_CONNECTING, LOCAL_HEIGHT_CONNECTING, scalingType, true); | |
191 | |
192 // Show/hide call control fragment on view click. | |
193 videoView.setOnClickListener(new View.OnClickListener() { | |
194 @Override | |
195 public void onClick(View view) { | |
196 toggleCallControlFragmentVisibility(); | |
197 } | |
198 }); | |
199 | |
200 // Check for mandatory permissions. | |
201 for (String permission : MANDATORY_PERMISSIONS) { | |
202 if (checkCallingOrSelfPermission(permission) != PackageManager.PERMISSION_
GRANTED) { | |
203 logAndToast("Permission " + permission + " is not granted"); | |
204 setResult(RESULT_CANCELED); | |
205 finish(); | |
206 return; | |
207 } | |
208 } | |
209 | |
210 // Get Intent parameters. | |
211 final Intent intent = getIntent(); | |
212 Uri roomUri = intent.getData(); | |
213 if (roomUri == null) { | |
214 logAndToast(getString(R.string.missing_url)); | |
215 Log.e(TAG, "Didn't get any URL in intent!"); | |
216 setResult(RESULT_CANCELED); | |
217 finish(); | |
218 return; | |
219 } | |
220 String roomId = intent.getStringExtra(EXTRA_ROOMID); | |
221 if (roomId == null || roomId.length() == 0) { | |
222 logAndToast(getString(R.string.missing_url)); | |
223 Log.e(TAG, "Incorrect room ID in intent!"); | |
224 setResult(RESULT_CANCELED); | |
225 finish(); | |
226 return; | |
227 } | |
228 boolean loopback = intent.getBooleanExtra(EXTRA_LOOPBACK, false); | |
229 peerConnectionParameters = new PeerConnectionParameters( | |
230 intent.getBooleanExtra(EXTRA_VIDEO_CALL, true), | |
231 loopback, | |
232 intent.getIntExtra(EXTRA_VIDEO_WIDTH, 0), | |
233 intent.getIntExtra(EXTRA_VIDEO_HEIGHT, 0), | |
234 intent.getIntExtra(EXTRA_VIDEO_FPS, 0), | |
235 intent.getIntExtra(EXTRA_VIDEO_BITRATE, 0), | |
236 intent.getStringExtra(EXTRA_VIDEOCODEC), | |
237 intent.getBooleanExtra(EXTRA_HWCODEC_ENABLED, true), | |
238 intent.getIntExtra(EXTRA_AUDIO_BITRATE, 0), | |
239 intent.getStringExtra(EXTRA_AUDIOCODEC), | |
240 intent.getBooleanExtra(EXTRA_NOAUDIOPROCESSING_ENABLED, false), | |
241 intent.getBooleanExtra(EXTRA_CPUOVERUSE_DETECTION, true)); | |
242 commandLineRun = intent.getBooleanExtra(EXTRA_CMDLINE, false); | |
243 runTimeMs = intent.getIntExtra(EXTRA_RUNTIME, 0); | |
244 | |
245 // Create connection client and connection parameters. | |
246 appRtcClient = new WebSocketRTCClient(this, new LooperExecutor()); | |
247 roomConnectionParameters = new RoomConnectionParameters( | |
248 roomUri.toString(), roomId, loopback); | |
249 | |
250 // Send intent arguments to fragments. | |
251 callFragment.setArguments(intent.getExtras()); | |
252 hudFragment.setArguments(intent.getExtras()); | |
253 // Activate call and HUD fragments and start the call. | |
254 FragmentTransaction ft = getFragmentManager().beginTransaction(); | |
255 ft.add(R.id.call_fragment_container, callFragment); | |
256 ft.add(R.id.hud_fragment_container, hudFragment); | |
257 ft.commit(); | |
258 startCall(); | |
259 | |
260 // For command line execution run connection for <runTimeMs> and exit. | |
261 if (commandLineRun && runTimeMs > 0) { | |
262 videoView.postDelayed(new Runnable() { | |
263 public void run() { | |
264 disconnect(); | |
265 } | |
266 }, runTimeMs); | |
267 } | |
268 } | |
269 | |
270 // Activity interfaces | |
271 @Override | |
272 public void onPause() { | |
273 super.onPause(); | |
274 videoView.onPause(); | |
275 activityRunning = false; | |
276 if (peerConnectionClient != null) { | |
277 peerConnectionClient.stopVideoSource(); | |
278 } | |
279 } | |
280 | |
281 @Override | |
282 public void onResume() { | |
283 super.onResume(); | |
284 videoView.onResume(); | |
285 activityRunning = true; | |
286 if (peerConnectionClient != null) { | |
287 peerConnectionClient.startVideoSource(); | |
288 } | |
289 } | |
290 | |
291 @Override | |
292 protected void onDestroy() { | |
293 disconnect(); | |
294 super.onDestroy(); | |
295 if (logToast != null) { | |
296 logToast.cancel(); | |
297 } | |
298 activityRunning = false; | |
299 } | |
300 | |
301 // CallFragment.OnCallEvents interface implementation. | |
302 @Override | |
303 public void onCallHangUp() { | |
304 disconnect(); | |
305 } | |
306 | |
307 @Override | |
308 public void onCameraSwitch() { | |
309 if (peerConnectionClient != null) { | |
310 peerConnectionClient.switchCamera(); | |
311 } | |
312 } | |
313 | |
314 @Override | |
315 public void onVideoScalingSwitch(ScalingType scalingType) { | |
316 this.scalingType = scalingType; | |
317 updateVideoView(); | |
318 } | |
319 | |
320 // Helper functions. | |
321 private void toggleCallControlFragmentVisibility() { | |
322 if (!iceConnected || !callFragment.isAdded()) { | |
323 return; | |
324 } | |
325 // Show/hide call control fragment | |
326 callControlFragmentVisible = !callControlFragmentVisible; | |
327 FragmentTransaction ft = getFragmentManager().beginTransaction(); | |
328 if (callControlFragmentVisible) { | |
329 ft.show(callFragment); | |
330 ft.show(hudFragment); | |
331 } else { | |
332 ft.hide(callFragment); | |
333 ft.hide(hudFragment); | |
334 } | |
335 ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE); | |
336 ft.commit(); | |
337 } | |
338 | |
339 private void updateVideoView() { | |
340 VideoRendererGui.update(remoteRender, | |
341 REMOTE_X, REMOTE_Y, | |
342 REMOTE_WIDTH, REMOTE_HEIGHT, scalingType, false); | |
343 if (iceConnected) { | |
344 VideoRendererGui.update(localRender, | |
345 LOCAL_X_CONNECTED, LOCAL_Y_CONNECTED, | |
346 LOCAL_WIDTH_CONNECTED, LOCAL_HEIGHT_CONNECTED, | |
347 ScalingType.SCALE_ASPECT_FIT, true); | |
348 } else { | |
349 VideoRendererGui.update(localRender, | |
350 LOCAL_X_CONNECTING, LOCAL_Y_CONNECTING, | |
351 LOCAL_WIDTH_CONNECTING, LOCAL_HEIGHT_CONNECTING, scalingType, true); | |
352 } | |
353 } | |
354 | |
355 private void startCall() { | |
356 if (appRtcClient == null) { | |
357 Log.e(TAG, "AppRTC client is not allocated for a call."); | |
358 return; | |
359 } | |
360 callStartedTimeMs = System.currentTimeMillis(); | |
361 | |
362 // Start room connection. | |
363 logAndToast(getString(R.string.connecting_to, | |
364 roomConnectionParameters.roomUrl)); | |
365 appRtcClient.connectToRoom(roomConnectionParameters); | |
366 | |
367 // Create and audio manager that will take care of audio routing, | |
368 // audio modes, audio device enumeration etc. | |
369 audioManager = AppRTCAudioManager.create(this, new Runnable() { | |
370 // This method will be called each time the audio state (number and | |
371 // type of devices) has been changed. | |
372 @Override | |
373 public void run() { | |
374 onAudioManagerChangedState(); | |
375 } | |
376 } | |
377 ); | |
378 // Store existing audio settings and change audio mode to | |
379 // MODE_IN_COMMUNICATION for best possible VoIP performance. | |
380 Log.d(TAG, "Initializing the audio manager..."); | |
381 audioManager.init(); | |
382 } | |
383 | |
384 // Should be called from UI thread | |
385 private void callConnected() { | |
386 final long delta = System.currentTimeMillis() - callStartedTimeMs; | |
387 Log.i(TAG, "Call connected: delay=" + delta + "ms"); | |
388 | |
389 // Update video view. | |
390 updateVideoView(); | |
391 // Enable statistics callback. | |
392 peerConnectionClient.enableStatsEvents(true, STAT_CALLBACK_PERIOD); | |
393 } | |
394 | |
395 private void onAudioManagerChangedState() { | |
396 // TODO(henrika): disable video if AppRTCAudioManager.AudioDevice.EARPIECE | |
397 // is active. | |
398 } | |
399 | |
400 // Create peer connection factory when EGL context is ready. | |
401 private void createPeerConnectionFactory() { | |
402 runOnUiThread(new Runnable() { | |
403 @Override | |
404 public void run() { | |
405 if (peerConnectionClient == null) { | |
406 final long delta = System.currentTimeMillis() - callStartedTimeMs; | |
407 Log.d(TAG, "Creating peer connection factory, delay=" + delta + "ms"); | |
408 peerConnectionClient = PeerConnectionClient.getInstance(); | |
409 peerConnectionClient.createPeerConnectionFactory(CallActivity.this, | |
410 VideoRendererGui.getEGLContext(), peerConnectionParameters, | |
411 CallActivity.this); | |
412 } | |
413 if (signalingParameters != null) { | |
414 Log.w(TAG, "EGL context is ready after room connection."); | |
415 onConnectedToRoomInternal(signalingParameters); | |
416 } | |
417 } | |
418 }); | |
419 } | |
420 | |
421 // Disconnect from remote resources, dispose of local resources, and exit. | |
422 private void disconnect() { | |
423 activityRunning = false; | |
424 if (appRtcClient != null) { | |
425 appRtcClient.disconnectFromRoom(); | |
426 appRtcClient = null; | |
427 } | |
428 if (peerConnectionClient != null) { | |
429 peerConnectionClient.close(); | |
430 peerConnectionClient = null; | |
431 } | |
432 if (audioManager != null) { | |
433 audioManager.close(); | |
434 audioManager = null; | |
435 } | |
436 if (iceConnected && !isError) { | |
437 setResult(RESULT_OK); | |
438 } else { | |
439 setResult(RESULT_CANCELED); | |
440 } | |
441 finish(); | |
442 } | |
443 | |
444 private void disconnectWithErrorMessage(final String errorMessage) { | |
445 if (commandLineRun || !activityRunning) { | |
446 Log.e(TAG, "Critical error: " + errorMessage); | |
447 disconnect(); | |
448 } else { | |
449 new AlertDialog.Builder(this) | |
450 .setTitle(getText(R.string.channel_error_title)) | |
451 .setMessage(errorMessage) | |
452 .setCancelable(false) | |
453 .setNeutralButton(R.string.ok, new DialogInterface.OnClickListener() { | |
454 @Override | |
455 public void onClick(DialogInterface dialog, int id) { | |
456 dialog.cancel(); | |
457 disconnect(); | |
458 } | |
459 }).create().show(); | |
460 } | |
461 } | |
462 | |
463 // Log |msg| and Toast about it. | |
464 private void logAndToast(String msg) { | |
465 Log.d(TAG, msg); | |
466 if (logToast != null) { | |
467 logToast.cancel(); | |
468 } | |
469 logToast = Toast.makeText(this, msg, Toast.LENGTH_SHORT); | |
470 logToast.show(); | |
471 } | |
472 | |
473 private void reportError(final String description) { | |
474 runOnUiThread(new Runnable() { | |
475 @Override | |
476 public void run() { | |
477 if (!isError) { | |
478 isError = true; | |
479 disconnectWithErrorMessage(description); | |
480 } | |
481 } | |
482 }); | |
483 } | |
484 | |
485 // -----Implementation of AppRTCClient.AppRTCSignalingEvents --------------- | |
486 // All callbacks are invoked from websocket signaling looper thread and | |
487 // are routed to UI thread. | |
488 private void onConnectedToRoomInternal(final SignalingParameters params) { | |
489 final long delta = System.currentTimeMillis() - callStartedTimeMs; | |
490 | |
491 signalingParameters = params; | |
492 if (peerConnectionClient == null) { | |
493 Log.w(TAG, "Room is connected, but EGL context is not ready yet."); | |
494 return; | |
495 } | |
496 logAndToast("Creating peer connection, delay=" + delta + "ms"); | |
497 peerConnectionClient.createPeerConnection( | |
498 localRender, remoteRender, signalingParameters); | |
499 | |
500 if (signalingParameters.initiator) { | |
501 logAndToast("Creating OFFER..."); | |
502 // Create offer. Offer SDP will be sent to answering client in | |
503 // PeerConnectionEvents.onLocalDescription event. | |
504 peerConnectionClient.createOffer(); | |
505 } else { | |
506 if (params.offerSdp != null) { | |
507 peerConnectionClient.setRemoteDescription(params.offerSdp); | |
508 logAndToast("Creating ANSWER..."); | |
509 // Create answer. Answer SDP will be sent to offering client in | |
510 // PeerConnectionEvents.onLocalDescription event. | |
511 peerConnectionClient.createAnswer(); | |
512 } | |
513 if (params.iceCandidates != null) { | |
514 // Add remote ICE candidates from room. | |
515 for (IceCandidate iceCandidate : params.iceCandidates) { | |
516 peerConnectionClient.addRemoteIceCandidate(iceCandidate); | |
517 } | |
518 } | |
519 } | |
520 } | |
521 | |
522 @Override | |
523 public void onConnectedToRoom(final SignalingParameters params) { | |
524 runOnUiThread(new Runnable() { | |
525 @Override | |
526 public void run() { | |
527 onConnectedToRoomInternal(params); | |
528 } | |
529 }); | |
530 } | |
531 | |
532 @Override | |
533 public void onRemoteDescription(final SessionDescription sdp) { | |
534 final long delta = System.currentTimeMillis() - callStartedTimeMs; | |
535 runOnUiThread(new Runnable() { | |
536 @Override | |
537 public void run() { | |
538 if (peerConnectionClient == null) { | |
539 Log.e(TAG, "Received remote SDP for non-initilized peer connection."); | |
540 return; | |
541 } | |
542 logAndToast("Received remote " + sdp.type + ", delay=" + delta + "ms"); | |
543 peerConnectionClient.setRemoteDescription(sdp); | |
544 if (!signalingParameters.initiator) { | |
545 logAndToast("Creating ANSWER..."); | |
546 // Create answer. Answer SDP will be sent to offering client in | |
547 // PeerConnectionEvents.onLocalDescription event. | |
548 peerConnectionClient.createAnswer(); | |
549 } | |
550 } | |
551 }); | |
552 } | |
553 | |
554 @Override | |
555 public void onRemoteIceCandidate(final IceCandidate candidate) { | |
556 runOnUiThread(new Runnable() { | |
557 @Override | |
558 public void run() { | |
559 if (peerConnectionClient == null) { | |
560 Log.e(TAG, | |
561 "Received ICE candidate for non-initilized peer connection."); | |
562 return; | |
563 } | |
564 peerConnectionClient.addRemoteIceCandidate(candidate); | |
565 } | |
566 }); | |
567 } | |
568 | |
569 @Override | |
570 public void onChannelClose() { | |
571 runOnUiThread(new Runnable() { | |
572 @Override | |
573 public void run() { | |
574 logAndToast("Remote end hung up; dropping PeerConnection"); | |
575 disconnect(); | |
576 } | |
577 }); | |
578 } | |
579 | |
580 @Override | |
581 public void onChannelError(final String description) { | |
582 reportError(description); | |
583 } | |
584 | |
585 // -----Implementation of PeerConnectionClient.PeerConnectionEvents.--------- | |
586 // Send local peer connection SDP and ICE candidates to remote party. | |
587 // All callbacks are invoked from peer connection client looper thread and | |
588 // are routed to UI thread. | |
589 @Override | |
590 public void onLocalDescription(final SessionDescription sdp) { | |
591 final long delta = System.currentTimeMillis() - callStartedTimeMs; | |
592 runOnUiThread(new Runnable() { | |
593 @Override | |
594 public void run() { | |
595 if (appRtcClient != null) { | |
596 logAndToast("Sending " + sdp.type + ", delay=" + delta + "ms"); | |
597 if (signalingParameters.initiator) { | |
598 appRtcClient.sendOfferSdp(sdp); | |
599 } else { | |
600 appRtcClient.sendAnswerSdp(sdp); | |
601 } | |
602 } | |
603 } | |
604 }); | |
605 } | |
606 | |
607 @Override | |
608 public void onIceCandidate(final IceCandidate candidate) { | |
609 runOnUiThread(new Runnable() { | |
610 @Override | |
611 public void run() { | |
612 if (appRtcClient != null) { | |
613 appRtcClient.sendLocalIceCandidate(candidate); | |
614 } | |
615 } | |
616 }); | |
617 } | |
618 | |
619 @Override | |
620 public void onIceConnected() { | |
621 final long delta = System.currentTimeMillis() - callStartedTimeMs; | |
622 runOnUiThread(new Runnable() { | |
623 @Override | |
624 public void run() { | |
625 logAndToast("ICE connected, delay=" + delta + "ms"); | |
626 iceConnected = true; | |
627 callConnected(); | |
628 } | |
629 }); | |
630 } | |
631 | |
632 @Override | |
633 public void onIceDisconnected() { | |
634 runOnUiThread(new Runnable() { | |
635 @Override | |
636 public void run() { | |
637 logAndToast("ICE disconnected"); | |
638 iceConnected = false; | |
639 disconnect(); | |
640 } | |
641 }); | |
642 } | |
643 | |
644 @Override | |
645 public void onPeerConnectionClosed() { | |
646 } | |
647 | |
648 @Override | |
649 public void onPeerConnectionStatsReady(final StatsReport[] reports) { | |
650 runOnUiThread(new Runnable() { | |
651 @Override | |
652 public void run() { | |
653 if (!isError && iceConnected) { | |
654 hudFragment.updateEncoderStatistics(reports); | |
655 } | |
656 } | |
657 }); | |
658 } | |
659 | |
660 @Override | |
661 public void onPeerConnectionError(final String description) { | |
662 reportError(description); | |
663 } | |
664 } | |
OLD | NEW |