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 package androidx.camera.camera2.pipe
17 
18 import androidx.annotation.RestrictTo
19 import androidx.camera.camera2.pipe.graph.GraphListener
20 import kotlinx.coroutines.Deferred
21 import kotlinx.coroutines.flow.Flow
22 import kotlinx.coroutines.flow.flowOf
23 
24 /** This is used to uniquely identify a specific backend implementation. */
25 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
26 @JvmInline
27 public value class CameraBackendId(public val value: String)
28 
29 /**
30  * A CameraBackend is used by [CameraPipe] to abstract out the lifecycle, state, and interactions
31  * with a set of camera devices in a standard way.
32  *
33  * Each [CameraBackend] is responsible for interacting with all of the individual cameras that are
34  * available through this backend. Since cameras often have complicated lifecycles and expensive
35  * interactions, this object serves as a low level facade that is used to manage access _across_ all
36  * cameras exposed by this backend.
37  *
38  * The lifecycle of an individual camera is managed by [CameraController]s, which may be created via
39  * [CameraBackend.createCameraController].
40  */
41 @JvmDefaultWithCompatibility
42 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
43 public interface CameraBackend {
44     public val id: CameraBackendId
45 
46     /**
47      * A flow of the list of currently openable [CameraId]s from this CameraBackend. It should
48      * continuously return a list of current cameras, and the list should be updated as camera
49      * availability changes, e.g., an external camera is plugged or unplugged. The flow should also
50      * replay the most recent value for each new subscriber.
51      */
52     public val cameraIds: Flow<List<CameraId>>
53         get() = flowOf(awaitCameraIds() ?: emptyList())
54 
55     /**
56      * Read out a list of _openable_ [CameraId]s for this backend. The backend may be able to report
57      * Metadata for non-openable cameras. However, these cameras should not appear the list of
58      * cameras returned by [getCameraIds].
59      */
getCameraIdsnull60     public suspend fun getCameraIds(): List<CameraId>? = awaitCameraIds()
61 
62     /** Thread-blocking version of [getCameraIds] for compatibility. */
63     public fun awaitCameraIds(): List<CameraId>?
64 
65     /**
66      * Read out a set of [CameraId] sets that can be operated concurrently. When multiple cameras
67      * are open, the number of configurable streams, as well as their sizes, might be considerably
68      * limited.
69      */
70     public suspend fun getConcurrentCameraIds(): Set<Set<CameraId>>? = awaitConcurrentCameraIds()
71 
72     /** Thread-blocking version of [getConcurrentCameraIds] for compatibility. */
73     public fun awaitConcurrentCameraIds(): Set<Set<CameraId>>?
74 
75     /**
76      * Retrieve [CameraMetadata] for this backend. Backends may cache the results of these calls.
77      *
78      * This call should should always succeed if the [CameraId] is in the list of ids returned by
79      * [getCameraIds]. For some backends, it may be possible to retrieve metadata for cameras that
80      * cannot be opened directly.
81      */
82     public suspend fun getCameraMetadata(cameraId: CameraId): CameraMetadata? =
83         awaitCameraMetadata(cameraId)
84 
85     /** Thread-blocking version of [getCameraMetadata] for compatibility. */
86     public fun awaitCameraMetadata(cameraId: CameraId): CameraMetadata?
87 
88     /**
89      * Stops all active [CameraController]s, which may disconnect any cached camera connection(s).
90      * This may be called on the main thread, and any long running background operations should be
91      * executed in the background. Once all connections are fully closed, the returned [Deferred]
92      * should be completed.
93      *
94      * Subsequent [CameraController]s may still be created after invoking [disconnectAllAsync], and
95      * existing [CameraController]s may attempt to restart.
96      */
97     public fun disconnectAllAsync(): Deferred<Unit>
98 
99     /**
100      * Shutdown this backend, closing active [CameraController]s, and clearing any cached resources.
101      *
102      * This method should be used carefully, as it can cause expensive reloading and re-querying of
103      * camera lists, metadata, and state. Once a backend instance has been shut down it should not
104      * be reused, and a new instance must be recreated.
105      */
106     public fun shutdownAsync(): Deferred<Unit>
107 
108     /**
109      * Creates a new [CameraController] instance that can be used to initialize and interact with a
110      * specific Camera that is available from this CameraBackend. Creating a [CameraController]
111      * should _not_ begin opening or interacting with the Camera until [CameraController.start] is
112      * called.
113      */
114     public fun createCameraController(
115         cameraContext: CameraContext,
116         graphId: CameraGraphId,
117         graphConfig: CameraGraph.Config,
118         graphListener: GraphListener,
119         streamGraph: StreamGraph,
120         surfaceTracker: SurfaceTracker,
121     ): CameraController
122 
123     /** Connects and starts the underlying camera */
124     public fun prewarm(cameraId: CameraId)
125 
126     /** Disconnects the underlying camera. */
127     public fun disconnect(cameraId: CameraId)
128 
129     /**
130      * Disconnects the underlying camera. Once the connection is closed, the returned [Deferred]
131      * should be completed.
132      */
133     public fun disconnectAsync(cameraId: CameraId): Deferred<Unit>
134 
135     /** Disconnects all active Cameras. */
136     public fun disconnectAll()
137 }
138 
139 /**
140  * Factory for creating a new [CameraBackend].
141  *
142  * [CameraBackend] instances should not be cached by the factory instance, as the lifecycle of
143  * returned instances is managed by [CameraPipe] unless the application asks [CameraPipe] to close
144  * and release previously created [CameraBackend]s.
145  */
146 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
147 public fun interface CameraBackendFactory {
148     /** Create a new [CameraBackend] instance based on the provided [CameraContext]. */
149     public fun create(cameraContext: CameraContext): CameraBackend
150 }
151 
152 /**
153  * Api for requesting and interacting with [CameraBackend] that are available in the current
154  * [CameraPipe] instance.
155  */
156 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
157 public interface CameraBackends {
158     /**
159      * This provides access to the default [CameraBackend]. Accessing this property will create the
160      * backend if it is not already created.
161      */
162     public val default: CameraBackend
163 
164     /**
165      * This provides a list of all available [CameraBackend] instances, including the default one.
166      * Accessing this set will not create or initialize [CameraBackend] instances.
167      */
168     public val allIds: Set<CameraBackendId>
169 
170     /**
171      * This provides a list of [CameraBackend] instances that have been loaded, including the
172      * default camera backend. Accessing this set will not create or initialize [CameraBackend]
173      * instances.
174      */
175     public val activeIds: Set<CameraBackendId>
176 
177     /** This instructs all backends to each shutdown their respective cameras. */
shutdownnull178     public suspend fun shutdown()
179 
180     /**
181      * Get a previously created [CameraBackend] instance, or create a new one. If the backend fails
182      * to load or is not available, this method will return null.
183      */
184     public operator fun get(backendId: CameraBackendId): CameraBackend?
185 }
186