Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Torch #145

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open

Torch #145

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public Camera1Capturer(
protected void createCameraSession(CameraSession.CreateSessionCallback createSessionCallback,
CameraSession.Events events, Context applicationContext,
SurfaceTextureHelper surfaceTextureHelper, String cameraName, int width, int height,
int framerate) {
int framerate, boolean torch) {
Camera1Session.create(createSessionCallback, events, captureToTexture, applicationContext,
surfaceTextureHelper, cameraName, width, height, framerate);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ public boolean isBackFacing(String deviceName) {
return info != null && info.facing == android.hardware.Camera.CameraInfo.CAMERA_FACING_BACK;
}

@Override
public boolean hasTorch(String deviceName) {
return false; //TODO, old API unsupported
}

@Override
public List<CaptureFormat> getSupportedFormats(String deviceName) {
return getSupportedFormats(getCameraIndex(deviceName));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ public Camera2Capturer(Context context, String cameraName, CameraEventsHandler e
protected void createCameraSession(CameraSession.CreateSessionCallback createSessionCallback,
CameraSession.Events events, Context applicationContext,
SurfaceTextureHelper surfaceTextureHelper, String cameraName, int width, int height,
int framerate) {
int framerate, boolean torch) {
Camera2Session.create(createSessionCallback, events, applicationContext, cameraManager,
surfaceTextureHelper, cameraName, width, height, framerate);
surfaceTextureHelper, cameraName, width, height, framerate, torch);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ public boolean isFrontFacing(String deviceName) {
== CameraMetadata.LENS_FACING_FRONT;
}

@Override
public boolean hasTorch(String deviceName) {
CameraCharacteristics characteristics = getCameraCharacteristics(deviceName);
return characteristics != null && characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
}

@Override
public boolean isBackFacing(String deviceName) {
CameraCharacteristics characteristics = getCameraCharacteristics(deviceName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ private static enum SessionState { RUNNING, STOPPED }
private final int height;
private final int framerate;

private final boolean torch;

// Initialized at start
private CameraCharacteristics cameraCharacteristics;
private int cameraOrientation;
Expand Down Expand Up @@ -167,6 +169,10 @@ public void onConfigured(CameraCaptureSession session) {
captureRequestBuilder.set(
CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
captureRequestBuilder.set(CaptureRequest.CONTROL_AE_LOCK, false);
if (Camera2Session.this.torch) {
captureRequestBuilder.set(CaptureRequest.FLASH_MODE, 2);
}

chooseStabilizationMode(captureRequestBuilder);
chooseFocusMode(captureRequestBuilder);

Expand Down Expand Up @@ -270,14 +276,14 @@ public void onCaptureFailed(
public static void create(CreateSessionCallback callback, Events events,
Context applicationContext, CameraManager cameraManager,
SurfaceTextureHelper surfaceTextureHelper, String cameraId, int width, int height,
int framerate) {
int framerate, boolean torch) {
new Camera2Session(callback, events, applicationContext, cameraManager, surfaceTextureHelper,
cameraId, width, height, framerate);
cameraId, width, height, framerate, torch);
}

private Camera2Session(CreateSessionCallback callback, Events events, Context applicationContext,
CameraManager cameraManager, SurfaceTextureHelper surfaceTextureHelper, String cameraId,
int width, int height, int framerate) {
int width, int height, int framerate, boolean torch) {
Logging.d(TAG, "Create new camera2 session on camera " + cameraId);

constructionTimeNs = System.nanoTime();
Expand All @@ -292,6 +298,7 @@ private Camera2Session(CreateSessionCallback callback, Events events, Context ap
this.width = width;
this.height = height;
this.framerate = framerate;
this.torch = torch;

start();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ enum SwitchState {
@Override
public void onDone(CameraSession session) {
checkIsOnCameraThread();
Logging.d(TAG, "Create session done. Switch state: " + switchState);
Logging.d(TAG, "Create session done. Switch state: " + switchState
+ ". Torch state: " + torchState);
uiThreadHandler.removeCallbacks(openCameraTimeoutRunnable);
synchronized (stateLock) {
capturerObserver.onCapturerStarted(true /* success */);
Expand All @@ -62,6 +63,17 @@ public void onDone(CameraSession session) {
switchState = SwitchState.IDLE;
switchCameraInternal(switchEventsHandler, selectedCameraName);
}

if (CameraCapturer.this.torchState == CameraCapturer.SwitchState.IN_PROGRESS) {
CameraCapturer.this.torchState = CameraCapturer.SwitchState.IDLE;
if (CameraCapturer.this.torchHandler != null) {
CameraCapturer.this.torchHandler.onTorchSuccess();
CameraCapturer.this.torchHandler = null;
}
} else if (CameraCapturer.this.torchState == CameraCapturer.SwitchState.PENDING) {
CameraCapturer.this.torchState = CameraCapturer.SwitchState.IDLE;
CameraCapturer.this.torchInternal(!CameraCapturer.this.torch, CameraCapturer.this.torchHandler);
}
}
}

Expand Down Expand Up @@ -188,13 +200,21 @@ public void run() {
@Nullable private CameraSession currentSession; /* guarded by stateLock */
private String cameraName; /* guarded by stateLock */
private String pendingCameraName; /* guarded by stateLock */

private boolean torch; /* guarded by stateLock */
private int width; /* guarded by stateLock */
private int height; /* guarded by stateLock */
private int framerate; /* guarded by stateLock */
private int openAttemptsRemaining; /* guarded by stateLock */
private SwitchState switchState = SwitchState.IDLE; /* guarded by stateLock */
@Nullable private CameraSwitchHandler switchEventsHandler; /* guarded by stateLock */
// Valid from onDone call until stopCapture, otherwise null.

private SwitchState torchState; /* guarded by stateLock */

@Nullable
private CameraVideoCapturer.TorchHandler torchHandler; /* guarded by stateLock */

@Nullable private CameraStatistics cameraStatistics; /* guarded by stateLock */
private boolean firstFrameObserved; /* guarded by stateLock */

Expand All @@ -218,6 +238,7 @@ public void onCameraClosed() {}
}

this.eventsHandler = eventsHandler;
this.torchState = SwitchState.IDLE;
this.cameraEnumerator = cameraEnumerator;
this.cameraName = cameraName;
List<String> deviceNames = Arrays.asList(cameraEnumerator.getDeviceNames());
Expand Down Expand Up @@ -270,7 +291,7 @@ private void createSessionInternal(int delayMs) {
@Override
public void run() {
createCameraSession(createSessionCallback, cameraSessionEventsHandler, applicationContext,
surfaceHelper, cameraName, width, height, framerate);
surfaceHelper, cameraName, width, height, framerate, torch);
}
}, delayMs);
}
Expand Down Expand Up @@ -347,6 +368,16 @@ public void run() {
});
}

@Override
public void torch(final boolean state, final CameraVideoCapturer.TorchHandler torchHandler) {
Logging.d("CameraCapturer", "torch");
this.cameraThreadHandler.post(new Runnable() {
public void run() {
CameraCapturer.this.torchInternal(state, torchHandler);
}
});
}

@Override
public void switchCamera(final CameraSwitchHandler switchEventsHandler, final String cameraName) {
Logging.d(TAG, "switchCamera");
Expand Down Expand Up @@ -387,6 +418,13 @@ private void reportCameraSwitchError(
}
}

private void reportTorchError(String error, @Nullable CameraVideoCapturer.TorchHandler torchHandler) {
Logging.e("CameraCapturer", error);
if (torchHandler != null) {
torchHandler.onTorchError(error);
}
}

private void switchCameraInternal(
@Nullable final CameraSwitchHandler switchEventsHandler, final String selectedCameraName) {
Logging.d(TAG, "switchCamera internal");
Expand All @@ -403,6 +441,10 @@ private void switchCameraInternal(
reportCameraSwitchError("Camera switch already in progress.", switchEventsHandler);
return;
}
if (this.torchState != CameraCapturer.SwitchState.IDLE) {
this.reportCameraSwitchError("Torch change in progress.", switchEventsHandler);
return;
}
if (!sessionOpening && currentSession == null) {
reportCameraSwitchError("switchCamera: camera is not running.", switchEventsHandler);
return;
Expand Down Expand Up @@ -438,6 +480,57 @@ public void run() {
Logging.d(TAG, "switchCamera done");
}

private void torchInternal(boolean state, CameraVideoCapturer.TorchHandler torchHandler) {
Logging.d("CameraCapturer", "torch internal");
if (!this.cameraEnumerator.hasTorch(this.cameraName)) {
if (torchHandler != null) {
torchHandler.onTorchUnsupported();
}

} else {
synchronized(this.stateLock) {
if (this.switchState != CameraCapturer.SwitchState.IDLE) {
this.reportTorchError("Camera switch in progress.", torchHandler);
return;
}

if (this.torchState != CameraCapturer.SwitchState.IDLE) {
this.reportTorchError("Torch change already in progress.", torchHandler);
return;
}

if (!this.sessionOpening && this.currentSession == null) {
this.reportTorchError("torch: camera is not running.", torchHandler);
return;
}

this.torchHandler = torchHandler;
if (this.sessionOpening) {
this.torchState = CameraCapturer.SwitchState.PENDING;
return;
}

this.torchState = CameraCapturer.SwitchState.IN_PROGRESS;
Logging.d("CameraCapturer", "torch: Stopping session");
this.cameraStatistics.release();
this.cameraStatistics = null;
final CameraSession oldSession = this.currentSession;
this.cameraThreadHandler.post(new Runnable() {
public void run() {
oldSession.stop();
}
});
this.currentSession = null;
this.torch = state;
this.sessionOpening = true;
this.openAttemptsRemaining = 1;
this.createSessionInternal(0);
}

Logging.d("CameraCapturer", "torch done");
}
}

private void checkIsOnCameraThread() {
if (Thread.currentThread() != cameraThreadHandler.getLooper().getThread()) {
Logging.e(TAG, "Check is on camera thread failed.");
Expand All @@ -454,5 +547,5 @@ protected String getCameraName() {
abstract protected void createCameraSession(
CameraSession.CreateSessionCallback createSessionCallback, CameraSession.Events events,
Context applicationContext, SurfaceTextureHelper surfaceTextureHelper, String cameraName,
int width, int height, int framerate);
int width, int height, int framerate, boolean torch);
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public interface CameraEnumerator {
public String[] getDeviceNames();
public boolean isFrontFacing(String deviceName);
public boolean isBackFacing(String deviceName);
public boolean hasTorch(String deviceName);
public List<CaptureFormat> getSupportedFormats(String deviceName);

public CameraVideoCapturer createCapturer(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,18 @@ public interface CameraEventsHandler {
void onCameraClosed();
}

/**
* Camera torch handler - one of these functions are invoked with the result of torch().
* The callback may be called on an arbitrary thread.
*/
public interface TorchHandler {
void onTorchSuccess();

void onTorchError(String var1);

void onTorchUnsupported();
}

/**
* Camera switch handler - one of these functions are invoked with the result of switchCamera().
* The callback may be called on an arbitrary thread.
Expand All @@ -67,6 +79,11 @@ public interface CameraSwitchHandler {
*/
void switchCamera(CameraSwitchHandler switchEventsHandler, String cameraName);

/**
* Switch torch on or off
*/
public void torch(final boolean state, final CameraVideoCapturer.TorchHandler torchHandler);

/**
* MediaRecorder add/remove handler - one of these functions are invoked with the result of
* addMediaRecorderToCamera() or removeMediaRecorderFromCamera calls.
Expand Down
Loading