1 /*
<lambda>null2  * Copyright 2021 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.graph
17 
18 import androidx.camera.camera2.pipe.CameraGraph
19 import androidx.camera.camera2.pipe.CameraGraphId
20 import androidx.camera.camera2.pipe.CaptureSequenceProcessor
21 import androidx.camera.camera2.pipe.GraphState
22 import androidx.camera.camera2.pipe.GraphState.GraphStateError
23 import androidx.camera.camera2.pipe.GraphState.GraphStateStarted
24 import androidx.camera.camera2.pipe.GraphState.GraphStateStarting
25 import androidx.camera.camera2.pipe.GraphState.GraphStateStopped
26 import androidx.camera.camera2.pipe.GraphState.GraphStateStopping
27 import androidx.camera.camera2.pipe.Request
28 import androidx.camera.camera2.pipe.compat.Camera2Quirks
29 import androidx.camera.camera2.pipe.compat.CameraPipeKeys
30 import androidx.camera.camera2.pipe.config.CameraGraphScope
31 import androidx.camera.camera2.pipe.config.ForCameraGraph
32 import androidx.camera.camera2.pipe.core.Log.debug
33 import androidx.camera.camera2.pipe.core.Log.info
34 import androidx.camera.camera2.pipe.core.Threads
35 import javax.inject.Inject
36 import kotlinx.coroutines.flow.MutableStateFlow
37 import kotlinx.coroutines.flow.StateFlow
38 import kotlinx.coroutines.flow.update
39 
40 /**
41  * The [GraphProcessor] is responsible for queuing and then submitting them to a
42  * [CaptureSequenceProcessor] when it becomes available. This enables interactions to be queued up
43  * and submitted before the camera is available.
44  */
45 internal interface GraphProcessor {
46     val graphState: StateFlow<GraphState>
47 
48     /**
49      * The currently configured repeating request. Setting this value to null will attempt to call
50      * stopRepeating on the Camera.
51      */
52     var repeatingRequest: Request?
53 
54     fun submit(request: Request): Boolean
55 
56     fun submit(requests: List<Request>): Boolean
57 
58     /**
59      * This tries to submit a list of parameters based on the current repeating request. If the
60      * CameraGraph hasn't been started but a valid repeating request has already been set this
61      * method will enqueue the submission based on the repeating request.
62      *
63      * This behavior is required if users call 3A methods immediately after start. For example:
64      * ```
65      * cameraGraph.start()
66      * cameraGraph.acquireSession().use {
67      *     it.startRepeating(request)
68      *     it.lock3A(...)
69      * }
70      * ```
71      *
72      * Under this scenario, developers should reasonably expect things to work, and therefore the
73      * implementation handles this on a best-effort basis for the developer. Please read b/263211462
74      * for more context.
75      *
76      * This method will throw a checked exception if no repeating request has been configured.
77      */
78     fun trigger(parameters: Map<*, Any?>): Boolean
79 
80     /** Update [CameraGraph.Parameters] changes to current repeating request. */
81     fun updateGraphParameters(parameters: Map<*, Any?>)
82 
83     /** Update [CameraGraph.Parameters] changes to current repeating request. */
84     fun update3AParameters(parameters: Map<*, Any?>)
85 
86     /**
87      * Indicates that internal state may have changed, and that the repeating request may need to be
88      * re-issued.
89      */
90     fun invalidate()
91 
92     /**
93      * Abort all submitted requests that have not yet been submitted, as well as asking the
94      * [CaptureSequenceProcessor] to abort any submitted requests, which may or may not succeed.
95      */
96     fun abort()
97 
98     /**
99      * Closing the [GraphProcessor] will abort all queued requests. Any requests submitted after the
100      * [GraphProcessor] is closed will immediately be aborted.
101      */
102     fun close()
103 }
104 
105 /** The graph processor handles *cross-session* state, such as the most recent repeating request. */
106 @CameraGraphScope
107 internal class GraphProcessorImpl
108 @Inject
109 constructor(
110     threads: Threads,
111     private val cameraGraphId: CameraGraphId,
112     private val cameraGraphConfig: CameraGraph.Config,
113     graphListener3A: Listener3A,
114     @ForCameraGraph graphListeners: List<@JvmSuppressWildcards Request.Listener>,
115 ) : GraphProcessor, GraphListener {
116     private val graphLoop: GraphLoop
117 
118     init {
119         val defaultParameters = cameraGraphConfig.defaultParameters
120         val requiredParameters = cameraGraphConfig.requiredParameters
121         val ignore3AState =
122             (defaultParameters[CameraPipeKeys.ignore3ARequiredParameters] == true) ||
123                 (requiredParameters[CameraPipeKeys.ignore3ARequiredParameters] == true)
124 
125         if (ignore3AState) {
<lambda>null126             info {
127                 "${CameraPipeKeys.ignore3ARequiredParameters} is set to true, " +
128                     "ignoring GraphState3A parameters."
129             }
130         }
131 
132         val requestsUntilActive =
133             Camera2Quirks.getRepeatingRequestFrameCountForCapture(cameraGraphConfig.flags)
134 
135         val captureLimiter =
136             if (requestsUntilActive != 0) {
137                 CaptureLimiter(requestsUntilActive.toLong())
138             } else {
139                 null
140             }
141 
142         graphLoop =
143             GraphLoop(
144                 cameraGraphId = cameraGraphId,
145                 defaultParameters = defaultParameters,
146                 requiredParameters = requiredParameters,
147                 graphListeners = graphListeners + listOfNotNull(captureLimiter),
148                 listeners = listOfNotNull(graphListener3A, captureLimiter),
149                 shutdownScope = threads.globalScope,
150                 dispatcher = threads.lightweightDispatcher
151             )
152 
153         captureLimiter?.graphLoop = graphLoop
154     }
155 
156     private val _graphState = MutableStateFlow<GraphState>(GraphStateStopped)
157     override val graphState: StateFlow<GraphState>
158         get() = _graphState
159 
160     override var repeatingRequest: Request?
161         get() = graphLoop.repeatingRequest
162         set(value) {
163             graphLoop.repeatingRequest = value
164         }
165 
onGraphStartingnull166     override fun onGraphStarting() {
167         debug { "$this onGraphStarting" }
168         _graphState.value = GraphStateStarting
169     }
170 
onGraphStartednull171     override fun onGraphStarted(requestProcessor: GraphRequestProcessor) {
172         debug { "$this onGraphStarted" }
173         _graphState.value = GraphStateStarted
174         graphLoop.requestProcessor = requestProcessor
175     }
176 
onGraphStoppingnull177     override fun onGraphStopping() {
178         debug { "$this onGraphStopping" }
179         _graphState.value = GraphStateStopping
180     }
181 
onGraphStoppednull182     override fun onGraphStopped(requestProcessor: GraphRequestProcessor?) {
183         debug { "$this onGraphStopped" }
184         _graphState.value = GraphStateStopped
185         graphLoop.requestProcessor = null
186     }
187 
onGraphModifiednull188     override fun onGraphModified(requestProcessor: GraphRequestProcessor) {
189         debug { "$this onGraphModified" }
190         graphLoop.invalidate()
191     }
192 
onGraphErrornull193     override fun onGraphError(graphStateError: GraphStateError) {
194         debug { "$this onGraphError($graphStateError)" }
195         _graphState.update { graphState ->
196             if (graphState is GraphStateStopping || graphState is GraphStateStopped) {
197                 GraphStateStopped
198             } else {
199                 graphStateError
200             }
201         }
202     }
203 
submitnull204     override fun submit(request: Request): Boolean = submit(listOf(request))
205 
206     override fun submit(requests: List<Request>): Boolean {
207         val reprocessingRequest = requests.firstOrNull { it.inputRequest != null }
208         if (reprocessingRequest != null) {
209             checkNotNull(cameraGraphConfig.input) {
210                 "Cannot submit $reprocessingRequest with input request " +
211                     "${reprocessingRequest.inputRequest} to $this because CameraGraph was not " +
212                     "configured to support reprocessing"
213             }
214         }
215 
216         return graphLoop.submit(requests)
217     }
218 
219     /**
220      * Submit a one time request to the camera using the most recent repeating request.
221      *
222      * If a repeating request is not currently set, this method will return false and fail.
223      */
triggernull224     override fun trigger(parameters: Map<*, Any?>): Boolean = graphLoop.trigger(parameters)
225 
226     override fun updateGraphParameters(parameters: Map<*, Any?>) {
227         graphLoop.graphParameters = parameters
228     }
229 
update3AParametersnull230     override fun update3AParameters(parameters: Map<*, Any?>) {
231         graphLoop.graph3AParameters = parameters
232     }
233 
invalidatenull234     override fun invalidate() {
235         graphLoop.invalidate()
236     }
237 
abortnull238     override fun abort() {
239         graphLoop.abort()
240     }
241 
closenull242     override fun close() {
243         graphLoop.close()
244     }
245 
toStringnull246     override fun toString(): String = "GraphProcessor(cameraGraph: $cameraGraphId)"
247 }
248