fix: Fix blackscreen issues and lifecycle when closing Camera (#2339)
* fix: Fix Blackscreen by deterministically destroying session if `isActive=false` * Re-open Camera if session died * Simplify Camera * Disconnect is optional, block when resetting state * fix: Log in `configure { ... }` * fix: Make concurrent configure safe * fix: Don't resize preview * fix: Use current `CameraConfiguration` * Don't start if no outputs are available * Only mount with preview outputs * Update CameraSession.kt * Update PreviewView.kt * Better logging * Update CameraSession.kt * Extract * fix: Rebuild entire session if `isActive` changed * isActive safe * Start session at 1 * Create ActiveCameraDevice.kt * interrupts * chore: Freeze `frame` in `useFrameProcessor` * Revert "chore: Freeze `frame` in `useFrameProcessor`" This reverts commit dff93d506e29a791d8dea8842b880ab5c892211e. * chore: Better logging * fix: Move HDR to `video`/`photo` config * fix: Fix hdr usage * fix: Ignore any updates after destroying Camera * fix: Fix video HDR * chore: Format code * fix: Check Camera permission * Remove unneeded error * Update CameraSession.kt * Update CameraPage.tsx * Delete OutputConfiguration.toDebugString.kt * Update CameraSession.kt
This commit is contained in:
@@ -4,22 +4,22 @@ import android.hardware.camera2.CameraCaptureSession
|
||||
import android.hardware.camera2.CameraCharacteristics
|
||||
import android.hardware.camera2.CameraDevice
|
||||
import android.hardware.camera2.CameraManager
|
||||
import android.hardware.camera2.params.OutputConfiguration
|
||||
import android.hardware.camera2.params.SessionConfiguration
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import com.mrousavy.camera.core.CameraQueues
|
||||
import com.mrousavy.camera.core.CameraSessionCannotBeConfiguredError
|
||||
import com.mrousavy.camera.core.outputs.SurfaceOutput
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.resumeWithException
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
|
||||
private const val TAG = "CreateCaptureSession"
|
||||
private var sessionId = 1000
|
||||
private var sessionId = 1
|
||||
|
||||
suspend fun CameraDevice.createCaptureSession(
|
||||
cameraManager: CameraManager,
|
||||
outputs: List<OutputConfiguration>,
|
||||
outputs: List<SurfaceOutput>,
|
||||
onClosed: (session: CameraCaptureSession) -> Unit,
|
||||
queue: CameraQueues.CameraQueue
|
||||
): CameraCaptureSession =
|
||||
@@ -29,34 +29,35 @@ suspend fun CameraDevice.createCaptureSession(
|
||||
val sessionId = sessionId++
|
||||
Log.i(
|
||||
TAG,
|
||||
"Camera $id: Creating Capture Session #$sessionId... " +
|
||||
"Hardware Level: $hardwareLevel} | Outputs: $outputs"
|
||||
"Camera #$id: Creating Capture Session #$sessionId... " +
|
||||
"(Hardware Level: $hardwareLevel | Outputs: [${outputs.joinToString()}])"
|
||||
)
|
||||
|
||||
val callback = object : CameraCaptureSession.StateCallback() {
|
||||
override fun onConfigured(session: CameraCaptureSession) {
|
||||
Log.i(TAG, "Camera $id: Capture Session #$sessionId configured!")
|
||||
Log.i(TAG, "Camera #$id: Successfully created CameraCaptureSession #$sessionId!")
|
||||
continuation.resume(session)
|
||||
}
|
||||
|
||||
override fun onConfigureFailed(session: CameraCaptureSession) {
|
||||
Log.e(TAG, "Camera $id: Failed to configure Capture Session #$sessionId!")
|
||||
Log.e(TAG, "Camera #$id: Failed to create CameraCaptureSession #$sessionId!")
|
||||
continuation.resumeWithException(CameraSessionCannotBeConfiguredError(id))
|
||||
}
|
||||
|
||||
override fun onClosed(session: CameraCaptureSession) {
|
||||
Log.i(TAG, "Camera #$id: CameraCaptureSession #$sessionId has been closed.")
|
||||
super.onClosed(session)
|
||||
Log.i(TAG, "Camera $id: Capture Session #$sessionId closed!")
|
||||
onClosed(session)
|
||||
}
|
||||
}
|
||||
|
||||
val configurations = outputs.map { it.toOutputConfiguration(characteristics) }
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
Log.i(TAG, "Using new API (>=28)")
|
||||
val config = SessionConfiguration(SessionConfiguration.SESSION_REGULAR, outputs, queue.executor, callback)
|
||||
val config = SessionConfiguration(SessionConfiguration.SESSION_REGULAR, configurations, queue.executor, callback)
|
||||
this.createCaptureSession(config)
|
||||
} else {
|
||||
Log.i(TAG, "Using legacy API (<28)")
|
||||
this.createCaptureSessionByOutputConfigurations(outputs, callback, queue.handler)
|
||||
this.createCaptureSessionByOutputConfigurations(configurations, callback, queue.handler)
|
||||
}
|
||||
}
|
||||
|
@@ -18,30 +18,30 @@ private const val TAG = "CameraManager"
|
||||
@SuppressLint("MissingPermission")
|
||||
suspend fun CameraManager.openCamera(
|
||||
cameraId: String,
|
||||
onDisconnected: (camera: CameraDevice, reason: Throwable) -> Unit,
|
||||
onDisconnected: (camera: CameraDevice, error: Throwable?) -> Unit,
|
||||
queue: CameraQueues.CameraQueue
|
||||
): CameraDevice =
|
||||
suspendCancellableCoroutine { continuation ->
|
||||
Log.i(TAG, "Camera $cameraId: Opening...")
|
||||
Log.i(TAG, "Camera #$cameraId: Opening...")
|
||||
|
||||
val callback = object : CameraDevice.StateCallback() {
|
||||
override fun onOpened(camera: CameraDevice) {
|
||||
Log.i(TAG, "Camera $cameraId: Opened!")
|
||||
Log.i(TAG, "Camera #$cameraId: Opened!")
|
||||
continuation.resume(camera)
|
||||
}
|
||||
|
||||
override fun onDisconnected(camera: CameraDevice) {
|
||||
Log.i(TAG, "Camera $cameraId: Disconnected!")
|
||||
Log.i(TAG, "Camera #$cameraId: Disconnected!")
|
||||
if (continuation.isActive) {
|
||||
continuation.resumeWithException(CameraCannotBeOpenedError(cameraId, CameraDeviceError.DISCONNECTED))
|
||||
} else {
|
||||
onDisconnected(camera, CameraDisconnectedError(cameraId, CameraDeviceError.DISCONNECTED))
|
||||
onDisconnected(camera, null)
|
||||
}
|
||||
camera.close()
|
||||
}
|
||||
|
||||
override fun onError(camera: CameraDevice, errorCode: Int) {
|
||||
Log.e(TAG, "Camera $cameraId: Error! $errorCode")
|
||||
Log.e(TAG, "Camera #$cameraId: Error! $errorCode")
|
||||
val error = CameraDeviceError.fromCameraDeviceError(errorCode)
|
||||
if (continuation.isActive) {
|
||||
continuation.resumeWithException(CameraCannotBeOpenedError(cameraId, error))
|
||||
|
Reference in New Issue
Block a user