From 28d5bc68c353c46d43faf0a875dea77863852691 Mon Sep 17 00:00:00 2001 From: sakal Date: Wed, 21 Sep 2016 07:44:50 -0700 Subject: [PATCH] Fix deadlock issue in CameraCapturer.stopCapture. BUG=webrtc:6404 NOTRY=True Review-Url: https://codereview.webrtc.org/2357213002 Cr-Commit-Position: refs/heads/master@{#14333} --- .../java/src/org/webrtc/Camera1Session.java | 42 ++++--------------- .../java/src/org/webrtc/Camera2Session.java | 42 ++++--------------- .../java/src/org/webrtc/CameraCapturer.java | 23 +++++++--- 3 files changed, 34 insertions(+), 73 deletions(-) diff --git a/webrtc/api/android/java/src/org/webrtc/Camera1Session.java b/webrtc/api/android/java/src/org/webrtc/Camera1Session.java index 2d897e3ed1..9081999641 100644 --- a/webrtc/api/android/java/src/org/webrtc/Camera1Session.java +++ b/webrtc/api/android/java/src/org/webrtc/Camera1Session.java @@ -22,7 +22,6 @@ import android.view.WindowManager; import java.io.IOException; import java.nio.ByteBuffer; import java.util.List; -import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @SuppressWarnings("deprecation") @@ -181,40 +180,15 @@ public class Camera1Session implements CameraSession { @Override public void stop() { - final long stopStartTime = System.nanoTime(); Logging.d(TAG, "Stop camera1 session on camera " + cameraId); - if (Thread.currentThread() == cameraThreadHandler.getLooper().getThread()) { - if (state != SessionState.STOPPED) { - state = SessionState.STOPPED; - // Post the stopInternal to return earlier. - cameraThreadHandler.post(new Runnable() { - @Override - public void run() { - stopInternal(); - final int stopTimeMs = - (int) TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - stopStartTime); - camera1StopTimeMsHistogram.addSample(stopTimeMs); - } - }); - } - } else { - final CountDownLatch stopLatch = new CountDownLatch(1); - - cameraThreadHandler.post(new Runnable() { - @Override - public void run() { - if (state != SessionState.STOPPED) { - state = SessionState.STOPPED; - stopLatch.countDown(); - stopInternal(); - final int stopTimeMs = - (int) TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - stopStartTime); - camera1StopTimeMsHistogram.addSample(stopTimeMs); - } - } - }); - - ThreadUtils.awaitUninterruptibly(stopLatch); + checkIsOnCameraThread(); + if (state != SessionState.STOPPED) { + final long stopStartTime = System.nanoTime(); + state = SessionState.STOPPED; + stopInternal(); + final int stopTimeMs = + (int) TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - stopStartTime); + camera1StopTimeMsHistogram.addSample(stopTimeMs); } } diff --git a/webrtc/api/android/java/src/org/webrtc/Camera2Session.java b/webrtc/api/android/java/src/org/webrtc/Camera2Session.java index 460bba68ec..c699bbb845 100644 --- a/webrtc/api/android/java/src/org/webrtc/Camera2Session.java +++ b/webrtc/api/android/java/src/org/webrtc/Camera2Session.java @@ -31,7 +31,6 @@ import android.view.WindowManager; import java.util.Arrays; import java.util.List; -import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @TargetApi(21) @@ -366,40 +365,15 @@ public class Camera2Session implements CameraSession { @Override public void stop() { - final long stopStartTime = System.nanoTime(); Logging.d(TAG, "Stop camera2 session on camera " + cameraId); - if (Thread.currentThread() == cameraThreadHandler.getLooper().getThread()) { - if (state != SessionState.STOPPED) { - state = SessionState.STOPPED; - // Post the stopInternal to return earlier. - cameraThreadHandler.post(new Runnable() { - @Override - public void run() { - stopInternal(); - final int stopTimeMs = - (int) TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - stopStartTime); - camera2StopTimeMsHistogram.addSample(stopTimeMs); - } - }); - } - } else { - final CountDownLatch stopLatch = new CountDownLatch(1); - - cameraThreadHandler.post(new Runnable() { - @Override - public void run() { - if (state != SessionState.STOPPED) { - state = SessionState.STOPPED; - stopLatch.countDown(); - stopInternal(); - final int stopTimeMs = - (int) TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - stopStartTime); - camera2StopTimeMsHistogram.addSample(stopTimeMs); - } - } - }); - - ThreadUtils.awaitUninterruptibly(stopLatch); + checkIsOnCameraThread(); + if (state != SessionState.STOPPED) { + final long stopStartTime = System.nanoTime(); + state = SessionState.STOPPED; + stopInternal(); + final int stopTimeMs = + (int) TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - stopStartTime); + camera2StopTimeMsHistogram.addSample(stopTimeMs); } } diff --git a/webrtc/api/android/java/src/org/webrtc/CameraCapturer.java b/webrtc/api/android/java/src/org/webrtc/CameraCapturer.java index e0ce19d42a..2b0ffdcee7 100644 --- a/webrtc/api/android/java/src/org/webrtc/CameraCapturer.java +++ b/webrtc/api/android/java/src/org/webrtc/CameraCapturer.java @@ -40,8 +40,8 @@ public abstract class CameraCapturer implements CameraVideoCapturer { checkIsOnCameraThread(); Logging.d(TAG, "Create session done"); uiThreadHandler.removeCallbacks(openCameraTimeoutRunnable); - capturerObserver.onCapturerStarted(true /* success */); synchronized (stateLock) { + capturerObserver.onCapturerStarted(true /* success */); sessionOpening = false; currentSession = session; cameraStatistics = new CameraStatistics(surfaceHelper, eventsHandler); @@ -66,8 +66,8 @@ public abstract class CameraCapturer implements CameraVideoCapturer { public void onFailure(String error) { checkIsOnCameraThread(); uiThreadHandler.removeCallbacks(openCameraTimeoutRunnable); - capturerObserver.onCapturerStarted(false /* success */); synchronized (stateLock) { + capturerObserver.onCapturerStarted(false /* success */); openAttemptsRemaining--; if (openAttemptsRemaining <= 0) { @@ -284,11 +284,18 @@ public abstract class CameraCapturer implements CameraVideoCapturer { ThreadUtils.waitUninterruptibly(stateLock); } + if (currentSession != null) { - Logging.d(TAG, "Stop capture: Stopping session"); + Logging.d(TAG, "Stop capture: Nulling session"); cameraStatistics.release(); cameraStatistics = null; - currentSession.stop(); + final CameraSession oldSession = currentSession; + cameraThreadHandler.post(new Runnable() { + @Override + public void run() { + oldSession.stop(); + } + }); currentSession = null; capturerObserver.onCapturerStopped(); } else { @@ -397,7 +404,13 @@ public abstract class CameraCapturer implements CameraVideoCapturer { Logging.d(TAG, "switchCamera: Stopping session"); cameraStatistics.release(); cameraStatistics = null; - currentSession.stop(); + final CameraSession oldSession = currentSession; + cameraThreadHandler.post(new Runnable() { + @Override + public void run() { + oldSession.stop(); + } + }); currentSession = null; int cameraNameIndex = Arrays.asList(deviceNames).indexOf(cameraName);