@@ -54,9 +54,13 @@ import java.util.Date
5454import java.util.concurrent.Executors
5555import kotlin.coroutines.resume
5656import kotlin.coroutines.suspendCoroutine
57+ import kotlinx.coroutines.CoroutineName
5758import kotlinx.coroutines.MainScope
59+ import kotlinx.coroutines.NonCancellable
60+ import kotlinx.coroutines.cancel
5861import kotlinx.coroutines.delay
5962import kotlinx.coroutines.launch
63+ import kotlinx.coroutines.plus
6064
6165internal typealias OnMuxedSegment = (bytes: ByteArray , timestamp: Long ) -> Unit
6266internal typealias OnChallengeComplete = () -> Unit
@@ -82,6 +86,7 @@ internal class LivenessCoordinator(
8286
8387 private val attemptCounter = AttemptCounter ()
8488 private val analysisExecutor = Executors .newSingleThreadExecutor()
89+ private val coordinatorScope = MainScope () + CoroutineName (" LivenessCoordinator" )
8590
8691 val livenessState = LivenessState (
8792 sessionId = sessionId,
@@ -153,7 +158,7 @@ internal class LivenessCoordinator(
153158 }
154159
155160 private fun launchCamera (camera : Camera ) {
156- MainScope () .launch {
161+ coordinatorScope .launch {
157162 delay(5_000 )
158163 if (! previewTextureView.hasReceivedUpdate) {
159164 val faceLivenessException = FaceLivenessDetectionException (
@@ -163,7 +168,7 @@ internal class LivenessCoordinator(
163168 processSessionError(faceLivenessException, true )
164169 }
165170 }
166- MainScope () .launch {
171+ coordinatorScope .launch {
167172 getCameraProvider(context).apply {
168173 if (lifecycleOwner.lifecycle.currentState != Lifecycle .State .DESTROYED ) {
169174 unbindAll()
@@ -241,7 +246,8 @@ internal class LivenessCoordinator(
241246 FaceLivenessDetectionException .UnsupportedChallengeTypeException (throwable = error) to true
242247 else -> FaceLivenessDetectionException (
243248 error.message ? : " Unknown error." ,
244- error.recoverySuggestion, error
249+ error.recoverySuggestion,
250+ error
245251 ) to false
246252 }
247253 processSessionError(faceLivenessException, shouldStopLivenessSession)
@@ -250,10 +256,8 @@ internal class LivenessCoordinator(
250256 }
251257
252258 private fun unbindCamera (context : Context ) {
253- MainScope ().launch {
254- getCameraProvider(context).apply {
255- unbindAll()
256- }
259+ coordinatorScope.launch(NonCancellable ) {
260+ getCameraProvider(context).unbindAll()
257261 }
258262 }
259263
@@ -294,44 +298,40 @@ internal class LivenessCoordinator(
294298
295299 fun processLivenessCheckComplete () {
296300 livenessState.onLivenessChallengeComplete()
297- stopEncoder { livenessState.onFullChallengeComplete() }
301+ coordinatorScope.launch {
302+ encoder.stop()
303+ livenessState.onFullChallengeComplete()
304+ }
298305 }
299306
300307 private fun processFinalEventsSent () {
301308 unbindCamera(context)
302309 }
303310
304- private fun stopEncoder (onComplete : () -> Unit ) {
305- encoder.stop {
306- MainScope ().launch {
307- onComplete()
308- }
309- }
310- }
311-
312311 /* *
313312 * This is only called when onDispose is triggered from FaceLivenessDetector view.
314313 * If we begin calling destroy in other places, we should ensure we are still tracking the proper error code.
315314 */
316315 fun destroy (context : Context ) {
317316 // Destroy all resources so a new coordinator can safely be created
318- encoder.stop {
317+ coordinatorScope.launch(NonCancellable ) {
318+ encoder.stop()
319319 encoder.destroy()
320320 }
321321 val webSocketCloseCode = if (! disconnectEventReceived) WebSocketCloseCode .DISPOSED else null
322322 livenessState.onDestroy(true , webSocketCloseCode)
323323 unbindCamera(context)
324324 analysisExecutor.shutdown()
325+ coordinatorScope.cancel()
325326 }
326327
327- private suspend fun getCameraProvider (context : Context ): ProcessCameraProvider =
328- suspendCoroutine { continuation ->
329- ProcessCameraProvider .getInstance(context).also { cameraProvider ->
330- cameraProvider.addListener({
331- continuation.resume(cameraProvider.get())
332- }, ContextCompat .getMainExecutor(context))
333- }
328+ private suspend fun getCameraProvider (context : Context ): ProcessCameraProvider = suspendCoroutine { continuation ->
329+ ProcessCameraProvider .getInstance(context).also { cameraProvider ->
330+ cameraProvider.addListener({
331+ continuation.resume(cameraProvider.get())
332+ }, ContextCompat .getMainExecutor(context))
334333 }
334+ }
335335
336336 companion object {
337337 const val TARGET_FPS_MIN = 24
0 commit comments