• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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