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.internal.ExcludeFromCodeCoverageGeneratedReport; 31 import com.android.car.internal.util.IndentingPrintWriter; 32 33 /** 34 * A helper class wraps {@link AudioDeviceInfo}, and helps get/set the gain on a specific port 35 * in terms of millibels. 36 * Note to the reader. For whatever reason, it seems that AudioGain contains only configuration 37 * information (min/max/step, etc) while the AudioGainConfig class contains the 38 * actual currently active gain value(s). 39 */ 40 /* package */ class CarAudioDeviceInfo { 41 42 public static final int DEFAULT_SAMPLE_RATE = 48000; 43 private final AudioDeviceInfo mAudioDeviceInfo; 44 private final int mSampleRate; 45 private final int mEncodingFormat; 46 private final int mChannelCount; 47 private final int mDefaultGain; 48 private final int mMaxGain; 49 private final int mMinGain; 50 private final int mStepValue; 51 private final AudioManager mAudioManager; 52 53 /** 54 * We need to store the current gain because it is not accessible from the current 55 * audio engine implementation. It would be nice if AudioPort#activeConfig() would return it, 56 * but in the current implementation, that function actually works only for mixer ports. 57 */ 58 private int mCurrentGain; 59 CarAudioDeviceInfo(AudioManager audioManager, AudioDeviceInfo audioDeviceInfo)60 CarAudioDeviceInfo(AudioManager audioManager, AudioDeviceInfo audioDeviceInfo) { 61 mAudioManager = audioManager; 62 mAudioDeviceInfo = audioDeviceInfo; 63 mSampleRate = getMaxSampleRate(audioDeviceInfo); 64 mEncodingFormat = ENCODING_PCM_16BIT; 65 mChannelCount = getMaxChannels(audioDeviceInfo); 66 AudioGainInfo audioGainInfo = AudioManagerHelper.getAudioGainInfo(audioDeviceInfo); 67 mDefaultGain = audioGainInfo.getDefaultGain(); 68 mMaxGain = audioGainInfo.getMaxGain(); 69 mMinGain = audioGainInfo.getMinGain(); 70 mStepValue = audioGainInfo.getStepValue(); 71 72 mCurrentGain = -1; // Not initialized till explicitly set 73 } 74 getAudioDeviceInfo()75 AudioDeviceInfo getAudioDeviceInfo() { 76 return mAudioDeviceInfo; 77 } 78 getAddress()79 String getAddress() { 80 return mAudioDeviceInfo.getAddress(); 81 } 82 getDefaultGain()83 int getDefaultGain() { 84 return mDefaultGain; 85 } 86 getMaxGain()87 int getMaxGain() { 88 return mMaxGain; 89 } 90 getMinGain()91 int getMinGain() { 92 return mMinGain; 93 } 94 getSampleRate()95 int getSampleRate() { 96 return mSampleRate; 97 } 98 getEncodingFormat()99 int getEncodingFormat() { 100 return mEncodingFormat; 101 } 102 getChannelCount()103 int getChannelCount() { 104 return mChannelCount; 105 } 106 getStepValue()107 int getStepValue() { 108 return mStepValue; 109 } 110 111 112 // Input is in millibels setCurrentGain(int gainInMillibels)113 void setCurrentGain(int gainInMillibels) { 114 // Clamp the incoming value to our valid range. Out of range values ARE legal input 115 if (gainInMillibels < mMinGain) { 116 gainInMillibels = mMinGain; 117 } else if (gainInMillibels > mMaxGain) { 118 gainInMillibels = mMaxGain; 119 } 120 121 if (AudioManagerHelper.setAudioDeviceGain(mAudioManager, 122 getAddress(), gainInMillibels, true)) { 123 // Since we can't query for the gain on a device port later, 124 // we have to remember what we asked for 125 mCurrentGain = gainInMillibels; 126 } else { 127 Slogf.e(CarLog.TAG_AUDIO, "Failed to setAudioPortGain " + gainInMillibels 128 + " for output device " + getAddress()); 129 } 130 } 131 getMaxSampleRate(AudioDeviceInfo info)132 private static int getMaxSampleRate(AudioDeviceInfo info) { 133 int[] sampleRates = info.getSampleRates(); 134 if (sampleRates == null || sampleRates.length == 0) { 135 return DEFAULT_SAMPLE_RATE; 136 } 137 int sampleRate = sampleRates[0]; 138 for (int i = 1; i < sampleRates.length; i++) { 139 if (sampleRates[i] > sampleRate) { 140 sampleRate = sampleRates[i]; 141 } 142 } 143 return sampleRate; 144 } 145 getMaxChannels(AudioDeviceInfo info)146 private static int getMaxChannels(AudioDeviceInfo info) { 147 int numChannels = 1; 148 int[] channelMasks = info.getChannelMasks(); 149 if (channelMasks == null) { 150 return numChannels; 151 } 152 for (int channelMask : channelMasks) { 153 int currentNumChannels = Integer.bitCount(channelMask); 154 if (currentNumChannels > numChannels) { 155 numChannels = currentNumChannels; 156 } 157 } 158 return numChannels; 159 } 160 161 @Override 162 @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE) toString()163 public String toString() { 164 return "address: " + mAudioDeviceInfo.getAddress() 165 + " sampleRate: " + getSampleRate() 166 + " encodingFormat: " + getEncodingFormat() 167 + " channelCount: " + getChannelCount() 168 + " currentGain: " + mCurrentGain 169 + " maxGain: " + mMaxGain 170 + " minGain: " + mMinGain; 171 } 172 173 @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO) dump(IndentingPrintWriter writer)174 void dump(IndentingPrintWriter writer) { 175 writer.printf("CarAudioDeviceInfo Device(%s)\n", mAudioDeviceInfo.getAddress()); 176 writer.increaseIndent(); 177 writer.printf("sample rate / encoding format / channel count: %d %d %d\n", 178 getSampleRate(), getEncodingFormat(), getChannelCount()); 179 writer.printf("Gain values (min / max / default/ current): %d %d %d %d\n", 180 mMinGain, mMaxGain, mDefaultGain, mCurrentGain); 181 writer.decreaseIndent(); 182 } 183 } 184