Skip to content

Commit 527935b

Browse files
committed
fix(*): fix few issues with the preview view and camera source for preview
1 parent 6e099e6 commit 527935b

File tree

7 files changed

+96
-149
lines changed

7 files changed

+96
-149
lines changed

core/src/main/java/io/github/thibaultbee/streampack/core/elements/sources/video/camera/CameraSource.kt

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -132,16 +132,29 @@ internal class CameraSource(
132132
override suspend fun hasPreview() = controller.hasOutput(PREVIEW_NAME)
133133

134134
@RequiresPermission(Manifest.permission.CAMERA)
135-
override suspend fun setPreview(surface: Surface) {
135+
private suspend fun setPreviewUnsafe(surface: Surface) {
136136
if (isPreviewingFlow.value) {
137137
Logger.w(TAG, "Trying to set preview while previewing")
138138
}
139139
controller.addOutput(CameraSurface(PREVIEW_NAME, surface))
140140
}
141141

142+
@RequiresPermission(Manifest.permission.CAMERA)
143+
override suspend fun setPreview(surface: Surface) {
144+
withContext(defaultDispatcher) {
145+
previewMutex.withLock {
146+
setPreviewUnsafe(surface)
147+
}
148+
}
149+
}
150+
142151
@SuppressLint("MissingPermission")
143152
override suspend fun resetPreviewImpl() {
144-
controller.removeOutput(PREVIEW_NAME)
153+
withContext(defaultDispatcher) {
154+
previewMutex.withLock {
155+
controller.removeOutput(PREVIEW_NAME)
156+
}
157+
}
145158
}
146159

147160
override suspend fun getOutput() = controller.getOutput(STREAM_NAME)?.surface
@@ -192,7 +205,6 @@ internal class CameraSource(
192205
private suspend fun startPreviewUnsafe() {
193206
if (isPreviewingFlow.value) {
194207
Logger.w(TAG, "Camera is already previewing")
195-
return
196208
}
197209
controller.addTarget(PREVIEW_NAME)
198210
_isPreviewingFlow.emit(true)
@@ -214,11 +226,7 @@ internal class CameraSource(
214226
override suspend fun startPreview(previewSurface: Surface) {
215227
withContext(defaultDispatcher) {
216228
previewMutex.withLock {
217-
if (isPreviewingFlow.value) {
218-
Logger.w(TAG, "Camera is already previewing")
219-
return@withContext
220-
}
221-
setPreview(previewSurface)
229+
setPreviewUnsafe(previewSurface)
222230
startPreviewUnsafe()
223231
}
224232
}
@@ -228,7 +236,6 @@ internal class CameraSource(
228236
override suspend fun stopPreview() {
229237
withContext(defaultDispatcher) {
230238
previewMutex.withLock {
231-
Logger.d(TAG, "Stopping preview")
232239
if (!isPreviewingFlow.value) {
233240
Logger.w(TAG, "Camera is not previewing")
234241
return@withContext
@@ -253,15 +260,13 @@ internal class CameraSource(
253260
Logger.w(TAG, "Camera is already streaming")
254261
return
255262
}
256-
Logger.d(TAG, "startStream")
257263
controller.addTarget(STREAM_NAME)
258264
_isStreamingFlow.emit(true)
259265
controller.muteVibrationAndSound()
260266
}
261267

262268
@SuppressLint("MissingPermission")
263269
override suspend fun stopStream() = streamMutex.withLock {
264-
Logger.d(TAG, "stopStream")
265270
if (!isStreamingFlow.value) {
266271
Logger.w(TAG, "Camera is not streaming")
267272
return

core/src/main/java/io/github/thibaultbee/streampack/core/elements/sources/video/camera/controllers/CameraController.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ internal class CameraController(
106106
withContext(defaultDispatcher) {
107107
controllerMutex.withLock {
108108
if (outputs.values.contains(output)) {
109+
Logger.w(TAG, "Output is already added: $output")
109110
return@withContext
110111
}
111112
outputs[output.name] = output
@@ -125,8 +126,7 @@ internal class CameraController(
125126
suspend fun removeOutput(name: String) {
126127
withContext(defaultDispatcher) {
127128
controllerMutex.withLock {
128-
val needRestart = outputs.containsKey(name) && isActiveFlow.value
129-
outputs.remove(name) != null
129+
val needRestart = outputs.remove(name) != null && isActiveFlow.value
130130
if (needRestart) {
131131
restartSessionUnsafe()
132132
}

core/src/main/java/io/github/thibaultbee/streampack/core/elements/sources/video/camera/controllers/CameraDeviceController.kt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,9 +103,8 @@ internal class CameraDeviceController private constructor(
103103
return@withLock
104104
}
105105
cameraDevice.close()
106-
if (!isClosedFlow.value) {
107-
isClosedFlow.first { it }
108-
}
106+
isClosedFlow.first { it }
107+
Logger.d(TAG, "Camera $id closed")
109108
}
110109
}
111110

core/src/main/java/io/github/thibaultbee/streampack/core/elements/sources/video/camera/controllers/CameraSessionController.kt

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,13 @@ internal class CameraSessionController private constructor(
4747
private val captureSession: CameraCaptureSession,
4848
private val outputs: List<CameraSurface>,
4949
val dynamicRange: Long,
50+
val cameraIsClosedFlow: StateFlow<Boolean>,
5051
val isClosedFlow: StateFlow<Boolean>
5152
) {
5253
private val captureSessionMutex = Mutex()
5354

5455
val isClosed: Boolean
55-
get() = isClosedFlow.value
56+
get() = isClosedFlow.value || cameraIsClosedFlow.value
5657

5758
private val requestTargetMutex = Mutex()
5859

@@ -82,8 +83,6 @@ internal class CameraSessionController private constructor(
8283
/**
8384
* Whether the current capture request has a target
8485
*
85-
* The target must be in the current capture session, see [hasOutput].
86-
*
8786
* @param surface The target to check
8887
* @return true if the target is in the current capture request, false otherwise
8988
*/
@@ -96,8 +95,6 @@ internal class CameraSessionController private constructor(
9695
/**
9796
* Whether the current capture request has a target
9897
*
99-
* The target must be in the current capture session, see [hasOutput].
100-
*
10198
* @param cameraSurface The target to check
10299
* @return true if the target is in the current capture request, false otherwise
103100
*/
@@ -242,10 +239,8 @@ internal class CameraSessionController private constructor(
242239
}
243240
try {
244241
captureSession.close()
245-
246-
if (!isClosedFlow.value) {
247-
isClosedFlow.first { it }
248-
}
242+
isClosedFlow.first { it }
243+
Logger.d(TAG, "Camera session closed")
249244
} catch (t: Throwable) {
250245
Logger.w(TAG, "Error closing camera session: $t")
251246
}
@@ -422,6 +417,7 @@ internal class CameraSessionController private constructor(
422417
newCaptureSession,
423418
outputs,
424419
dynamicRange,
420+
cameraDeviceController.isClosedFlow,
425421
isClosedFlow.asStateFlow()
426422
)
427423

@@ -472,6 +468,7 @@ internal class CameraSessionController private constructor(
472468
captureSession,
473469
outputs,
474470
dynamicRange,
471+
cameraDeviceController.isClosedFlow,
475472
isClosedFlow.asStateFlow()
476473
)
477474
}

core/src/main/java/io/github/thibaultbee/streampack/core/elements/sources/video/camera/utils/CaptureRequestWithTargetsBuilder.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import android.hardware.camera2.CaptureRequest
2020
import android.hardware.camera2.CaptureRequest.Builder
2121
import android.view.Surface
2222
import io.github.thibaultbee.streampack.core.elements.sources.video.camera.controllers.CameraDeviceController
23+
import io.github.thibaultbee.streampack.core.logger.Logger
2324
import kotlinx.coroutines.sync.Mutex
2425
import kotlinx.coroutines.sync.withLock
2526

demos/camera/src/main/java/io/github/thibaultbee/streampack/app/ui/main/PreviewFragment.kt

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -193,17 +193,8 @@ class PreviewFragment : Fragment(R.layout.main_fragment) {
193193
}
194194

195195
// Wait till streamer exists to set it to the SurfaceView.
196-
preview.streamer = streamer
197-
if (PermissionManager.hasPermissions(requireContext(), Manifest.permission.CAMERA)) {
198-
lifecycleScope.launch {
199-
try {
200-
preview.startPreview()
201-
} catch (t: Throwable) {
202-
Log.e(TAG, "Error starting preview", t)
203-
}
204-
}
205-
} else {
206-
Log.e(TAG, "Camera permission not granted. Preview will not start.")
196+
lifecycleScope.launch {
197+
preview.setVideoSourceProvider(streamer)
207198
}
208199
}
209200

0 commit comments

Comments
 (0)