Index: webrtc/sdk/android/src/java/org/webrtc/CameraCapturer.java |
diff --git a/webrtc/sdk/android/src/java/org/webrtc/CameraCapturer.java b/webrtc/sdk/android/src/java/org/webrtc/CameraCapturer.java |
index c3e8daab17cd857f8f5a968f0fdc86ab94c20e63..127df3b20f0f035fad51101954a487f6eefb9333 100644 |
--- a/webrtc/sdk/android/src/java/org/webrtc/CameraCapturer.java |
+++ b/webrtc/sdk/android/src/java/org/webrtc/CameraCapturer.java |
@@ -11,6 +11,7 @@ |
package org.webrtc; |
import android.content.Context; |
+import android.media.MediaRecorder; |
import android.os.Handler; |
import android.os.Looper; |
import java.util.Arrays; |
@@ -23,6 +24,13 @@ abstract class CameraCapturer implements CameraVideoCapturer { |
IN_PROGRESS, // Waiting for new switched capture session to start. |
} |
+ enum MediaRecorderState { |
+ IDLE, // No media recording update (add or remove) requested. |
+ IDLE_TO_ACTIVE, // Waiting for new capture session with added MediaRecorder surface to start. |
+ ACTIVE_TO_IDLE, // Waiting for new capture session with removed MediaRecorder surface to start. |
+ ACTIVE, // MediaRecorder was successfully added to camera pipeline. |
+ } |
+ |
private static final String TAG = "CameraCapturer"; |
private final static int MAX_OPEN_CAMERA_ATTEMPTS = 3; |
private final static int OPEN_CAMERA_DELAY_MS = 500; |
@@ -37,7 +45,9 @@ abstract class CameraCapturer implements CameraVideoCapturer { |
@Override |
public void onDone(CameraSession session) { |
checkIsOnCameraThread(); |
- Logging.d(TAG, "Create session done"); |
+ Logging.d(TAG, |
+ "Create session done. Switch state: " + switchState |
+ + ". MediaRecorder state: " + mediaRecorderState); |
uiThreadHandler.removeCallbacks(openCameraTimeoutRunnable); |
synchronized (stateLock) { |
capturerObserver.onCapturerStarted(true /* success */); |
@@ -57,6 +67,20 @@ abstract class CameraCapturer implements CameraVideoCapturer { |
switchState = SwitchState.IDLE; |
switchCameraInternal(switchEventsHandler); |
} |
+ |
+ if (mediaRecorderState == MediaRecorderState.IDLE_TO_ACTIVE |
+ || mediaRecorderState == MediaRecorderState.ACTIVE_TO_IDLE) { |
+ if (mediaRecorderEventsHandler != null) { |
+ mediaRecorderEventsHandler.onMediaRecorderSuccess(); |
+ mediaRecorderEventsHandler = null; |
+ } |
+ if (mediaRecorderState == MediaRecorderState.IDLE_TO_ACTIVE) { |
+ mediaRecorderState = MediaRecorderState.ACTIVE; |
+ } else { |
+ mediaRecorderState = MediaRecorderState.IDLE; |
+ } |
+ mediaRecorder = null; |
+ } |
} |
} |
@@ -81,6 +105,15 @@ abstract class CameraCapturer implements CameraVideoCapturer { |
switchState = SwitchState.IDLE; |
} |
+ if (mediaRecorderState != MediaRecorderState.IDLE) { |
+ if (mediaRecorderEventsHandler != null) { |
+ mediaRecorderEventsHandler.onMediaRecorderError(error); |
+ mediaRecorderEventsHandler = null; |
+ } |
+ mediaRecorderState = MediaRecorderState.IDLE; |
+ mediaRecorder = null; |
+ } |
+ |
if (failureType == CameraSession.FailureType.DISCONNECTED) { |
eventsHandler.onCameraDisconnected(); |
} else { |
@@ -213,6 +246,11 @@ abstract class CameraCapturer implements CameraVideoCapturer { |
private CameraStatistics cameraStatistics; /* guarded by stateLock */ |
private boolean firstFrameObserved; /* guarded by stateLock */ |
+ // Variables used on camera thread - do not require stateLock synchronization. |
+ private MediaRecorderState mediaRecorderState = MediaRecorderState.IDLE; |
+ private MediaRecorderHandler mediaRecorderEventsHandler; |
+ private MediaRecorder mediaRecorder; |
+ |
public CameraCapturer( |
String cameraName, CameraEventsHandler eventsHandler, CameraEnumerator cameraEnumerator) { |
if (eventsHandler == null) { |
@@ -287,7 +325,7 @@ abstract class CameraCapturer implements CameraVideoCapturer { |
@Override |
public void run() { |
createCameraSession(createSessionCallback, cameraSessionEventsHandler, applicationContext, |
- surfaceHelper, cameraName, width, height, framerate); |
+ surfaceHelper, mediaRecorder, cameraName, width, height, framerate); |
} |
}, delayMs); |
} |
@@ -350,6 +388,29 @@ abstract class CameraCapturer implements CameraVideoCapturer { |
} |
@Override |
+ public void addMediaRecorderToCamera( |
+ final MediaRecorder mediaRecorder, final MediaRecorderHandler mediaRecoderEventsHandler) { |
+ Logging.d(TAG, "addMediaRecorderToCamera"); |
+ cameraThreadHandler.post(new Runnable() { |
+ @Override |
+ public void run() { |
+ updateMediaRecorderInternal(mediaRecorder, mediaRecoderEventsHandler); |
+ } |
+ }); |
+ } |
+ |
+ @Override |
+ public void removeMediaRecorderFromCamera(final MediaRecorderHandler mediaRecoderEventsHandler) { |
+ Logging.d(TAG, "removeMediaRecorderFromCamera"); |
+ cameraThreadHandler.post(new Runnable() { |
+ @Override |
+ public void run() { |
+ updateMediaRecorderInternal(null /* mediaRecorder */, mediaRecoderEventsHandler); |
+ } |
+ }); |
+ } |
+ |
+ @Override |
public boolean isScreencast() { |
return false; |
} |
@@ -370,6 +431,13 @@ abstract class CameraCapturer implements CameraVideoCapturer { |
} |
} |
+ private void reportCameraSwitchError(String error, CameraSwitchHandler switchEventsHandler) { |
+ Logging.e(TAG, error); |
+ if (switchEventsHandler != null) { |
+ switchEventsHandler.onCameraSwitchError(error); |
+ } |
+ } |
+ |
private void switchCameraInternal(final CameraSwitchHandler switchEventsHandler) { |
Logging.d(TAG, "switchCamera internal"); |
@@ -384,18 +452,15 @@ abstract class CameraCapturer implements CameraVideoCapturer { |
synchronized (stateLock) { |
if (switchState != SwitchState.IDLE) { |
- Logging.d(TAG, "switchCamera switchInProgress"); |
- if (switchEventsHandler != null) { |
- switchEventsHandler.onCameraSwitchError("Camera switch already in progress."); |
- } |
+ reportCameraSwitchError("Camera switch already in progress.", switchEventsHandler); |
+ return; |
+ } |
+ if (mediaRecorderState != MediaRecorderState.IDLE) { |
+ reportCameraSwitchError("switchCamera: media recording is active", switchEventsHandler); |
return; |
} |
- |
if (!sessionOpening && currentSession == null) { |
- Logging.d(TAG, "switchCamera: No session open"); |
- if (switchEventsHandler != null) { |
- switchEventsHandler.onCameraSwitchError("Camera is not running."); |
- } |
+ reportCameraSwitchError("switchCamera: camera is not running.", switchEventsHandler); |
return; |
} |
@@ -429,6 +494,73 @@ abstract class CameraCapturer implements CameraVideoCapturer { |
Logging.d(TAG, "switchCamera done"); |
} |
+ private void reportUpdateMediaRecorderError( |
+ String error, MediaRecorderHandler mediaRecoderEventsHandler) { |
+ checkIsOnCameraThread(); |
+ Logging.e(TAG, error); |
+ if (mediaRecoderEventsHandler != null) { |
+ mediaRecoderEventsHandler.onMediaRecorderError(error); |
+ } |
+ } |
+ |
+ private void updateMediaRecorderInternal( |
+ MediaRecorder mediaRecorder, MediaRecorderHandler mediaRecoderEventsHandler) { |
+ checkIsOnCameraThread(); |
+ boolean addMediaRecorder = (mediaRecorder != null); |
+ Logging.d(TAG, |
+ "updateMediaRecoderInternal internal. State: " + mediaRecorderState |
+ + ". Switch state: " + switchState + ". Add MediaRecorder: " + addMediaRecorder); |
+ |
+ synchronized (stateLock) { |
+ if ((addMediaRecorder && mediaRecorderState != MediaRecorderState.IDLE) |
+ || (!addMediaRecorder && mediaRecorderState != MediaRecorderState.ACTIVE)) { |
+ reportUpdateMediaRecorderError( |
+ "Incorrect state for MediaRecorder update.", mediaRecoderEventsHandler); |
+ return; |
+ } |
+ if (switchState != SwitchState.IDLE) { |
+ reportUpdateMediaRecorderError( |
+ "MediaRecorder update while camera is switching.", mediaRecoderEventsHandler); |
+ return; |
+ } |
+ if (currentSession == null) { |
+ reportUpdateMediaRecorderError( |
+ "MediaRecorder update while camera is closed.", mediaRecoderEventsHandler); |
+ return; |
+ } |
+ if (sessionOpening) { |
+ reportUpdateMediaRecorderError( |
+ "MediaRecorder update while camera is still opening.", mediaRecoderEventsHandler); |
+ return; |
+ } |
+ |
+ this.mediaRecorderEventsHandler = mediaRecoderEventsHandler; |
+ if (addMediaRecorder) { |
sakal
2017/04/26 07:34:12
nit: can be replaced with a ternary operator
AlexG
2017/04/26 21:04:10
Done.
|
+ mediaRecorderState = MediaRecorderState.IDLE_TO_ACTIVE; |
+ } else { |
+ mediaRecorderState = MediaRecorderState.ACTIVE_TO_IDLE; |
+ } |
+ this.mediaRecorder = mediaRecorder; |
+ |
+ Logging.d(TAG, "updateMediaRecoder: Stopping session"); |
+ cameraStatistics.release(); |
+ cameraStatistics = null; |
+ final CameraSession oldSession = currentSession; |
+ cameraThreadHandler.post(new Runnable() { |
+ @Override |
+ public void run() { |
+ oldSession.stop(); |
+ } |
+ }); |
+ currentSession = null; |
+ |
+ sessionOpening = true; |
+ openAttemptsRemaining = 1; |
+ createSessionInternal(0); |
+ } |
+ Logging.d(TAG, "updateMediaRecoderInternal done"); |
+ } |
+ |
private void checkIsOnCameraThread() { |
if (Thread.currentThread() != cameraThreadHandler.getLooper().getThread()) { |
Logging.e(TAG, "Check is on camera thread failed."); |
@@ -444,6 +576,6 @@ abstract class CameraCapturer implements CameraVideoCapturer { |
abstract protected void createCameraSession( |
CameraSession.CreateSessionCallback createSessionCallback, CameraSession.Events events, |
- Context applicationContext, SurfaceTextureHelper surfaceTextureHelper, String cameraName, |
- int width, int height, int framerate); |
+ Context applicationContext, SurfaceTextureHelper surfaceTextureHelper, |
+ MediaRecorder mediaRecoder, String cameraName, int width, int height, int framerate); |
} |