diff --git a/webrtc/api/android/java/src/org/webrtc/Camera2Session.java b/webrtc/api/android/java/src/org/webrtc/Camera2Session.java index 5e32c27102..9bcdfafa20 100644 --- a/webrtc/api/android/java/src/org/webrtc/Camera2Session.java +++ b/webrtc/api/android/java/src/org/webrtc/Camera2Session.java @@ -318,21 +318,35 @@ public class Camera2Session implements CameraSession { @Override public void stop() { Logging.d(TAG, "Stop camera2 session on camera " + cameraId); - final CountDownLatch stopLatch = new CountDownLatch(1); - - cameraThreadHandler.post(new Runnable() { - @Override - public void run() { - if (state != SessionState.STOPPED) { - state = SessionState.STOPPED; - capturerObserver.onCapturerStopped(); - stopLatch.countDown(); - stopInternal(); - } + if (Thread.currentThread() == cameraThreadHandler.getLooper().getThread()) { + if (state != SessionState.STOPPED) { + state = SessionState.STOPPED; + capturerObserver.onCapturerStopped(); + // Post the stopInternal to return earlier. + cameraThreadHandler.post(new Runnable() { + @Override + public void run() { + stopInternal(); + } + }); } - }); + } else { + final CountDownLatch stopLatch = new CountDownLatch(1); - ThreadUtils.awaitUninterruptibly(stopLatch); + cameraThreadHandler.post(new Runnable() { + @Override + public void run() { + if (state != SessionState.STOPPED) { + state = SessionState.STOPPED; + capturerObserver.onCapturerStopped(); + stopLatch.countDown(); + stopInternal(); + } + } + }); + + ThreadUtils.awaitUninterruptibly(stopLatch); + } } private void stopInternal() { diff --git a/webrtc/api/android/java/src/org/webrtc/CameraCapturer.java b/webrtc/api/android/java/src/org/webrtc/CameraCapturer.java index 75712cc570..7e7d2362bd 100644 --- a/webrtc/api/android/java/src/org/webrtc/CameraCapturer.java +++ b/webrtc/api/android/java/src/org/webrtc/CameraCapturer.java @@ -10,17 +10,19 @@ package org.webrtc; -import org.webrtc.CameraEnumerationAndroid.CaptureFormat; - import android.content.Context; import android.os.Handler; -import android.os.SystemClock; import java.util.Arrays; -import java.util.List; @SuppressWarnings("deprecation") public abstract class CameraCapturer implements CameraVideoCapturer { + enum SwitchState { + IDLE, // No switch requested. + PENDING, // Waiting for previous capture session to open. + IN_PROGRESS, // Waiting for new switched capture session to start. + } + private static final String TAG = "CameraCapturer"; private final static int MAX_OPEN_CAMERA_ATTEMPTS = 3; private final static int OPEN_CAMERA_DELAY_MS = 500; @@ -39,12 +41,17 @@ public abstract class CameraCapturer implements CameraVideoCapturer { currentSession = session; stateLock.notifyAll(); - if (switchEventsHandler != null) { - switchEventsHandler.onCameraSwitchDone( - cameraEnumerator.isFrontFacing(cameraName)); - switchEventsHandler = null; + if (switchState == SwitchState.IN_PROGRESS) { + if (switchEventsHandler != null) { + switchEventsHandler.onCameraSwitchDone( + cameraEnumerator.isFrontFacing(cameraName)); + switchEventsHandler = null; + } + switchState = SwitchState.IDLE; + } else if (switchState == SwitchState.PENDING) { + switchState = SwitchState.IDLE; + switchCameraInternal(switchEventsHandler); } - switchInProgress = false; } } @@ -58,11 +65,13 @@ public abstract class CameraCapturer implements CameraVideoCapturer { sessionOpening = false; stateLock.notifyAll(); - if (switchEventsHandler != null) { - switchEventsHandler.onCameraSwitchError(error); - switchEventsHandler = null; + if (switchState != SwitchState.IDLE) { + if (switchEventsHandler != null) { + switchEventsHandler.onCameraSwitchError(error); + switchEventsHandler = null; + } + switchState = SwitchState.IDLE; } - switchInProgress = false; eventsHandler.onCameraError(error); } else { @@ -76,8 +85,6 @@ public abstract class CameraCapturer implements CameraVideoCapturer { // Initialized on initialize // ------------------------- - // Use postOnCameraThread() instead of posting directly to the handler - this way all - // callbacks with a specifed token can be removed at once. private Handler cameraThreadHandler; private Context applicationContext; private CapturerObserver capturerObserver; @@ -91,7 +98,7 @@ public abstract class CameraCapturer implements CameraVideoCapturer { private int height; /* guarded by stateLock */ private int framerate; /* guarded by stateLock */ private int openAttemptsRemaining; /* guarded by stateLock */ - private boolean switchInProgress; /* guarded by stateLock */ + private SwitchState switchState = SwitchState.IDLE; /* guarded by stateLock */ private CameraSwitchHandler switchEventsHandler; /* guarded by stateLock */ public CameraCapturer( @@ -219,6 +226,16 @@ public abstract class CameraCapturer implements CameraVideoCapturer { @Override public void switchCamera(final CameraSwitchHandler switchEventsHandler) { Logging.d(TAG, "switchCamera"); + cameraThreadHandler.post(new Runnable() { + @Override + public void run() { + switchCameraInternal(switchEventsHandler); + } + }); + } + + private void switchCameraInternal(final CameraSwitchHandler switchEventsHandler) { + Logging.d(TAG, "switchCamera internal"); final String[] deviceNames = cameraEnumerator.getDeviceNames(); @@ -230,7 +247,7 @@ public abstract class CameraCapturer implements CameraVideoCapturer { } synchronized (stateLock) { - if (switchInProgress) { + if (switchState != SwitchState.IDLE) { Logging.d(TAG, "switchCamera switchInProgress"); if (switchEventsHandler != null) { switchEventsHandler.onCameraSwitchError("Camera switch already in progress."); @@ -238,12 +255,12 @@ public abstract class CameraCapturer implements CameraVideoCapturer { return; } + this.switchEventsHandler = switchEventsHandler; if (sessionOpening) { - Logging.d(TAG, "switchCamera sessionOpening"); - if (switchEventsHandler != null) { - switchEventsHandler.onCameraSwitchError("Session is still opening."); - } + switchState = SwitchState.PENDING; return; + } else { + switchState = SwitchState.IN_PROGRESS; } if (currentSession == null) { @@ -261,8 +278,6 @@ public abstract class CameraCapturer implements CameraVideoCapturer { int cameraNameIndex = Arrays.asList(deviceNames).indexOf(cameraName); cameraName = deviceNames[(cameraNameIndex + 1) % deviceNames.length]; - switchInProgress = true; - this.switchEventsHandler = switchEventsHandler; sessionOpening = true; openAttemptsRemaining = 1; createSessionInternal(0);