1 /*
2  * Copyright 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package androidx.camera.camera2.pipe.internal
18 
19 import android.content.Context
20 import androidx.annotation.GuardedBy
21 import androidx.camera.camera2.pipe.CameraBackend
22 import androidx.camera.camera2.pipe.CameraBackendFactory
23 import androidx.camera.camera2.pipe.CameraBackendId
24 import androidx.camera.camera2.pipe.CameraBackends
25 import androidx.camera.camera2.pipe.CameraContext
26 import androidx.camera.camera2.pipe.config.CameraPipeContext
27 import androidx.camera.camera2.pipe.core.Threads
28 import kotlinx.coroutines.joinAll
29 
30 /** Provides an implementation for interacting with CameraBackends. */
31 internal class CameraBackendsImpl(
32     private val defaultBackendId: CameraBackendId,
33     private val cameraBackends: Map<CameraBackendId, CameraBackendFactory>,
34     @CameraPipeContext private val cameraPipeContext: Context,
35     private val threads: Threads
36 ) : CameraBackends {
37     private val lock = Any()
38 
39     @GuardedBy("lock")
40     private val activeCameraBackends = mutableMapOf<CameraBackendId, CameraBackend>()
41 
42     override val default: CameraBackend =
<lambda>null43         checkNotNull(get(defaultBackendId)) {
44             "Failed to load the default backend for $defaultBackendId! Available backends are " +
45                 "${cameraBackends.keys}"
46         }
47 
48     override val allIds: Set<CameraBackendId>
49         get() = cameraBackends.keys
50 
51     override val activeIds: Set<CameraBackendId>
<lambda>null52         get() = synchronized(lock) { activeCameraBackends.keys }
53 
shutdownnull54     override suspend fun shutdown() {
55         val shutdownJobs = activeCameraBackends.map { it.value.shutdownAsync() }
56         shutdownJobs.joinAll()
57     }
58 
getnull59     override fun get(backendId: CameraBackendId): CameraBackend? {
60         synchronized(lock) {
61             val existing = activeCameraBackends[backendId]
62             if (existing != null) return existing
63 
64             val backend =
65                 cameraBackends[backendId]?.create(
66                     CameraBackendContext(cameraPipeContext, threads, this)
67                 )
68             if (backend != null) {
69                 check(backendId == backend.id) {
70                     "Unexpected backend id! Expected $backendId but it was actually ${backend.id}"
71                 }
72                 activeCameraBackends[backendId] = backend
73             }
74             return backend
75         }
76     }
77 
78     internal class CameraBackendContext(
79         override val appContext: Context,
80         override val threads: Threads,
81         override val cameraBackends: CameraBackends
82     ) : CameraContext
83 }
84