1 /*
<lambda>null2  * Copyright 2020 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.integration.config
18 
19 import androidx.camera.camera2.pipe.CameraGraph
20 import androidx.camera.camera2.pipe.CameraStream
21 import androidx.camera.camera2.pipe.StreamId
22 import androidx.camera.camera2.pipe.core.Log
23 import androidx.camera.camera2.pipe.integration.adapter.CameraStateAdapter
24 import androidx.camera.camera2.pipe.integration.adapter.SessionConfigAdapter
25 import androidx.camera.camera2.pipe.integration.compat.workaround.CapturePipelineTorchCorrection
26 import androidx.camera.camera2.pipe.integration.impl.CameraInteropStateCallbackRepository
27 import androidx.camera.camera2.pipe.integration.impl.CapturePipeline
28 import androidx.camera.camera2.pipe.integration.impl.CapturePipelineImpl
29 import androidx.camera.camera2.pipe.integration.impl.SessionProcessorManager
30 import androidx.camera.camera2.pipe.integration.impl.UseCaseCamera
31 import androidx.camera.camera2.pipe.integration.impl.UseCaseCameraImpl
32 import androidx.camera.camera2.pipe.integration.impl.UseCaseCameraRequestControlImpl
33 import androidx.camera.camera2.pipe.integration.impl.UseCaseSurfaceManager
34 import androidx.camera.core.UseCase
35 import androidx.camera.core.impl.DeferrableSurface
36 import dagger.Module
37 import dagger.Provides
38 import dagger.Subcomponent
39 import java.util.concurrent.CancellationException
40 import javax.inject.Scope
41 
42 @Scope public annotation class UseCaseCameraScope
43 
44 /** Dependency bindings for building a [UseCaseCamera] */
45 @Module(
46     includes =
47         [
48             UseCaseCameraImpl.Bindings::class,
49             UseCaseCameraRequestControlImpl.Bindings::class,
50         ]
51 )
52 public abstract class UseCaseCameraModule {
53     // Used for dagger provider methods that are static.
54     public companion object {
55 
56         @UseCaseCameraScope
57         @Provides
58         public fun provideCapturePipeline(
59             capturePipelineImpl: CapturePipelineImpl,
60             capturePipelineTorchCorrection: CapturePipelineTorchCorrection
61         ): CapturePipeline {
62             if (CapturePipelineTorchCorrection.isEnabled) {
63                 return capturePipelineTorchCorrection
64             }
65 
66             return capturePipelineImpl
67         }
68     }
69 }
70 
71 /** Dagger module for binding the [UseCase]'s to the [UseCaseCamera]. */
72 @Module
73 public class UseCaseCameraConfig(
74     private val useCases: List<UseCase>,
75     private val sessionConfigAdapter: SessionConfigAdapter,
76     private val cameraStateAdapter: CameraStateAdapter,
77     private val cameraGraph: CameraGraph,
78     private val streamConfigMap: Map<CameraStream.Config, DeferrableSurface>,
79     private val sessionProcessorManager: SessionProcessorManager?,
80 ) {
81     @UseCaseCameraScope
82     @Provides
provideUseCaseListnull83     public fun provideUseCaseList(): java.util.ArrayList<UseCase> {
84         return java.util.ArrayList(useCases)
85     }
86 
87     @UseCaseCameraScope
88     @Provides
provideSessionConfigAdapternull89     public fun provideSessionConfigAdapter(): SessionConfigAdapter {
90         return sessionConfigAdapter
91     }
92 
93     @UseCaseCameraScope
94     @Provides
provideSessionProcessorManagernull95     public fun provideSessionProcessorManager(): SessionProcessorManager? {
96         return sessionProcessorManager
97     }
98 
99     /**
100      * [UseCaseGraphConfig] would store the CameraGraph and related surface map that would be used
101      * for [UseCaseCamera].
102      */
103     @UseCaseCameraScope
104     @Provides
provideUseCaseGraphConfignull105     public fun provideUseCaseGraphConfig(
106         useCaseSurfaceManager: UseCaseSurfaceManager,
107         cameraInteropStateCallbackRepository: CameraInteropStateCallbackRepository
108     ): UseCaseGraphConfig {
109         sessionConfigAdapter.getValidSessionConfigOrNull()?.let { sessionConfig ->
110             cameraInteropStateCallbackRepository.updateCallbacks(sessionConfig)
111         }
112 
113         val surfaceToStreamMap = mutableMapOf<DeferrableSurface, StreamId>()
114         streamConfigMap.forEach { (streamConfig, deferrableSurface) ->
115             cameraGraph.streams[streamConfig]?.let { surfaceToStreamMap[deferrableSurface] = it.id }
116         }
117 
118         Log.debug { "Prepare UseCaseCameraGraphConfig: $cameraGraph " }
119 
120         // Start the CameraGraph first before setting up Surfaces. Surfaces can be closed, and we
121         // will close the CameraGraph when that happens, and we cannot start a closed CameraGraph.
122         cameraGraph.start()
123 
124         if (!sessionConfigAdapter.isSessionProcessorEnabled) {
125             Log.debug { "Setting up Surfaces with UseCaseSurfaceManager" }
126             if (sessionConfigAdapter.isSessionConfigValid()) {
127                 useCaseSurfaceManager
128                     .setupAsync(
129                         cameraGraph,
130                         sessionConfigAdapter,
131                         surfaceToStreamMap,
132                     )
133                     .invokeOnCompletion { throwable ->
134                         // Only show logs for error cases, ignore CancellationException since the
135                         // task could be cancelled by UseCaseSurfaceManager#stopAsync().
136                         if (throwable != null && throwable !is CancellationException) {
137                             Log.error(throwable) { "Surface setup error!" }
138                         }
139                     }
140             } else {
141                 Log.error { "Unable to create capture session due to conflicting configurations" }
142             }
143         }
144 
145         return UseCaseGraphConfig(
146             graph = cameraGraph,
147             surfaceToStreamMap = surfaceToStreamMap,
148             cameraStateAdapter = cameraStateAdapter,
149         )
150     }
151 }
152 
153 public data class UseCaseGraphConfig(
154     val graph: CameraGraph,
155     val surfaceToStreamMap: Map<DeferrableSurface, StreamId>,
156     val cameraStateAdapter: CameraStateAdapter,
157 ) {
getStreamIdsFromSurfacesnull158     public fun getStreamIdsFromSurfaces(
159         deferrableSurfaces: Collection<DeferrableSurface>
160     ): Set<StreamId> {
161         val streamIds = mutableSetOf<StreamId>()
162         deferrableSurfaces.forEach {
163             surfaceToStreamMap[it]?.let { streamId -> streamIds.add(streamId) }
164         }
165         return streamIds
166     }
167 }
168 
169 /** Dagger subcomponent for a single [UseCaseCamera] instance. */
170 @UseCaseCameraScope
171 @Subcomponent(modules = [UseCaseCameraModule::class, UseCaseCameraConfig::class])
172 public interface UseCaseCameraComponent {
getUseCaseCameranull173     public fun getUseCaseCamera(): UseCaseCamera
174 
175     public fun getUseCaseGraphConfig(): UseCaseGraphConfig
176 
177     @Subcomponent.Builder
178     public interface Builder {
179         public fun config(config: UseCaseCameraConfig): Builder
180 
181         public fun build(): UseCaseCameraComponent
182     }
183 }
184