1 /* 2 * Copyright 2024 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.compat 18 19 import android.hardware.camera2.CameraDevice 20 import android.os.Build 21 import androidx.annotation.GuardedBy 22 import androidx.camera.camera2.pipe.AudioRestrictionMode 23 import androidx.camera.camera2.pipe.AudioRestrictionMode.Companion.AUDIO_RESTRICTION_NONE 24 import androidx.camera.camera2.pipe.AudioRestrictionMode.Companion.AUDIO_RESTRICTION_VIBRATION 25 import androidx.camera.camera2.pipe.AudioRestrictionMode.Companion.AUDIO_RESTRICTION_VIBRATION_SOUND 26 import androidx.camera.camera2.pipe.CameraGraph 27 import javax.inject.Inject 28 import javax.inject.Singleton 29 30 /** 31 * AudioRestrictionController keeps the global audio restriction mode and audio restriction mode on 32 * each CameraGraph, and computes the final audio restriction mode based on the settings. 33 */ 34 public interface AudioRestrictionController { 35 /** Public global audio restriction mode across all CameraGraph instances. */ 36 public var globalAudioRestrictionMode: AudioRestrictionMode 37 38 /** Update the audio restriction mode of the given CameraGraph. */ updateCameraGraphAudioRestrictionModenull39 public fun updateCameraGraphAudioRestrictionMode( 40 cameraGraph: CameraGraph, 41 mode: AudioRestrictionMode 42 ) 43 44 /** Removes the CameraGraph from the local CameraGraph to audio restriction mode mapping. */ 45 public fun removeCameraGraph(cameraGraph: CameraGraph) 46 47 /** Adds the listener to the controller's stored collection of listeners. */ 48 public fun addListener(listener: Listener) 49 50 /** Removes the listener to the controller's stored collection of listeners. */ 51 public fun removeListener(listener: Listener) 52 53 /** 54 * [CameraDeviceWrapper] extends the [Listener]. When audio restriction mode changes, the 55 * listener's update method would be invoked. 56 */ 57 public interface Listener { 58 /** @see CameraDevice.getCameraAudioRestriction */ 59 public fun onCameraAudioRestrictionUpdated(mode: AudioRestrictionMode) 60 } 61 } 62 63 @Singleton 64 public class AudioRestrictionControllerImpl @Inject constructor() : AudioRestrictionController { 65 private val lock = Any() 66 override var globalAudioRestrictionMode: AudioRestrictionMode = AUDIO_RESTRICTION_NONE <lambda>null67 get() = synchronized(lock) { field } 68 set(value: AudioRestrictionMode) { <lambda>null69 synchronized(lock) { 70 val previousMode = computeAudioRestrictionMode() 71 field = value 72 updateListenersMode(previousMode) 73 } 74 } 75 76 private val audioRestrictionModeMap = mutableMapOf<CameraGraph, AudioRestrictionMode>() 77 private val activeListeners = mutableSetOf<AudioRestrictionController.Listener>() 78 updateCameraGraphAudioRestrictionModenull79 override fun updateCameraGraphAudioRestrictionMode( 80 cameraGraph: CameraGraph, 81 mode: AudioRestrictionMode 82 ) { 83 synchronized(lock) { 84 val previousMode = computeAudioRestrictionMode() 85 audioRestrictionModeMap[cameraGraph] = mode 86 updateListenersMode(previousMode) 87 } 88 } 89 removeCameraGraphnull90 override fun removeCameraGraph(cameraGraph: CameraGraph) { 91 synchronized(lock) { 92 val previousMode = computeAudioRestrictionMode() 93 audioRestrictionModeMap.remove(cameraGraph) 94 updateListenersMode(previousMode) 95 } 96 } 97 98 @GuardedBy("lock") computeAudioRestrictionModenull99 private fun computeAudioRestrictionMode(): AudioRestrictionMode { 100 if ( 101 audioRestrictionModeMap.containsValue(AUDIO_RESTRICTION_VIBRATION_SOUND) || 102 globalAudioRestrictionMode == AUDIO_RESTRICTION_VIBRATION_SOUND 103 ) { 104 return AUDIO_RESTRICTION_VIBRATION_SOUND 105 } 106 if ( 107 audioRestrictionModeMap.containsValue(AUDIO_RESTRICTION_VIBRATION) || 108 globalAudioRestrictionMode == AUDIO_RESTRICTION_VIBRATION 109 ) { 110 return AUDIO_RESTRICTION_VIBRATION 111 } 112 return AUDIO_RESTRICTION_NONE 113 } 114 addListenernull115 override fun addListener(listener: AudioRestrictionController.Listener) { 116 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { 117 return 118 } 119 synchronized(lock) { 120 activeListeners.add(listener) 121 val mode = computeAudioRestrictionMode() 122 listener.onCameraAudioRestrictionUpdated(mode) 123 } 124 } 125 removeListenernull126 override fun removeListener(listener: AudioRestrictionController.Listener) { 127 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { 128 return 129 } 130 synchronized(lock) { activeListeners.remove(listener) } 131 } 132 133 @GuardedBy("lock") updateListenersModenull134 private fun updateListenersMode(previousMode: AudioRestrictionMode? = null) { 135 val mode = computeAudioRestrictionMode() 136 if (previousMode != null && mode != previousMode) { 137 for (listener in activeListeners) { 138 listener.onCameraAudioRestrictionUpdated(mode) 139 } 140 } 141 } 142 } 143