Я реализовал Camera2 API. Это работает хорошо на большинстве устройств, но у меня есть несколько сообщений от пользователей, что они не позволяют им делать снимки. Я получил журналы от этих пользователей. Все они получают ошибку ERROR_CAMERA_DEVICE в методе onError CameraDevice.StateCallback, который я передаю при открытии фронтальной камеры. Эта ошибка говорит о том, что с камерой произошла неустранимая ошибка, и ее необходимо повторно открыть для использования. https://developer.android.com/reference/android/hardware/camera2/CameraDevice.StateCallback#ERROR_CAMERA_DEVICE
Я написал код, который снова открывает камеру, но каждый раз ошибка повторяется.
Кто-нибудь знает, почему это может происходить и как я могу исправить это?
Вот некоторые из соответствующих реализаций:
override fun open(): Boolean {
if (hasCamera) {
try {
val id = manager.cameraIdList[cameraId]
val characteristics = manager.getCameraCharacteristics(id)
val map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
map?.let {
imageDimension = map.getOutputSizes(SurfaceTexture::class.java)[0]
}
if (!isOpen) {
manager.openCamera(id, object : CameraDevice.StateCallback() {
override fun onOpened(camera: CameraDevice) {
isOpen = true
openCount++
this.cameraDevice = camera
startPreview(null)
}
override fun onDisconnected(camera: CameraDevice) {
this.cameraDevice = camera
close()
}
override fun onError(camera: CameraDevice, error: Int) {
this.cameraDevice = camera
close()
this.cameraDevice = null
if (openCount < 10) {
openCount++
open()
}
}
}, null)
}
} catch (e: Exception) {
Timber.e("open: $e")
} catch (e: SecurityException) {
Timber.e("open: $e")
}
}
return hasCamera
}
override fun startPreview(startPreviewFailCallback: (() -> Unit)?) {
cameraDevice?.let { cameraDevice ->
try {
val texture = textureView.surfaceTexture ?: return
imageDimension?.let {
texture.setDefaultBufferSize(it.width, it.height)
} ?: kotlin.run {
texture.setDefaultBufferSize(640, 480)
}
surface = Surface(texture)
captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
captureRequestBuilder.addTarget(surface)
val range = getRange()
range?.let {
captureRequestBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, getRange())
}
cameraDevice.createCaptureSession(Arrays.asList(surface), object : CameraCaptureSession.StateCallback() {
override fun onConfigured(@NonNull cameraCaptureSession: CameraCaptureSession) {
//The camera is already closed
if (null == cameraDevice) {
return
}
// When the session is ready, we start displaying the preview.
this@CameraNew.cameraCaptureSession = cameraCaptureSession
updatePreview()
}
override fun onConfigureFailed(@NonNull cameraCaptureSession: CameraCaptureSession) {
this.cameraCaptureSession = cameraCaptureSession
}
}, null)
} catch (e: CameraAccessException) {
e.printStackTrace()
Timber.e("startPreview: $e")
} catch (e: SecurityException) {
Timber.e("startPreview: $e")
}
} ?: kotlin.run {
startPreviewFailCallback?.let {
it.invoke()
}
}
}
private fun updatePreview() {
if (null == cameraDevice) {
return
}
captureRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO)
try {
cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(), null, backgroundHandler)
} catch (e: CameraAccessException) {
e.printStackTrace()
Timber.e("updatePreview: $e")
} catch (e: IllegalStateException) {
Timber.e("updatePreview: $e")
}
}