Skip to content

Commit 1d1e5a6

Browse files
authored
fix(liveness): LivenessCoordinator uses a coroutine scope that cancels on destroy (#275)
1 parent 5168db7 commit 1d1e5a6

File tree

3 files changed

+32
-28
lines changed

3 files changed

+32
-28
lines changed

liveness/src/main/java/com/amplifyframework/ui/liveness/camera/LivenessCoordinator.kt

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,13 @@ import java.util.Date
5454
import java.util.concurrent.Executors
5555
import kotlin.coroutines.resume
5656
import kotlin.coroutines.suspendCoroutine
57+
import kotlinx.coroutines.CoroutineName
5758
import kotlinx.coroutines.MainScope
59+
import kotlinx.coroutines.NonCancellable
60+
import kotlinx.coroutines.cancel
5861
import kotlinx.coroutines.delay
5962
import kotlinx.coroutines.launch
63+
import kotlinx.coroutines.plus
6064

6165
internal typealias OnMuxedSegment = (bytes: ByteArray, timestamp: Long) -> Unit
6266
internal 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

liveness/src/main/java/com/amplifyframework/ui/liveness/camera/LivenessVideoEncoder.kt

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ import androidx.annotation.WorkerThread
2727
import com.amplifyframework.core.Amplify
2828
import com.amplifyframework.ui.liveness.util.isKeyFrame
2929
import java.io.File
30+
import kotlin.coroutines.resume
31+
import kotlin.coroutines.suspendCoroutine
3032

3133
internal class LivenessVideoEncoder private constructor(
3234
width: Int,
@@ -212,19 +214,19 @@ internal class LivenessVideoEncoder private constructor(
212214
}
213215
}
214216

215-
fun stop(onComplete: () -> Unit) {
217+
suspend fun stop() = suspendCoroutine { continuation ->
216218
encoderHandler.post {
217219
encoding = false
218220
livenessMuxer?.stop()
219221
livenessMuxer = null
220222
if (LOGGING_ENABLED) {
221223
Log.i(TAG, "Stopping encoder")
222224
}
223-
onComplete()
225+
continuation.resume(Unit)
224226
}
225227
}
226228

227-
fun destroy() {
229+
suspend fun destroy() = suspendCoroutine { continuation ->
228230
encoderHandler.post {
229231
if (LOGGING_ENABLED) {
230232
Log.i(TAG, "Destroying encoder")
@@ -241,6 +243,8 @@ internal class LivenessVideoEncoder private constructor(
241243
// may already be stopped
242244
}
243245
encoder.release()
246+
247+
continuation.resume(Unit)
244248
}
245249
}
246250
}

samples/liveness/app/.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
/build
22
/buildNative
33
**/awsconfiguration.json
4-
**/amplifyconfiguration.json
4+
**/amplifyconfiguration**.json

0 commit comments

Comments
 (0)