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