summaryrefslogtreecommitdiffstats
path: root/media/base/android/java
diff options
context:
space:
mode:
authorbraveyao <braveyao@chromium.org>2015-08-24 21:21:08 -0700
committerCommit bot <commit-bot@chromium.org>2015-08-25 04:21:39 +0000
commite4f0b8fffdaa39c929fde3dccd1561efbc7b6935 (patch)
treed128a1133fc51d065d97f49132393565dc28d4ce /media/base/android/java
parent33050eaa1f93d596b6fa166dfede492645a440f9 (diff)
downloadchromium_src-e4f0b8fffdaa39c929fde3dccd1561efbc7b6935.zip
chromium_src-e4f0b8fffdaa39c929fde3dccd1561efbc7b6935.tar.gz
chromium_src-e4f0b8fffdaa39c929fde3dccd1561efbc7b6935.tar.bz2
On Nexus9, if you open two webrtc tabs and switch them very quickly, then chrome will stop responding soon.
The reason is tab switching on Android will cause capture start/stop accordingly on the OnWasHidden/OnWasShown events. On N9 it's Camera2 API deployed. And with Camera2, capture will start asynchronously. If stopCapture comes too soon, it will fail and the next startCapture will cause the Camera2 into error status(You can't start capture twice in a row with Camera2 API) and freezes Chrome. This is a simple/straight patch to make the startCapture return synchronously. Please help to advice if this is proper here, or what other ideas you may have. BUG=501790 Test=Manual Test Review URL: https://codereview.chromium.org/1294953004 Cr-Commit-Position: refs/heads/master@{#345254}
Diffstat (limited to 'media/base/android/java')
-rw-r--r--media/base/android/java/src/org/chromium/media/VideoCaptureCamera2.java61
1 files changed, 40 insertions, 21 deletions
diff --git a/media/base/android/java/src/org/chromium/media/VideoCaptureCamera2.java b/media/base/android/java/src/org/chromium/media/VideoCaptureCamera2.java
index 81c147f..81db67a 100644
--- a/media/base/android/java/src/org/chromium/media/VideoCaptureCamera2.java
+++ b/media/base/android/java/src/org/chromium/media/VideoCaptureCamera2.java
@@ -46,10 +46,9 @@ public class VideoCaptureCamera2 extends VideoCapture {
@Override
public void onOpened(CameraDevice cameraDevice) {
mCameraDevice = cameraDevice;
- mOpeningCamera = false;
- mConfiguringCamera = true;
+ changeCameraStateAndNotify(CameraState.CONFIGURING);
if (!createCaptureObjects()) {
- mConfiguringCamera = false;
+ changeCameraStateAndNotify(CameraState.STOPPED);
nativeOnError(mNativeVideoCaptureDeviceAndroid,
"Error configuring camera");
}
@@ -59,14 +58,14 @@ public class VideoCaptureCamera2 extends VideoCapture {
public void onDisconnected(CameraDevice cameraDevice) {
cameraDevice.close();
mCameraDevice = null;
- mOpeningCamera = false;
+ changeCameraStateAndNotify(CameraState.STOPPED);
}
@Override
public void onError(CameraDevice cameraDevice, int error) {
cameraDevice.close();
mCameraDevice = null;
- mOpeningCamera = false;
+ changeCameraStateAndNotify(CameraState.STOPPED);
nativeOnError(mNativeVideoCaptureDeviceAndroid,
"Camera device error " + Integer.toString(error));
}
@@ -78,14 +77,15 @@ public class VideoCaptureCamera2 extends VideoCapture {
public void onConfigured(CameraCaptureSession cameraCaptureSession) {
Log.d(TAG, "onConfigured");
mCaptureSession = cameraCaptureSession;
- mConfiguringCamera = false;
createCaptureRequest();
+ changeCameraStateAndNotify(CameraState.STARTED);
}
@Override
public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
// TODO(mcasas): When signalling error, C++ will tear us down. Is there need for
// cleanup?
+ changeCameraStateAndNotify(CameraState.STOPPED);
nativeOnError(mNativeVideoCaptureDeviceAndroid,
"Camera session configuration error");
}
@@ -125,14 +125,6 @@ public class VideoCaptureCamera2 extends VideoCapture {
private byte[] mCapturedData;
- // |mOpeningCamera| is used to signal the transient between openCamera() and
- // CrStateListener.onOpened().
- private boolean mOpeningCamera = false;
- // |mConfiguringCamera| marks the transient between CrStateListener.onOpened()
- // and CrCaptureSessionListener.onConfigured(), including the time it takes
- // to createCaptureObjects().
- private boolean mConfiguringCamera = false;
-
private CameraDevice mCameraDevice = null;
private CaptureRequest.Builder mPreviewBuilder = null;
private CameraCaptureSession mCaptureSession = null;
@@ -141,6 +133,10 @@ public class VideoCaptureCamera2 extends VideoCapture {
private static final double kNanoSecondsToFps = 1.0E-9;
private static final String TAG = "cr.media";
+ private static enum CameraState {OPENING, CONFIGURING, STARTED, STOPPED}
+ private CameraState mCameraState = CameraState.STOPPED;
+ private final Object mCameraStateLock = new Object();
+
// Service function to grab CameraCharacteristics and handle exceptions.
private static CameraCharacteristics getCameraCharacteristics(Context appContext, int id) {
final CameraManager manager =
@@ -283,6 +279,13 @@ public class VideoCaptureCamera2 extends VideoCapture {
}
}
+ private void changeCameraStateAndNotify(CameraState state) {
+ synchronized (mCameraStateLock) {
+ mCameraState = state;
+ mCameraStateLock.notifyAll();
+ }
+ }
+
static boolean isLegacyDevice(Context appContext, int id) {
final CameraCharacteristics cameraCharacteristics =
getCameraCharacteristics(appContext, id);
@@ -387,9 +390,11 @@ public class VideoCaptureCamera2 extends VideoCapture {
@Override
public boolean allocate(int width, int height, int frameRate) {
Log.d(TAG, "allocate: requested (%d x %d) @%dfps", width, height, frameRate);
- if (mOpeningCamera || mConfiguringCamera) {
- Log.e(TAG, "allocate() invoked while Camera is busy opening/configuring.");
- return false;
+ synchronized (mCameraStateLock) {
+ if (mCameraState == CameraState.OPENING || mCameraState == CameraState.CONFIGURING) {
+ Log.e(TAG, "allocate() invoked while Camera is busy opening/configuring.");
+ return false;
+ }
}
// |mCaptureFormat| is also used to configure the ImageReader.
mCaptureFormat = new VideoCaptureFormat(width, height, frameRate, ImageFormat.YUV_420_888);
@@ -411,8 +416,7 @@ public class VideoCaptureCamera2 extends VideoCapture {
@Override
public boolean startCapture() {
Log.d(TAG, "startCapture");
- mOpeningCamera = true;
- mConfiguringCamera = false;
+ changeCameraStateAndNotify(CameraState.OPENING);
final CameraManager manager =
(CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE);
final Handler mainHandler = new Handler(mContext.getMainLooper());
@@ -429,13 +433,28 @@ public class VideoCaptureCamera2 extends VideoCapture {
Log.e(TAG, "allocate: manager.openCamera: " + ex);
return false;
}
+
return true;
}
@Override
public boolean stopCapture() {
Log.d(TAG, "stopCapture");
- if (mCaptureSession == null) return false;
+
+ // With Camera2 API, the capture is started asynchronously, which will cause problem if
+ // stopCapture comes too quickly. Without stopping the previous capture properly, the next
+ // startCapture will fail and make Chrome no-responding. So wait camera to be STARTED.
+ synchronized (mCameraStateLock) {
+ while (mCameraState != CameraState.STARTED && mCameraState != CameraState.STOPPED) {
+ try {
+ mCameraStateLock.wait();
+ } catch (InterruptedException ex) {
+ Log.e(TAG, "CaptureStartedEvent: " + ex);
+ }
+ }
+ if (mCameraState == CameraState.STOPPED) return true;
+ }
+
try {
mCaptureSession.abortCaptures();
} catch (CameraAccessException ex) {
@@ -447,7 +466,7 @@ public class VideoCaptureCamera2 extends VideoCapture {
}
if (mCameraDevice == null) return false;
mCameraDevice.close();
-
+ changeCameraStateAndNotify(CameraState.STOPPED);
return true;
}