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 
17 package androidx.camera.camera2.pipe.integration.impl
18 
19 import android.hardware.camera2.CameraCaptureSession
20 import android.hardware.camera2.CameraDevice
21 import android.os.Build
22 import android.view.Surface
23 import androidx.annotation.RequiresApi
24 import androidx.camera.camera2.pipe.core.Log
25 import androidx.camera.core.impl.SessionConfig
26 import kotlinx.atomicfu.AtomicRef
27 import kotlinx.atomicfu.atomic
28 
29 /**
30  * A application-level single-instance repository for Camera Interop callbacks. It supplies
31  * camera-pipe with internal callbacks on CameraX initialization. During runtime, before a camera
32  * graph is created, CameraX updates these internal callbacks with Camera Interop callbacks so that
33  * they may be triggered in camera-pipe.
34  */
35 public class CameraInteropStateCallbackRepository {
36 
37     private val _deviceStateCallback = CameraInteropDeviceStateCallback()
38     private val _sessionStateCallback = CameraInteropSessionStateCallback()
39 
40     /**
41      * Called after merging all sessionConfigs from CameraX useCases and UseCases supplied by Camera
42      * Interop. If the Interop has any callbacks, they would be contained in the sessionConfig.
43      * CameraInteropStateCallbackRepository would store these callbacks to be triggered by
44      * camera-pipe.
45      *
46      * @param sessionConfig the final merged sessionConfig used to create camera graph
47      */
updateCallbacksnull48     public fun updateCallbacks(sessionConfig: SessionConfig) {
49         _deviceStateCallback.updateCallbacks(sessionConfig)
50         _sessionStateCallback.updateCallbacks(sessionConfig)
51     }
52 
53     public val deviceStateCallback: CameraInteropDeviceStateCallback
54         get() = _deviceStateCallback
55 
56     public val sessionStateCallback: CameraInteropSessionStateCallback
57         get() = _sessionStateCallback
58 
59     public class CameraInteropDeviceStateCallback : CameraDevice.StateCallback() {
60 
61         private var callbacks: AtomicRef<List<CameraDevice.StateCallback>> = atomic(listOf())
62 
updateCallbacksnull63         internal fun updateCallbacks(sessionConfig: SessionConfig) {
64             callbacks.value = sessionConfig.deviceStateCallbacks.toList()
65         }
66 
onOpenednull67         override fun onOpened(cameraDevice: CameraDevice) {
68             for (callback in callbacks.value) {
69                 callback.onOpened(cameraDevice)
70             }
71         }
72 
onClosednull73         override fun onClosed(cameraDevice: CameraDevice) {
74             for (callback in callbacks.value) {
75                 callback.onClosed(cameraDevice)
76             }
77         }
78 
onDisconnectednull79         override fun onDisconnected(cameraDevice: CameraDevice) {
80             for (callback in callbacks.value) {
81                 callback.onDisconnected(cameraDevice)
82             }
83         }
84 
onErrornull85         override fun onError(cameraDevice: CameraDevice, errorCode: Int) {
86             for (callback in callbacks.value) {
87                 callback.onError(cameraDevice, errorCode)
88             }
89         }
90     }
91 
92     public class CameraInteropSessionStateCallback : CameraCaptureSession.StateCallback() {
93 
94         private var callbacks: AtomicRef<List<CameraCaptureSession.StateCallback>> =
95             atomic(listOf())
96 
updateCallbacksnull97         internal fun updateCallbacks(sessionConfig: SessionConfig) {
98             callbacks.value = sessionConfig.sessionStateCallbacks.toList()
99         }
100 
onConfigurednull101         override fun onConfigured(session: CameraCaptureSession) {
102             for (callback in callbacks.value) {
103                 callback.onConfigured(session)
104             }
105         }
106 
onConfigureFailednull107         override fun onConfigureFailed(session: CameraCaptureSession) {
108             for (callback in callbacks.value) {
109                 callback.onConfigureFailed(session)
110             }
111         }
112 
onReadynull113         override fun onReady(session: CameraCaptureSession) {
114             for (callback in callbacks.value) {
115                 callback.onReady(session)
116             }
117         }
118 
onActivenull119         override fun onActive(session: CameraCaptureSession) {
120             for (callback in callbacks.value) {
121                 callback.onActive(session)
122             }
123         }
124 
onCaptureQueueEmptynull125         override fun onCaptureQueueEmpty(session: CameraCaptureSession) {
126             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
127                 Api26CompatImpl.onCaptureQueueEmpty(session, callbacks)
128             } else {
129                 Log.error { "onCaptureQueueEmpty called for unsupported OS version." }
130             }
131         }
132 
onClosednull133         override fun onClosed(session: CameraCaptureSession) {
134             for (callback in callbacks.value) {
135                 callback.onClosed(session)
136             }
137         }
138 
onSurfacePreparednull139         override fun onSurfacePrepared(session: CameraCaptureSession, surface: Surface) {
140             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
141                 Api23CompatImpl.onSurfacePrepared(session, surface, callbacks)
142             } else {
143                 Log.error { "onSurfacePrepared called for unsupported OS version." }
144             }
145         }
146 
147         @RequiresApi(Build.VERSION_CODES.M)
148         private object Api23CompatImpl {
149             @JvmStatic
onSurfacePreparednull150             fun onSurfacePrepared(
151                 session: CameraCaptureSession,
152                 surface: Surface,
153                 callbacks: AtomicRef<List<CameraCaptureSession.StateCallback>>
154             ) {
155                 for (callback in callbacks.value) {
156                     callback.onSurfacePrepared(session, surface)
157                 }
158             }
159         }
160 
161         @RequiresApi(Build.VERSION_CODES.O)
162         private object Api26CompatImpl {
163             @JvmStatic
onCaptureQueueEmptynull164             fun onCaptureQueueEmpty(
165                 session: CameraCaptureSession,
166                 callbacks: AtomicRef<List<CameraCaptureSession.StateCallback>>
167             ) {
168                 for (callback in callbacks.value) {
169                     callback.onCaptureQueueEmpty(session)
170                 }
171             }
172         }
173     }
174 }
175