1 /*
<lambda>null2  * 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.graph
18 
19 import android.view.Surface
20 import androidx.annotation.GuardedBy
21 import androidx.camera.camera2.pipe.CameraController
22 import androidx.camera.camera2.pipe.CameraGraph
23 import androidx.camera.camera2.pipe.CameraSurfaceManager
24 import androidx.camera.camera2.pipe.StreamId
25 import androidx.camera.camera2.pipe.SurfaceTracker
26 import androidx.camera.camera2.pipe.core.Log
27 import androidx.camera.camera2.pipe.media.ImageSource
28 import javax.inject.Provider
29 
30 /**
31  * A SurfaceGraph tracks the current stream-to-surface mapping state for a [CameraGraph] instance.
32  *
33  * It's primary responsibility is aggregating the current stream-to-surface mapping and passing the
34  * most up to date version to the [CameraController] instance.
35  */
36 internal class SurfaceGraph(
37     private val streamGraphImpl: StreamGraphImpl,
38     private val cameraController: Provider<CameraController>,
39     private val surfaceManager: CameraSurfaceManager,
40     private val imageSources: Map<StreamId, ImageSource>
41 ) : SurfaceTracker, AutoCloseable {
42     private val lock = Any()
43 
44     /**
45      * A map of [StreamId]s to [Surface]s that stores the mapping of [Surface]s set on the streams
46      * on a [CameraGraph].
47      */
48     @GuardedBy("lock")
49     private val surfaceMap = imageSources.mapValuesTo(mutableMapOf()) { it.value.surface }
50 
51     /**
52      * A map of [Surface]s to closeables from [CameraSurfaceManager]. This keeps track of the token
53      * each [Surface] is associated with, as well as the current tokens that remain active.
54      */
55     @GuardedBy("lock")
56     private val surfaceUsageMap: MutableMap<Surface, AutoCloseable> = mutableMapOf()
57 
58     @GuardedBy("lock") private var shouldRegisterSurfaces = true
59 
60     @GuardedBy("lock") private var closed: Boolean = false
61 
62     operator fun set(streamId: StreamId, surface: Surface?) {
63         check(!imageSources.keys.contains(streamId)) {
64             "Cannot configure surface for $streamId, it is permanently assigned to " +
65                 "${imageSources[streamId]}"
66         }
67         val closeable =
68             synchronized(lock) {
69                 if (closed) {
70                     if (surface != null) {
71                         Log.warn { "Refusing to configure $streamId with $surface after close!" }
72                     }
73                     return
74                 }
75 
76                 Log.info {
77                     if (surface != null) {
78                         "Configured $streamId with $surface"
79                     } else {
80                         "Removed surface for $streamId"
81                     }
82                 }
83                 var oldSurfaceToken: AutoCloseable? = null
84 
85                 if (surface == null) {
86                     // TODO: Tell the graph processor that it should resubmit the repeating request
87                     // or reconfigure the camera2 captureSession
88                     val oldSurface = surfaceMap.remove(streamId)
89                     if (shouldRegisterSurfaces && oldSurface != null) {
90                         oldSurfaceToken = surfaceUsageMap.remove(oldSurface)
91                     }
92                 } else {
93                     val oldSurface = surfaceMap[streamId]
94                     surfaceMap[streamId] = surface
95 
96                     if (shouldRegisterSurfaces && oldSurface != surface) {
97                         check(!surfaceUsageMap.containsKey(surface)) {
98                             "Surface ($surface) is already in use!"
99                         }
100                         oldSurfaceToken = surfaceUsageMap.remove(oldSurface)
101                         val newToken = surfaceManager.registerSurface(surface)
102                         surfaceUsageMap[surface] = newToken
103                     }
104                 }
105 
106                 return@synchronized oldSurfaceToken
107             }
108         maybeUpdateSurfaces()
109         closeable?.close()
110     }
111 
112     override fun unregisterAllSurfaces() {
113         val closeables =
114             synchronized(lock) {
115                 shouldRegisterSurfaces = false
116                 surfaceUsageMap.values.toList().also { surfaceUsageMap.clear() }
117             }
118         for (closeable in closeables) {
119             closeable.close()
120         }
121     }
122 
123     override fun registerAllSurfaces() {
124         synchronized(lock) {
125             check(!closed)
126             for (surface in surfaceMap.values) {
127                 surfaceManager.registerSurface(surface).also { token ->
128                     surfaceUsageMap[surface] = token
129                 }
130             }
131             shouldRegisterSurfaces = true
132         }
133     }
134 
135     override fun close() {
136         val closeables =
137             synchronized(lock) {
138                 if (closed) {
139                     return
140                 }
141                 closed = true
142                 surfaceMap.clear()
143                 val tokensToClose = surfaceUsageMap.values.toList()
144                 surfaceUsageMap.clear()
145                 tokensToClose
146             }
147 
148         for (closeable in closeables) {
149             closeable.close()
150         }
151     }
152 
153     private fun maybeUpdateSurfaces() {
154         // Rules:
155         // 1. There must be at least one non-null surface.
156         // 2. All non-deferrable streams must have a non-null surface.
157 
158         val surfaces = buildSurfaceMap()
159         if (surfaces.isEmpty()) {
160             return
161         }
162         cameraController.get().updateSurfaceMap(surfaces)
163     }
164 
165     private fun buildSurfaceMap(): Map<StreamId, Surface> =
166         synchronized(lock) {
167             val surfaces = mutableMapOf<StreamId, Surface>()
168             for (outputConfig in streamGraphImpl.outputConfigs) {
169                 for (stream in outputConfig.streamBuilder) {
170                     val surface = surfaceMap[stream.id]
171                     if (surface == null) {
172                         if (!outputConfig.deferrable) {
173                             // If output is non-deferrable, a surface must be available or the
174                             // config is not yet valid. Exit now with an empty map.
175                             return emptyMap()
176                         }
177                     } else {
178                         surfaces[stream.id] = surface
179                     }
180                 }
181             }
182             return surfaces
183         }
184 }
185