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