1 /* 2 * Copyright (C) 2018 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 com.android.car.audio; 17 18 import static android.media.AudioFormat.ENCODING_PCM_16BIT; 19 20 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE; 21 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO; 22 23 import android.car.builtin.media.AudioManagerHelper; 24 import android.car.builtin.media.AudioManagerHelper.AudioGainInfo; 25 import android.car.builtin.util.Slogf; 26 import android.media.AudioDeviceInfo; 27 import android.media.AudioManager; 28 29 import com.android.car.CarLog; 30 import com.android.car.audio.hal.HalAudioDeviceInfo; 31 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport; 32 import com.android.car.internal.util.IndentingPrintWriter; 33 import com.android.internal.annotations.GuardedBy; 34 35 /** 36 * A helper class wraps {@link AudioDeviceInfo}, and helps get/set the gain on a specific port 37 * in terms of millibels. 38 * Note to the reader. For whatever reason, it seems that AudioGain contains only configuration 39 * information (min/max/step, etc) while the AudioGainConfig class contains the 40 * actual currently active gain value(s). 41 */ 42 /* package */ class CarAudioDeviceInfo { 43 44 public static final int DEFAULT_SAMPLE_RATE = 48000; 45 private final AudioDeviceInfo mAudioDeviceInfo; 46 private final int mSampleRate; 47 private final int mEncodingFormat; 48 private final int mChannelCount; 49 private final AudioManager mAudioManager; 50 51 private final Object mLock = new Object(); 52 @GuardedBy("mLock") 53 private int mDefaultGain; 54 @GuardedBy("mLock") 55 private int mMaxGain; 56 @GuardedBy("mLock") 57 private int mMinGain; 58 @GuardedBy("mLock") 59 private int mStepValue; 60 @GuardedBy("mLock") 61 private boolean mCanBeRoutedWithDynamicPolicyMixRule = true; 62 63 64 /** 65 * We need to store the current gain because it is not accessible from the current 66 * audio engine implementation. It would be nice if AudioPort#activeConfig() would return it, 67 * but in the current implementation, that function actually works only for mixer ports. 68 */ 69 private int mCurrentGain; 70 CarAudioDeviceInfo(AudioManager audioManager, AudioDeviceInfo audioDeviceInfo)71 CarAudioDeviceInfo(AudioManager audioManager, AudioDeviceInfo audioDeviceInfo) { 72 mAudioManager = audioManager; 73 mAudioDeviceInfo = audioDeviceInfo; 74 mSampleRate = getMaxSampleRate(audioDeviceInfo); 75 mEncodingFormat = ENCODING_PCM_16BIT; 76 mChannelCount = getMaxChannels(audioDeviceInfo); 77 AudioGainInfo audioGainInfo = AudioManagerHelper.getAudioGainInfo(audioDeviceInfo); 78 mDefaultGain = audioGainInfo.getDefaultGain(); 79 mMaxGain = audioGainInfo.getMaxGain(); 80 mMinGain = audioGainInfo.getMinGain(); 81 mStepValue = audioGainInfo.getStepValue(); 82 83 mCurrentGain = -1; // Not initialized till explicitly set 84 } 85 getAudioDeviceInfo()86 AudioDeviceInfo getAudioDeviceInfo() { 87 return mAudioDeviceInfo; 88 } 89 90 /** 91 * By default, considers all AudioDevice can be used to establish dynamic policy mixing rules. 92 * until validation state is performed. 93 * Once called, the device is marked definitively as "connot be routed with dynamic mixes". 94 */ resetCanBeRoutedWithDynamicPolicyMix()95 void resetCanBeRoutedWithDynamicPolicyMix() { 96 synchronized (mLock) { 97 mCanBeRoutedWithDynamicPolicyMixRule = false; 98 } 99 } 100 canBeRoutedWithDynamicPolicyMix()101 boolean canBeRoutedWithDynamicPolicyMix() { 102 synchronized (mLock) { 103 return mCanBeRoutedWithDynamicPolicyMixRule; 104 } 105 } 106 getAddress()107 String getAddress() { 108 return mAudioDeviceInfo.getAddress(); 109 } 110 getDefaultGain()111 int getDefaultGain() { 112 synchronized (mLock) { 113 return mDefaultGain; 114 } 115 } 116 getMaxGain()117 int getMaxGain() { 118 synchronized (mLock) { 119 return mMaxGain; 120 } 121 } 122 getMinGain()123 int getMinGain() { 124 synchronized (mLock) { 125 return mMinGain; 126 } 127 } 128 getSampleRate()129 int getSampleRate() { 130 return mSampleRate; 131 } 132 getEncodingFormat()133 int getEncodingFormat() { 134 return mEncodingFormat; 135 } 136 getChannelCount()137 int getChannelCount() { 138 return mChannelCount; 139 } 140 getStepValue()141 int getStepValue() { 142 synchronized (mLock) { 143 return mStepValue; 144 } 145 } 146 147 148 // Input is in millibels setCurrentGain(int gainInMillibels)149 void setCurrentGain(int gainInMillibels) { 150 int gain = gainInMillibels; 151 // Clamp the incoming value to our valid range. Out of range values ARE legal input 152 synchronized (mLock) { 153 if (gain < mMinGain) { 154 gain = mMinGain; 155 } else if (gain > mMaxGain) { 156 gain = mMaxGain; 157 } 158 } 159 160 if (AudioManagerHelper.setAudioDeviceGain(mAudioManager, 161 getAddress(), gain, true)) { 162 // Since we can't query for the gain on a device port later, 163 // we have to remember what we asked for 164 mCurrentGain = gain; 165 } else { 166 Slogf.e(CarLog.TAG_AUDIO, "Failed to setAudioPortGain " + gain 167 + " for output device " + getAddress()); 168 } 169 } 170 171 // Updates audio device info for dynamic gain stage configurations updateAudioDeviceInfo(HalAudioDeviceInfo halDeviceInfo)172 void updateAudioDeviceInfo(HalAudioDeviceInfo halDeviceInfo) { 173 synchronized (mLock) { 174 mMinGain = halDeviceInfo.getGainMinValue(); 175 mMaxGain = halDeviceInfo.getGainMaxValue(); 176 mStepValue = halDeviceInfo.getGainStepValue(); 177 mDefaultGain = halDeviceInfo.getGainDefaultValue(); 178 } 179 } 180 getMaxSampleRate(AudioDeviceInfo info)181 private static int getMaxSampleRate(AudioDeviceInfo info) { 182 int[] sampleRates = info.getSampleRates(); 183 if (sampleRates == null || sampleRates.length == 0) { 184 return DEFAULT_SAMPLE_RATE; 185 } 186 int sampleRate = sampleRates[0]; 187 for (int i = 1; i < sampleRates.length; i++) { 188 if (sampleRates[i] > sampleRate) { 189 sampleRate = sampleRates[i]; 190 } 191 } 192 return sampleRate; 193 } 194 getMaxChannels(AudioDeviceInfo info)195 private static int getMaxChannels(AudioDeviceInfo info) { 196 int numChannels = 1; 197 int[] channelMasks = info.getChannelMasks(); 198 if (channelMasks == null) { 199 return numChannels; 200 } 201 for (int channelMask : channelMasks) { 202 int currentNumChannels = Integer.bitCount(channelMask); 203 if (currentNumChannels > numChannels) { 204 numChannels = currentNumChannels; 205 } 206 } 207 return numChannels; 208 } 209 210 @Override 211 @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE) toString()212 public String toString() { 213 return "address: " + mAudioDeviceInfo.getAddress() 214 + " sampleRate: " + getSampleRate() 215 + " encodingFormat: " + getEncodingFormat() 216 + " channelCount: " + getChannelCount() 217 + " currentGain: " + mCurrentGain 218 + " maxGain: " + getMaxGain() 219 + " minGain: " + getMinGain(); 220 } 221 222 @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO) dump(IndentingPrintWriter writer)223 void dump(IndentingPrintWriter writer) { 224 synchronized (mLock) { 225 writer.printf("CarAudioDeviceInfo Device(%s)\n", mAudioDeviceInfo.getAddress()); 226 writer.increaseIndent(); 227 writer.printf("Routing with Dynamic Mix enabled (%b)\n", 228 mCanBeRoutedWithDynamicPolicyMixRule); 229 writer.printf("sample rate / encoding format / channel count: %d %d %d\n", 230 getSampleRate(), getEncodingFormat(), getChannelCount()); 231 writer.printf("Gain values (min / max / default/ current): %d %d %d %d\n", 232 mMinGain, mMaxGain, mDefaultGain, mCurrentGain); 233 writer.decreaseIndent(); 234 } 235 } 236 } 237