AudioGain.cpp revision dfd7409c1b708f6c429aa43722ca8493a91d8df0
1/*
2 * Copyright (C) 2015 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#define LOG_TAG "APM::AudioGain"
18//#define LOG_NDEBUG 0
19
20//#define VERY_VERBOSE_LOGGING
21#ifdef VERY_VERBOSE_LOGGING
22#define ALOGVV ALOGV
23#else
24#define ALOGVV(a...) do { } while(0)
25#endif
26
27#include "AudioGain.h"
28#include "StreamDescriptor.h"
29#include <utils/Log.h>
30#include <utils/String8.h>
31
32#include <math.h>
33
34namespace android {
35
36const VolumeCurvePoint
37ApmGains::sDefaultVolumeCurve[Volume::VOLCNT] = {
38    {1, -49.5f}, {33, -33.5f}, {66, -17.0f}, {100, 0.0f}
39};
40
41
42const VolumeCurvePoint
43ApmGains::sDefaultMediaVolumeCurve[Volume::VOLCNT] = {
44    {1, -58.0f}, {20, -40.0f}, {60, -17.0f}, {100, 0.0f}
45};
46
47const VolumeCurvePoint
48ApmGains::sExtMediaSystemVolumeCurve[Volume::VOLCNT] = {
49    {1, -58.0f}, {20, -40.0f}, {60, -21.0f}, {100, -10.0f}
50};
51
52const VolumeCurvePoint
53ApmGains::sSpeakerMediaVolumeCurve[Volume::VOLCNT] = {
54    {1, -56.0f}, {20, -34.0f}, {60, -11.0f}, {100, 0.0f}
55};
56
57const VolumeCurvePoint
58ApmGains::sSpeakerMediaVolumeCurveDrc[Volume::VOLCNT] = {
59    {1, -55.0f}, {20, -43.0f}, {86, -12.0f}, {100, 0.0f}
60};
61
62const VolumeCurvePoint
63ApmGains::sSpeakerSonificationVolumeCurve[Volume::VOLCNT] = {
64    {1, -29.7f}, {33, -20.1f}, {66, -10.2f}, {100, 0.0f}
65};
66
67const VolumeCurvePoint
68ApmGains::sSpeakerSonificationVolumeCurveDrc[Volume::VOLCNT] = {
69    {1, -35.7f}, {33, -26.1f}, {66, -13.2f}, {100, 0.0f}
70};
71
72// AUDIO_STREAM_SYSTEM, AUDIO_STREAM_ENFORCED_AUDIBLE and AUDIO_STREAM_DTMF volume tracks
73// AUDIO_STREAM_RING on phones and AUDIO_STREAM_MUSIC on tablets.
74// AUDIO_STREAM_DTMF tracks AUDIO_STREAM_VOICE_CALL while in call (See AudioService.java).
75// The range is constrained between -24dB and -6dB over speaker and -30dB and -18dB over headset.
76
77const VolumeCurvePoint
78ApmGains::sDefaultSystemVolumeCurve[Volume::VOLCNT] = {
79    {1, -24.0f}, {33, -18.0f}, {66, -12.0f}, {100, -6.0f}
80};
81
82const VolumeCurvePoint
83ApmGains::sDefaultSystemVolumeCurveDrc[Volume::VOLCNT] = {
84    {1, -34.0f}, {33, -24.0f}, {66, -15.0f}, {100, -6.0f}
85};
86
87const VolumeCurvePoint
88ApmGains::sHeadsetSystemVolumeCurve[Volume::VOLCNT] = {
89    {1, -30.0f}, {33, -26.0f}, {66, -22.0f}, {100, -18.0f}
90};
91
92const VolumeCurvePoint
93ApmGains::sDefaultVoiceVolumeCurve[Volume::VOLCNT] = {
94    {0, -42.0f}, {33, -28.0f}, {66, -14.0f}, {100, 0.0f}
95};
96
97const VolumeCurvePoint
98ApmGains::sSpeakerVoiceVolumeCurve[Volume::VOLCNT] = {
99    {0, -24.0f}, {33, -16.0f}, {66, -8.0f}, {100, 0.0f}
100};
101
102const VolumeCurvePoint
103ApmGains::sLinearVolumeCurve[Volume::VOLCNT] = {
104    {0, -96.0f}, {33, -68.0f}, {66, -34.0f}, {100, 0.0f}
105};
106
107const VolumeCurvePoint
108ApmGains::sSilentVolumeCurve[Volume::VOLCNT] = {
109    {0, -96.0f}, {1, -96.0f}, {2, -96.0f}, {100, -96.0f}
110};
111
112const VolumeCurvePoint
113ApmGains::sFullScaleVolumeCurve[Volume::VOLCNT] = {
114    {0, 0.0f}, {1, 0.0f}, {2, 0.0f}, {100, 0.0f}
115};
116
117const VolumeCurvePoint *ApmGains::sVolumeProfiles[AUDIO_STREAM_CNT]
118                                                  [Volume::DEVICE_CATEGORY_CNT] = {
119    { // AUDIO_STREAM_VOICE_CALL
120        ApmGains::sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_HEADSET
121        ApmGains::sSpeakerVoiceVolumeCurve, // DEVICE_CATEGORY_SPEAKER
122        ApmGains::sSpeakerVoiceVolumeCurve, // DEVICE_CATEGORY_EARPIECE
123        ApmGains::sDefaultMediaVolumeCurve  // DEVICE_CATEGORY_EXT_MEDIA
124    },
125    { // AUDIO_STREAM_SYSTEM
126        ApmGains::sHeadsetSystemVolumeCurve, // DEVICE_CATEGORY_HEADSET
127        ApmGains::sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_SPEAKER
128        ApmGains::sDefaultSystemVolumeCurve,  // DEVICE_CATEGORY_EARPIECE
129        ApmGains::sExtMediaSystemVolumeCurve  // DEVICE_CATEGORY_EXT_MEDIA
130    },
131    { // AUDIO_STREAM_RING
132        ApmGains::sDefaultVolumeCurve, // DEVICE_CATEGORY_HEADSET
133        ApmGains::sSpeakerSonificationVolumeCurve, // DEVICE_CATEGORY_SPEAKER
134        ApmGains::sDefaultVolumeCurve,  // DEVICE_CATEGORY_EARPIECE
135        ApmGains::sExtMediaSystemVolumeCurve  // DEVICE_CATEGORY_EXT_MEDIA
136    },
137    { // AUDIO_STREAM_MUSIC
138        ApmGains::sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_HEADSET
139        ApmGains::sSpeakerMediaVolumeCurve, // DEVICE_CATEGORY_SPEAKER
140        ApmGains::sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_EARPIECE
141        ApmGains::sDefaultMediaVolumeCurve  // DEVICE_CATEGORY_EXT_MEDIA
142    },
143    { // AUDIO_STREAM_ALARM
144        ApmGains::sDefaultVolumeCurve, // DEVICE_CATEGORY_HEADSET
145        ApmGains::sSpeakerSonificationVolumeCurve, // DEVICE_CATEGORY_SPEAKER
146        ApmGains::sDefaultVolumeCurve,  // DEVICE_CATEGORY_EARPIECE
147        ApmGains::sExtMediaSystemVolumeCurve  // DEVICE_CATEGORY_EXT_MEDIA
148    },
149    { // AUDIO_STREAM_NOTIFICATION
150        ApmGains::sDefaultVolumeCurve, // DEVICE_CATEGORY_HEADSET
151        ApmGains::sSpeakerSonificationVolumeCurve, // DEVICE_CATEGORY_SPEAKER
152        ApmGains::sDefaultVolumeCurve,  // DEVICE_CATEGORY_EARPIECE
153        ApmGains::sExtMediaSystemVolumeCurve  // DEVICE_CATEGORY_EXT_MEDIA
154    },
155    { // AUDIO_STREAM_BLUETOOTH_SCO
156        ApmGains::sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_HEADSET
157        ApmGains::sSpeakerVoiceVolumeCurve, // DEVICE_CATEGORY_SPEAKER
158        ApmGains::sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_EARPIECE
159        ApmGains::sDefaultMediaVolumeCurve  // DEVICE_CATEGORY_EXT_MEDIA
160    },
161    { // AUDIO_STREAM_ENFORCED_AUDIBLE
162        ApmGains::sHeadsetSystemVolumeCurve, // DEVICE_CATEGORY_HEADSET
163        ApmGains::sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_SPEAKER
164        ApmGains::sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_EARPIECE
165        ApmGains::sExtMediaSystemVolumeCurve  // DEVICE_CATEGORY_EXT_MEDIA
166    },
167    {  // AUDIO_STREAM_DTMF
168        ApmGains::sHeadsetSystemVolumeCurve, // DEVICE_CATEGORY_HEADSET
169        ApmGains::sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_SPEAKER
170        ApmGains::sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_EARPIECE
171        ApmGains::sExtMediaSystemVolumeCurve  // DEVICE_CATEGORY_EXT_MEDIA
172    },
173    { // AUDIO_STREAM_TTS
174      // "Transmitted Through Speaker": always silent except on DEVICE_CATEGORY_SPEAKER
175        ApmGains::sSilentVolumeCurve, // DEVICE_CATEGORY_HEADSET
176        ApmGains::sLinearVolumeCurve, // DEVICE_CATEGORY_SPEAKER
177        ApmGains::sSilentVolumeCurve, // DEVICE_CATEGORY_EARPIECE
178        ApmGains::sSilentVolumeCurve  // DEVICE_CATEGORY_EXT_MEDIA
179    },
180    { // AUDIO_STREAM_ACCESSIBILITY
181        ApmGains::sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_HEADSET
182        ApmGains::sSpeakerMediaVolumeCurve, // DEVICE_CATEGORY_SPEAKER
183        ApmGains::sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_EARPIECE
184        ApmGains::sDefaultMediaVolumeCurve  // DEVICE_CATEGORY_EXT_MEDIA
185    },
186    { // AUDIO_STREAM_REROUTING
187        ApmGains::sFullScaleVolumeCurve, // DEVICE_CATEGORY_HEADSET
188        ApmGains::sFullScaleVolumeCurve, // DEVICE_CATEGORY_SPEAKER
189        ApmGains::sFullScaleVolumeCurve, // DEVICE_CATEGORY_EARPIECE
190        ApmGains::sFullScaleVolumeCurve  // DEVICE_CATEGORY_EXT_MEDIA
191    },
192    { // AUDIO_STREAM_PATCH
193        ApmGains::sFullScaleVolumeCurve, // DEVICE_CATEGORY_HEADSET
194        ApmGains::sFullScaleVolumeCurve, // DEVICE_CATEGORY_SPEAKER
195        ApmGains::sFullScaleVolumeCurve, // DEVICE_CATEGORY_EARPIECE
196        ApmGains::sFullScaleVolumeCurve  // DEVICE_CATEGORY_EXT_MEDIA
197    },
198};
199
200//static
201float ApmGains::volIndexToAmpl(audio_devices_t device, const StreamDescriptor& streamDesc,
202        int indexInUi)
203{
204    Volume::device_category deviceCategory = Volume::getDeviceCategory(device);
205    const VolumeCurvePoint *curve = streamDesc.getVolumeCurvePoint(deviceCategory);
206
207    // the volume index in the UI is relative to the min and max volume indices for this stream type
208    int nbSteps = 1 + curve[Volume::VOLMAX].mIndex -
209            curve[Volume::VOLMIN].mIndex;
210    int volIdx = (nbSteps * (indexInUi - streamDesc.getVolumeIndexMin())) /
211            (streamDesc.getVolumeIndexMax() - streamDesc.getVolumeIndexMin());
212
213    // find what part of the curve this index volume belongs to, or if it's out of bounds
214    int segment = 0;
215    if (volIdx < curve[Volume::VOLMIN].mIndex) {         // out of bounds
216        return 0.0f;
217    } else if (volIdx < curve[Volume::VOLKNEE1].mIndex) {
218        segment = 0;
219    } else if (volIdx < curve[Volume::VOLKNEE2].mIndex) {
220        segment = 1;
221    } else if (volIdx <= curve[Volume::VOLMAX].mIndex) {
222        segment = 2;
223    } else {                                                               // out of bounds
224        return 1.0f;
225    }
226
227    // linear interpolation in the attenuation table in dB
228    float decibels = curve[segment].mDBAttenuation +
229            ((float)(volIdx - curve[segment].mIndex)) *
230                ( (curve[segment+1].mDBAttenuation -
231                        curve[segment].mDBAttenuation) /
232                    ((float)(curve[segment+1].mIndex -
233                            curve[segment].mIndex)) );
234
235    float amplification = exp( decibels * 0.115129f); // exp( dB * ln(10) / 20 )
236
237    ALOGVV("VOLUME vol index=[%d %d %d], dB=[%.1f %.1f %.1f] ampl=%.5f",
238            curve[segment].mIndex, volIdx,
239            curve[segment+1].mIndex,
240            curve[segment].mDBAttenuation,
241            decibels,
242            curve[segment+1].mDBAttenuation,
243            amplification);
244
245    return amplification;
246}
247
248
249
250AudioGain::AudioGain(int index, bool useInChannelMask)
251{
252    mIndex = index;
253    mUseInChannelMask = useInChannelMask;
254    memset(&mGain, 0, sizeof(struct audio_gain));
255}
256
257void AudioGain::getDefaultConfig(struct audio_gain_config *config)
258{
259    config->index = mIndex;
260    config->mode = mGain.mode;
261    config->channel_mask = mGain.channel_mask;
262    if ((mGain.mode & AUDIO_GAIN_MODE_JOINT) == AUDIO_GAIN_MODE_JOINT) {
263        config->values[0] = mGain.default_value;
264    } else {
265        uint32_t numValues;
266        if (mUseInChannelMask) {
267            numValues = audio_channel_count_from_in_mask(mGain.channel_mask);
268        } else {
269            numValues = audio_channel_count_from_out_mask(mGain.channel_mask);
270        }
271        for (size_t i = 0; i < numValues; i++) {
272            config->values[i] = mGain.default_value;
273        }
274    }
275    if ((mGain.mode & AUDIO_GAIN_MODE_RAMP) == AUDIO_GAIN_MODE_RAMP) {
276        config->ramp_duration_ms = mGain.min_ramp_ms;
277    }
278}
279
280status_t AudioGain::checkConfig(const struct audio_gain_config *config)
281{
282    if ((config->mode & ~mGain.mode) != 0) {
283        return BAD_VALUE;
284    }
285    if ((config->mode & AUDIO_GAIN_MODE_JOINT) == AUDIO_GAIN_MODE_JOINT) {
286        if ((config->values[0] < mGain.min_value) ||
287                    (config->values[0] > mGain.max_value)) {
288            return BAD_VALUE;
289        }
290    } else {
291        if ((config->channel_mask & ~mGain.channel_mask) != 0) {
292            return BAD_VALUE;
293        }
294        uint32_t numValues;
295        if (mUseInChannelMask) {
296            numValues = audio_channel_count_from_in_mask(config->channel_mask);
297        } else {
298            numValues = audio_channel_count_from_out_mask(config->channel_mask);
299        }
300        for (size_t i = 0; i < numValues; i++) {
301            if ((config->values[i] < mGain.min_value) ||
302                    (config->values[i] > mGain.max_value)) {
303                return BAD_VALUE;
304            }
305        }
306    }
307    if ((config->mode & AUDIO_GAIN_MODE_RAMP) == AUDIO_GAIN_MODE_RAMP) {
308        if ((config->ramp_duration_ms < mGain.min_ramp_ms) ||
309                    (config->ramp_duration_ms > mGain.max_ramp_ms)) {
310            return BAD_VALUE;
311        }
312    }
313    return NO_ERROR;
314}
315
316void AudioGain::dump(int fd, int spaces, int index) const
317{
318    const size_t SIZE = 256;
319    char buffer[SIZE];
320    String8 result;
321
322    snprintf(buffer, SIZE, "%*sGain %d:\n", spaces, "", index+1);
323    result.append(buffer);
324    snprintf(buffer, SIZE, "%*s- mode: %08x\n", spaces, "", mGain.mode);
325    result.append(buffer);
326    snprintf(buffer, SIZE, "%*s- channel_mask: %08x\n", spaces, "", mGain.channel_mask);
327    result.append(buffer);
328    snprintf(buffer, SIZE, "%*s- min_value: %d mB\n", spaces, "", mGain.min_value);
329    result.append(buffer);
330    snprintf(buffer, SIZE, "%*s- max_value: %d mB\n", spaces, "", mGain.max_value);
331    result.append(buffer);
332    snprintf(buffer, SIZE, "%*s- default_value: %d mB\n", spaces, "", mGain.default_value);
333    result.append(buffer);
334    snprintf(buffer, SIZE, "%*s- step_value: %d mB\n", spaces, "", mGain.step_value);
335    result.append(buffer);
336    snprintf(buffer, SIZE, "%*s- min_ramp_ms: %d ms\n", spaces, "", mGain.min_ramp_ms);
337    result.append(buffer);
338    snprintf(buffer, SIZE, "%*s- max_ramp_ms: %d ms\n", spaces, "", mGain.max_ramp_ms);
339    result.append(buffer);
340
341    write(fd, result.string(), result.size());
342}
343
344}; // namespace android
345