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

Side by Side Diff: webrtc/sdk/android/src/java/org/webrtc/CameraCapturer.java

Issue 2833773003: Support adding and removing MediaRecorder to camera 2 session. (Closed)
Patch Set: Created 3 years, 8 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
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
11 package org.webrtc; 11 package org.webrtc;
12 12
13 import android.content.Context; 13 import android.content.Context;
14 import android.media.MediaRecorder;
14 import android.os.Handler; 15 import android.os.Handler;
15 import android.os.Looper; 16 import android.os.Looper;
16 import java.util.Arrays; 17 import java.util.Arrays;
17 18
18 @SuppressWarnings("deprecation") 19 @SuppressWarnings("deprecation")
19 abstract class CameraCapturer implements CameraVideoCapturer { 20 abstract class CameraCapturer implements CameraVideoCapturer {
20 enum SwitchState { 21 enum SwitchState {
21 IDLE, // No switch requested. 22 IDLE, // No switch requested.
22 PENDING, // Waiting for previous capture session to open. 23 PENDING, // Waiting for previous capture session to open.
23 IN_PROGRESS, // Waiting for new switched capture session to start. 24 IN_PROGRESS, // Waiting for new switched capture session to start.
24 } 25 }
25 26
27 enum MediaRecorderState {
28 IDLE, // No media recording update (add or remove) requested.
29 IN_PROGRESS, // Waiting for new capture session with updated MediaRecorder s urface to start.
30 }
31
26 private static final String TAG = "CameraCapturer"; 32 private static final String TAG = "CameraCapturer";
27 private final static int MAX_OPEN_CAMERA_ATTEMPTS = 3; 33 private final static int MAX_OPEN_CAMERA_ATTEMPTS = 3;
28 private final static int OPEN_CAMERA_DELAY_MS = 500; 34 private final static int OPEN_CAMERA_DELAY_MS = 500;
29 private final static int OPEN_CAMERA_TIMEOUT = 10000; 35 private final static int OPEN_CAMERA_TIMEOUT = 10000;
30 36
31 private final CameraEnumerator cameraEnumerator; 37 private final CameraEnumerator cameraEnumerator;
32 private final CameraEventsHandler eventsHandler; 38 private final CameraEventsHandler eventsHandler;
33 private final Handler uiThreadHandler; 39 private final Handler uiThreadHandler;
34 40
35 private final CameraSession.CreateSessionCallback createSessionCallback = 41 private final CameraSession.CreateSessionCallback createSessionCallback =
(...skipping 13 matching lines...) Expand all
49 55
50 if (switchState == SwitchState.IN_PROGRESS) { 56 if (switchState == SwitchState.IN_PROGRESS) {
51 if (switchEventsHandler != null) { 57 if (switchEventsHandler != null) {
52 switchEventsHandler.onCameraSwitchDone(cameraEnumerator.isFrontF acing(cameraName)); 58 switchEventsHandler.onCameraSwitchDone(cameraEnumerator.isFrontF acing(cameraName));
53 switchEventsHandler = null; 59 switchEventsHandler = null;
54 } 60 }
55 switchState = SwitchState.IDLE; 61 switchState = SwitchState.IDLE;
56 } else if (switchState == SwitchState.PENDING) { 62 } else if (switchState == SwitchState.PENDING) {
57 switchState = SwitchState.IDLE; 63 switchState = SwitchState.IDLE;
58 switchCameraInternal(switchEventsHandler); 64 switchCameraInternal(switchEventsHandler);
65 } else if (mediaRecorderState == MediaRecorderState.IN_PROGRESS) {
sakal 2017/04/21 08:06:15 One more thing, this shouldn't be else if. switchS
AlexG 2017/04/21 19:38:11 Done.
66 if (mediaRecorderEventsHandler != null) {
67 mediaRecorderEventsHandler.onMediaRecorderSuccess();
68 mediaRecorderEventsHandler = null;
69 }
70 mediaRecorder = null;
sakal 2017/04/21 08:06:15 Why is mediaRecorder set to null here? This means
AlexG 2017/04/21 19:38:11 Yes, camera switch is not allowed while MediaRecor
71 mediaRecorderState = MediaRecorderState.IDLE;
59 } 72 }
60 } 73 }
61 } 74 }
62 75
63 @Override 76 @Override
64 public void onFailure(CameraSession.FailureType failureType, String erro r) { 77 public void onFailure(CameraSession.FailureType failureType, String erro r) {
65 checkIsOnCameraThread(); 78 checkIsOnCameraThread();
66 uiThreadHandler.removeCallbacks(openCameraTimeoutRunnable); 79 uiThreadHandler.removeCallbacks(openCameraTimeoutRunnable);
67 synchronized (stateLock) { 80 synchronized (stateLock) {
68 capturerObserver.onCapturerStarted(false /* success */); 81 capturerObserver.onCapturerStarted(false /* success */);
69 openAttemptsRemaining--; 82 openAttemptsRemaining--;
70 83
71 if (openAttemptsRemaining <= 0) { 84 if (openAttemptsRemaining <= 0) {
72 Logging.w(TAG, "Opening camera failed, passing: " + error); 85 Logging.w(TAG, "Opening camera failed, passing: " + error);
73 sessionOpening = false; 86 sessionOpening = false;
74 stateLock.notifyAll(); 87 stateLock.notifyAll();
75 88
76 if (switchState != SwitchState.IDLE) { 89 if (switchState != SwitchState.IDLE) {
77 if (switchEventsHandler != null) { 90 if (switchEventsHandler != null) {
78 switchEventsHandler.onCameraSwitchError(error); 91 switchEventsHandler.onCameraSwitchError(error);
79 switchEventsHandler = null; 92 switchEventsHandler = null;
80 } 93 }
81 switchState = SwitchState.IDLE; 94 switchState = SwitchState.IDLE;
82 } 95 }
96 if (mediaRecorderState == MediaRecorderState.IN_PROGRESS) {
97 if (mediaRecorderEventsHandler != null) {
98 mediaRecorderEventsHandler.onMediaRecorderError(error);
99 mediaRecorderEventsHandler = null;
100 }
101 mediaRecorder = null;
102 mediaRecorderState = MediaRecorderState.IDLE;
103 }
83 104
84 if (failureType == CameraSession.FailureType.DISCONNECTED) { 105 if (failureType == CameraSession.FailureType.DISCONNECTED) {
85 eventsHandler.onCameraDisconnected(); 106 eventsHandler.onCameraDisconnected();
86 } else { 107 } else {
87 eventsHandler.onCameraError(error); 108 eventsHandler.onCameraError(error);
88 } 109 }
89 } else { 110 } else {
90 Logging.w(TAG, "Opening camera failed, retry: " + error); 111 Logging.w(TAG, "Opening camera failed, retry: " + error);
91 112
92 createSessionInternal(OPEN_CAMERA_DELAY_MS); 113 createSessionInternal(OPEN_CAMERA_DELAY_MS);
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
191 eventsHandler.onCameraError("Camera failed to start within timeout."); 212 eventsHandler.onCameraError("Camera failed to start within timeout.");
192 } 213 }
193 }; 214 };
194 215
195 // Initialized on initialize 216 // Initialized on initialize
196 // ------------------------- 217 // -------------------------
197 private Handler cameraThreadHandler; 218 private Handler cameraThreadHandler;
198 private Context applicationContext; 219 private Context applicationContext;
199 private CapturerObserver capturerObserver; 220 private CapturerObserver capturerObserver;
200 private SurfaceTextureHelper surfaceHelper; 221 private SurfaceTextureHelper surfaceHelper;
222 private MediaRecorder mediaRecorder;
201 223
202 private final Object stateLock = new Object(); 224 private final Object stateLock = new Object();
203 private boolean sessionOpening; /* guarded by stateLock */ 225 private boolean sessionOpening; /* guarded by stateLock */
204 private CameraSession currentSession; /* guarded by stateLock */ 226 private CameraSession currentSession; /* guarded by stateLock */
205 private String cameraName; /* guarded by stateLock */ 227 private String cameraName; /* guarded by stateLock */
206 private int width; /* guarded by stateLock */ 228 private int width; /* guarded by stateLock */
207 private int height; /* guarded by stateLock */ 229 private int height; /* guarded by stateLock */
208 private int framerate; /* guarded by stateLock */ 230 private int framerate; /* guarded by stateLock */
209 private int openAttemptsRemaining; /* guarded by stateLock */ 231 private int openAttemptsRemaining; /* guarded by stateLock */
210 private SwitchState switchState = SwitchState.IDLE; /* guarded by stateLock */ 232 private SwitchState switchState = SwitchState.IDLE; /* guarded by stateLock */
233 /* guarded by stateLock */
234 private MediaRecorderState mediaRecorderState = MediaRecorderState.IDLE;
sakal 2017/04/21 07:56:49 Since these are only manipulated on the camera thr
AlexG 2017/04/21 19:38:11 Done.
211 private CameraSwitchHandler switchEventsHandler; /* guarded by stateLock */ 235 private CameraSwitchHandler switchEventsHandler; /* guarded by stateLock */
236 private MediaRecorderHandler mediaRecorderEventsHandler; /* guarded by stateLo ck */
212 // Valid from onDone call until stopCapture, otherwise null. 237 // Valid from onDone call until stopCapture, otherwise null.
213 private CameraStatistics cameraStatistics; /* guarded by stateLock */ 238 private CameraStatistics cameraStatistics; /* guarded by stateLock */
214 private boolean firstFrameObserved; /* guarded by stateLock */ 239 private boolean firstFrameObserved; /* guarded by stateLock */
215 240
216 public CameraCapturer( 241 public CameraCapturer(
217 String cameraName, CameraEventsHandler eventsHandler, CameraEnumerator cam eraEnumerator) { 242 String cameraName, CameraEventsHandler eventsHandler, CameraEnumerator cam eraEnumerator) {
218 if (eventsHandler == null) { 243 if (eventsHandler == null) {
219 eventsHandler = new CameraEventsHandler() { 244 eventsHandler = new CameraEventsHandler() {
220 @Override 245 @Override
221 public void onCameraError(String errorDescription) {} 246 public void onCameraError(String errorDescription) {}
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
280 createSessionInternal(0); 305 createSessionInternal(0);
281 } 306 }
282 } 307 }
283 308
284 private void createSessionInternal(int delayMs) { 309 private void createSessionInternal(int delayMs) {
285 uiThreadHandler.postDelayed(openCameraTimeoutRunnable, delayMs + OPEN_CAMERA _TIMEOUT); 310 uiThreadHandler.postDelayed(openCameraTimeoutRunnable, delayMs + OPEN_CAMERA _TIMEOUT);
286 cameraThreadHandler.postDelayed(new Runnable() { 311 cameraThreadHandler.postDelayed(new Runnable() {
287 @Override 312 @Override
288 public void run() { 313 public void run() {
289 createCameraSession(createSessionCallback, cameraSessionEventsHandler, a pplicationContext, 314 createCameraSession(createSessionCallback, cameraSessionEventsHandler, a pplicationContext,
290 surfaceHelper, cameraName, width, height, framerate); 315 surfaceHelper, mediaRecorder, cameraName, width, height, framerate);
291 } 316 }
292 }, delayMs); 317 }, delayMs);
293 } 318 }
294 319
295 @Override 320 @Override
296 public void stopCapture() { 321 public void stopCapture() {
297 Logging.d(TAG, "Stop capture"); 322 Logging.d(TAG, "Stop capture");
298 323
299 synchronized (stateLock) { 324 synchronized (stateLock) {
300 while (sessionOpening) { 325 while (sessionOpening) {
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
343 Logging.d(TAG, "switchCamera"); 368 Logging.d(TAG, "switchCamera");
344 cameraThreadHandler.post(new Runnable() { 369 cameraThreadHandler.post(new Runnable() {
345 @Override 370 @Override
346 public void run() { 371 public void run() {
347 switchCameraInternal(switchEventsHandler); 372 switchCameraInternal(switchEventsHandler);
348 } 373 }
349 }); 374 });
350 } 375 }
351 376
352 @Override 377 @Override
378 public void addMediaRecorderToCamera(
379 final MediaRecorder mediaRecorder, final MediaRecorderHandler mediaRecoder EventsHandler) {
380 Logging.d(TAG, "addMediaRecorderToCamera");
381 cameraThreadHandler.post(new Runnable() {
382 @Override
383 public void run() {
384 updateMediaRecorderInternal(mediaRecorder, mediaRecoderEventsHandler);
385 }
386 });
387 }
388
389 @Override
390 public void removeMediaRecorderFromCamera(final MediaRecorderHandler mediaReco derEventsHandler) {
391 Logging.d(TAG, "removeMediaRecorderFromCamera");
392 cameraThreadHandler.post(new Runnable() {
393 @Override
394 public void run() {
395 updateMediaRecorderInternal(null /* mediaRecorder */, mediaRecoderEvents Handler);
396 }
397 });
398 }
399
400 @Override
353 public boolean isScreencast() { 401 public boolean isScreencast() {
354 return false; 402 return false;
355 } 403 }
356 404
357 public void printStackTrace() { 405 public void printStackTrace() {
358 Thread cameraThread = null; 406 Thread cameraThread = null;
359 if (cameraThreadHandler != null) { 407 if (cameraThreadHandler != null) {
360 cameraThread = cameraThreadHandler.getLooper().getThread(); 408 cameraThread = cameraThreadHandler.getLooper().getThread();
361 } 409 }
362 if (cameraThread != null) { 410 if (cameraThread != null) {
(...skipping 30 matching lines...) Expand all
393 441
394 if (!sessionOpening && currentSession == null) { 442 if (!sessionOpening && currentSession == null) {
395 Logging.d(TAG, "switchCamera: No session open"); 443 Logging.d(TAG, "switchCamera: No session open");
396 if (switchEventsHandler != null) { 444 if (switchEventsHandler != null) {
397 switchEventsHandler.onCameraSwitchError("Camera is not running."); 445 switchEventsHandler.onCameraSwitchError("Camera is not running.");
398 } 446 }
399 return; 447 return;
400 } 448 }
401 449
402 this.switchEventsHandler = switchEventsHandler; 450 this.switchEventsHandler = switchEventsHandler;
403 if (sessionOpening) { 451 if (sessionOpening) {
magjed_webrtc 2017/04/21 10:45:16 We should decide if it's ok or not to call switchC
AlexG 2017/04/21 19:38:11 I think this is not allowed - we can not reconfigu
404 switchState = SwitchState.PENDING; 452 switchState = SwitchState.PENDING;
405 return; 453 return;
406 } else { 454 } else {
407 switchState = SwitchState.IN_PROGRESS; 455 switchState = SwitchState.IN_PROGRESS;
408 } 456 }
409 457
410 Logging.d(TAG, "switchCamera: Stopping session"); 458 Logging.d(TAG, "switchCamera: Stopping session");
411 cameraStatistics.release(); 459 cameraStatistics.release();
412 cameraStatistics = null; 460 cameraStatistics = null;
413 final CameraSession oldSession = currentSession; 461 final CameraSession oldSession = currentSession;
414 cameraThreadHandler.post(new Runnable() { 462 cameraThreadHandler.post(new Runnable() {
415 @Override 463 @Override
416 public void run() { 464 public void run() {
417 oldSession.stop(); 465 oldSession.stop();
418 } 466 }
419 }); 467 });
420 currentSession = null; 468 currentSession = null;
421 469
422 int cameraNameIndex = Arrays.asList(deviceNames).indexOf(cameraName); 470 int cameraNameIndex = Arrays.asList(deviceNames).indexOf(cameraName);
423 cameraName = deviceNames[(cameraNameIndex + 1) % deviceNames.length]; 471 cameraName = deviceNames[(cameraNameIndex + 1) % deviceNames.length];
424 472
425 sessionOpening = true; 473 sessionOpening = true;
426 openAttemptsRemaining = 1; 474 openAttemptsRemaining = 1;
427 createSessionInternal(0); 475 createSessionInternal(0);
428 } 476 }
429 Logging.d(TAG, "switchCamera done"); 477 Logging.d(TAG, "switchCamera done");
430 } 478 }
431 479
480 private void reportUpdateMediaRecorderError(
481 String error, MediaRecorderHandler mediaRecoderEventsHandler) {
482 Logging.e(TAG, error);
sakal 2017/04/21 07:56:49 Please add checkIsOnCameraThread()
AlexG 2017/04/21 19:38:11 Done.
483 if (mediaRecoderEventsHandler != null) {
484 mediaRecoderEventsHandler.onMediaRecorderError(error);
485 }
486 }
487
488 private void updateMediaRecorderInternal(
489 final MediaRecorder mediaRecorder, final MediaRecorderHandler mediaRecoder EventsHandler) {
490 Logging.d(TAG,
sakal 2017/04/21 07:56:49 Please add checkIsOnCameraThread()
AlexG 2017/04/21 19:38:11 Done.
491 "updateMediaRecoderInternal internal. State: " + mediaRecorderState
492 + ". Session opening: " + sessionOpening);
493
494 synchronized (stateLock) {
495 if (mediaRecorderState != MediaRecorderState.IDLE) {
496 reportUpdateMediaRecorderError(
497 "MediaRecorder update already in progress.", mediaRecoderEventsHandl er);
498 return;
499 }
500 if (switchState != SwitchState.IDLE) {
501 reportUpdateMediaRecorderError(
502 "MediaRecorder update while camera is switching.", mediaRecoderEvent sHandler);
503 return;
504 }
505 if (sessionOpening) {
506 reportUpdateMediaRecorderError(
507 "MediaRecorder update while camera is still opening.", mediaRecoderE ventsHandler);
508 return;
509 }
510
511 this.mediaRecorder = mediaRecorder;
512 this.mediaRecorderEventsHandler = mediaRecoderEventsHandler;
513 mediaRecorderState = MediaRecorderState.IN_PROGRESS;
514
515 Logging.d(TAG, "updateMediaRecoder: Stopping session");
516 cameraStatistics.release();
517 cameraStatistics = null;
518 final CameraSession oldSession = currentSession;
519 cameraThreadHandler.post(new Runnable() {
520 @Override
521 public void run() {
522 oldSession.stop();
523 }
524 });
525 currentSession = null;
526
527 sessionOpening = true;
528 openAttemptsRemaining = 1;
529 createSessionInternal(0);
530 }
531 Logging.d(TAG, "updateMediaRecoderInternal done");
532 }
533
432 private void checkIsOnCameraThread() { 534 private void checkIsOnCameraThread() {
433 if (Thread.currentThread() != cameraThreadHandler.getLooper().getThread()) { 535 if (Thread.currentThread() != cameraThreadHandler.getLooper().getThread()) {
434 Logging.e(TAG, "Check is on camera thread failed."); 536 Logging.e(TAG, "Check is on camera thread failed.");
435 throw new RuntimeException("Not on camera thread."); 537 throw new RuntimeException("Not on camera thread.");
436 } 538 }
437 } 539 }
438 540
439 protected String getCameraName() { 541 protected String getCameraName() {
440 synchronized (stateLock) { 542 synchronized (stateLock) {
441 return cameraName; 543 return cameraName;
442 } 544 }
443 } 545 }
444 546
445 abstract protected void createCameraSession( 547 abstract protected void createCameraSession(
446 CameraSession.CreateSessionCallback createSessionCallback, CameraSession.E vents events, 548 CameraSession.CreateSessionCallback createSessionCallback, CameraSession.E vents events,
447 Context applicationContext, SurfaceTextureHelper surfaceTextureHelper, Str ing cameraName, 549 Context applicationContext, SurfaceTextureHelper surfaceTextureHelper,
448 int width, int height, int framerate); 550 MediaRecorder mediaRecoder, String cameraName, int width, int height, int framerate);
449 } 551 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698