AudioGain.cpp revision 98cc191247388132b6fd8a4ecd07abd6e4c5a0ed
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 <utils/Log.h>
29#include <utils/String8.h>
30
31#include <math.h>
32
33namespace android {
34
35const VolumeCurvePoint
36ApmGains::sDefaultVolumeCurve[ApmGains::VOLCNT] = {
37    {1, -49.5f}, {33, -33.5f}, {66, -17.0f}, {100, 0.0f}
38};
39
40
41const VolumeCurvePoint
42ApmGains::sDefaultMediaVolumeCurve[ApmGains::VOLCNT] = {
43    {1, -58.0f}, {20, -40.0f}, {60, -17.0f}, {100, 0.0f}
44};
45
46const VolumeCurvePoint
47ApmGains::sExtMediaSystemVolumeCurve[ApmGains::VOLCNT] = {
48    {1, -58.0f}, {20, -40.0f}, {60, -21.0f}, {100, -10.0f}
49};
50
51const VolumeCurvePoint
52ApmGains::sSpeakerMediaVolumeCurve[ApmGains::VOLCNT] = {
53    {1, -56.0f}, {20, -34.0f}, {60, -11.0f}, {100, 0.0f}
54};
55
56const VolumeCurvePoint
57ApmGains::sSpeakerMediaVolumeCurveDrc[ApmGains::VOLCNT] = {
58    {1, -55.0f}, {20, -43.0f}, {86, -12.0f}, {100, 0.0f}
59};
60
61const VolumeCurvePoint
62ApmGains::sSpeakerSonificationVolumeCurve[ApmGains::VOLCNT] = {
63    {1, -29.7f}, {33, -20.1f}, {66, -10.2f}, {100, 0.0f}
64};
65
66const VolumeCurvePoint
67ApmGains::sSpeakerSonificationVolumeCurveDrc[ApmGains::VOLCNT] = {
68    {1, -35.7f}, {33, -26.1f}, {66, -13.2f}, {100, 0.0f}
69};
70
71// AUDIO_STREAM_SYSTEM, AUDIO_STREAM_ENFORCED_AUDIBLE and AUDIO_STREAM_DTMF volume tracks
72// AUDIO_STREAM_RING on phones and AUDIO_STREAM_MUSIC on tablets.
73// AUDIO_STREAM_DTMF tracks AUDIO_STREAM_VOICE_CALL while in call (See AudioService.java).
74// The range is constrained between -24dB and -6dB over speaker and -30dB and -18dB over headset.
75
76const VolumeCurvePoint
77ApmGains::sDefaultSystemVolumeCurve[ApmGains::VOLCNT] = {
78    {1, -24.0f}, {33, -18.0f}, {66, -12.0f}, {100, -6.0f}
79};
80
81const VolumeCurvePoint
82ApmGains::sDefaultSystemVolumeCurveDrc[ApmGains::VOLCNT] = {
83    {1, -34.0f}, {33, -24.0f}, {66, -15.0f}, {100, -6.0f}
84};
85
86const VolumeCurvePoint
87ApmGains::sHeadsetSystemVolumeCurve[ApmGains::VOLCNT] = {
88    {1, -30.0f}, {33, -26.0f}, {66, -22.0f}, {100, -18.0f}
89};
90
91const VolumeCurvePoint
92ApmGains::sDefaultVoiceVolumeCurve[ApmGains::VOLCNT] = {
93    {0, -42.0f}, {33, -28.0f}, {66, -14.0f}, {100, 0.0f}
94};
95
96const VolumeCurvePoint
97ApmGains::sSpeakerVoiceVolumeCurve[ApmGains::VOLCNT] = {
98    {0, -24.0f}, {33, -16.0f}, {66, -8.0f}, {100, 0.0f}
99};
100
101const VolumeCurvePoint
102ApmGains::sLinearVolumeCurve[ApmGains::VOLCNT] = {
103    {0, -96.0f}, {33, -68.0f}, {66, -34.0f}, {100, 0.0f}
104};
105
106const VolumeCurvePoint
107ApmGains::sSilentVolumeCurve[ApmGains::VOLCNT] = {
108    {0, -96.0f}, {1, -96.0f}, {2, -96.0f}, {100, -96.0f}
109};
110
111const VolumeCurvePoint
112ApmGains::sFullScaleVolumeCurve[ApmGains::VOLCNT] = {
113    {0, 0.0f}, {1, 0.0f}, {2, 0.0f}, {100, 0.0f}
114};
115
116const VolumeCurvePoint *ApmGains::sVolumeProfiles[AUDIO_STREAM_CNT]
117                                                  [ApmGains::DEVICE_CATEGORY_CNT] = {
118    { // AUDIO_STREAM_VOICE_CALL
119        ApmGains::sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_HEADSET
120        ApmGains::sSpeakerVoiceVolumeCurve, // DEVICE_CATEGORY_SPEAKER
121        ApmGains::sSpeakerVoiceVolumeCurve, // DEVICE_CATEGORY_EARPIECE
122        ApmGains::sDefaultMediaVolumeCurve  // DEVICE_CATEGORY_EXT_MEDIA
123    },
124    { // AUDIO_STREAM_SYSTEM
125        ApmGains::sHeadsetSystemVolumeCurve, // DEVICE_CATEGORY_HEADSET
126        ApmGains::sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_SPEAKER
127        ApmGains::sDefaultSystemVolumeCurve,  // DEVICE_CATEGORY_EARPIECE
128        ApmGains::sExtMediaSystemVolumeCurve  // DEVICE_CATEGORY_EXT_MEDIA
129    },
130    { // AUDIO_STREAM_RING
131        ApmGains::sDefaultVolumeCurve, // DEVICE_CATEGORY_HEADSET
132        ApmGains::sSpeakerSonificationVolumeCurve, // DEVICE_CATEGORY_SPEAKER
133        ApmGains::sDefaultVolumeCurve,  // DEVICE_CATEGORY_EARPIECE
134        ApmGains::sExtMediaSystemVolumeCurve  // DEVICE_CATEGORY_EXT_MEDIA
135    },
136    { // AUDIO_STREAM_MUSIC
137        ApmGains::sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_HEADSET
138        ApmGains::sSpeakerMediaVolumeCurve, // DEVICE_CATEGORY_SPEAKER
139        ApmGains::sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_EARPIECE
140        ApmGains::sDefaultMediaVolumeCurve  // DEVICE_CATEGORY_EXT_MEDIA
141    },
142    { // AUDIO_STREAM_ALARM
143        ApmGains::sDefaultVolumeCurve, // DEVICE_CATEGORY_HEADSET
144        ApmGains::sSpeakerSonificationVolumeCurve, // DEVICE_CATEGORY_SPEAKER
145        ApmGains::sDefaultVolumeCurve,  // DEVICE_CATEGORY_EARPIECE
146        ApmGains::sExtMediaSystemVolumeCurve  // DEVICE_CATEGORY_EXT_MEDIA
147    },
148    { // AUDIO_STREAM_NOTIFICATION
149        ApmGains::sDefaultVolumeCurve, // DEVICE_CATEGORY_HEADSET
150        ApmGains::sSpeakerSonificationVolumeCurve, // DEVICE_CATEGORY_SPEAKER
151        ApmGains::sDefaultVolumeCurve,  // DEVICE_CATEGORY_EARPIECE
152        ApmGains::sExtMediaSystemVolumeCurve  // DEVICE_CATEGORY_EXT_MEDIA
153    },
154    { // AUDIO_STREAM_BLUETOOTH_SCO
155        ApmGains::sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_HEADSET
156        ApmGains::sSpeakerVoiceVolumeCurve, // DEVICE_CATEGORY_SPEAKER
157        ApmGains::sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_EARPIECE
158        ApmGains::sDefaultMediaVolumeCurve  // DEVICE_CATEGORY_EXT_MEDIA
159    },
160    { // AUDIO_STREAM_ENFORCED_AUDIBLE
161        ApmGains::sHeadsetSystemVolumeCurve, // DEVICE_CATEGORY_HEADSET
162        ApmGains::sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_SPEAKER
163        ApmGains::sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_EARPIECE
164        ApmGains::sExtMediaSystemVolumeCurve  // DEVICE_CATEGORY_EXT_MEDIA
165    },
166    {  // AUDIO_STREAM_DTMF
167        ApmGains::sHeadsetSystemVolumeCurve, // DEVICE_CATEGORY_HEADSET
168        ApmGains::sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_SPEAKER
169        ApmGains::sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_EARPIECE
170        ApmGains::sExtMediaSystemVolumeCurve  // DEVICE_CATEGORY_EXT_MEDIA
171    },
172    { // AUDIO_STREAM_TTS
173      // "Transmitted Through Speaker": always silent except on DEVICE_CATEGORY_SPEAKER
174        ApmGains::sSilentVolumeCurve, // DEVICE_CATEGORY_HEADSET
175        ApmGains::sLinearVolumeCurve, // DEVICE_CATEGORY_SPEAKER
176        ApmGains::sSilentVolumeCurve, // DEVICE_CATEGORY_EARPIECE
177        ApmGains::sSilentVolumeCurve  // DEVICE_CATEGORY_EXT_MEDIA
178    },
179    { // AUDIO_STREAM_ACCESSIBILITY
180        ApmGains::sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_HEADSET
181        ApmGains::sSpeakerMediaVolumeCurve, // DEVICE_CATEGORY_SPEAKER
182        ApmGains::sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_EARPIECE
183        ApmGains::sDefaultMediaVolumeCurve  // DEVICE_CATEGORY_EXT_MEDIA
184    },
185    { // AUDIO_STREAM_REROUTING
186        ApmGains::sFullScaleVolumeCurve, // DEVICE_CATEGORY_HEADSET
187        ApmGains::sFullScaleVolumeCurve, // DEVICE_CATEGORY_SPEAKER
188        ApmGains::sFullScaleVolumeCurve, // DEVICE_CATEGORY_EARPIECE
189        ApmGains::sFullScaleVolumeCurve  // DEVICE_CATEGORY_EXT_MEDIA
190    },
191    { // AUDIO_STREAM_PATCH
192        ApmGains::sFullScaleVolumeCurve, // DEVICE_CATEGORY_HEADSET
193        ApmGains::sFullScaleVolumeCurve, // DEVICE_CATEGORY_SPEAKER
194        ApmGains::sFullScaleVolumeCurve, // DEVICE_CATEGORY_EARPIECE
195        ApmGains::sFullScaleVolumeCurve  // DEVICE_CATEGORY_EXT_MEDIA
196    },
197};
198
199//static
200audio_devices_t ApmGains::getDeviceForVolume(audio_devices_t device)
201{
202    if (device == AUDIO_DEVICE_NONE) {
203        // this happens when forcing a route update and no track is active on an output.
204        // In this case the returned category is not important.
205        device =  AUDIO_DEVICE_OUT_SPEAKER;
206    } else if (popcount(device) > 1) {
207        // Multiple device selection is either:
208        //  - speaker + one other device: give priority to speaker in this case.
209        //  - one A2DP device + another device: happens with duplicated output. In this case
210        // retain the device on the A2DP output as the other must not correspond to an active
211        // selection if not the speaker.
212        //  - HDMI-CEC system audio mode only output: give priority to available item in order.
213        if (device & AUDIO_DEVICE_OUT_SPEAKER) {
214            device = AUDIO_DEVICE_OUT_SPEAKER;
215        } else if (device & AUDIO_DEVICE_OUT_HDMI_ARC) {
216            device = AUDIO_DEVICE_OUT_HDMI_ARC;
217        } else if (device & AUDIO_DEVICE_OUT_AUX_LINE) {
218            device = AUDIO_DEVICE_OUT_AUX_LINE;
219        } else if (device & AUDIO_DEVICE_OUT_SPDIF) {
220            device = AUDIO_DEVICE_OUT_SPDIF;
221        } else {
222            device = (audio_devices_t)(device & AUDIO_DEVICE_OUT_ALL_A2DP);
223        }
224    }
225
226    /*SPEAKER_SAFE is an alias of SPEAKER for purposes of volume control*/
227    if (device == AUDIO_DEVICE_OUT_SPEAKER_SAFE)
228        device = AUDIO_DEVICE_OUT_SPEAKER;
229
230    ALOGW_IF(popcount(device) != 1,
231            "getDeviceForVolume() invalid device combination: %08x",
232            device);
233
234    return device;
235}
236
237//static
238ApmGains::device_category ApmGains::getDeviceCategory(audio_devices_t device)
239{
240    switch(getDeviceForVolume(device)) {
241        case AUDIO_DEVICE_OUT_EARPIECE:
242            return ApmGains::DEVICE_CATEGORY_EARPIECE;
243        case AUDIO_DEVICE_OUT_WIRED_HEADSET:
244        case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
245        case AUDIO_DEVICE_OUT_BLUETOOTH_SCO:
246        case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
247        case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP:
248        case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
249            return ApmGains::DEVICE_CATEGORY_HEADSET;
250        case AUDIO_DEVICE_OUT_LINE:
251        case AUDIO_DEVICE_OUT_AUX_DIGITAL:
252        /*USB?  Remote submix?*/
253            return ApmGains::DEVICE_CATEGORY_EXT_MEDIA;
254        case AUDIO_DEVICE_OUT_SPEAKER:
255        case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
256        case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER:
257        case AUDIO_DEVICE_OUT_USB_ACCESSORY:
258        case AUDIO_DEVICE_OUT_USB_DEVICE:
259        case AUDIO_DEVICE_OUT_REMOTE_SUBMIX:
260        default:
261            return ApmGains::DEVICE_CATEGORY_SPEAKER;
262    }
263}
264
265//static
266float ApmGains::volIndexToAmpl(audio_devices_t device, const StreamDescriptor& streamDesc,
267        int indexInUi)
268{
269    ApmGains::device_category deviceCategory = ApmGains::getDeviceCategory(device);
270    const VolumeCurvePoint *curve = streamDesc.mVolumeCurve[deviceCategory];
271
272    // the volume index in the UI is relative to the min and max volume indices for this stream type
273    int nbSteps = 1 + curve[ApmGains::VOLMAX].mIndex -
274            curve[ApmGains::VOLMIN].mIndex;
275    int volIdx = (nbSteps * (indexInUi - streamDesc.mIndexMin)) /
276            (streamDesc.mIndexMax - streamDesc.mIndexMin);
277
278    // find what part of the curve this index volume belongs to, or if it's out of bounds
279    int segment = 0;
280    if (volIdx < curve[ApmGains::VOLMIN].mIndex) {         // out of bounds
281        return 0.0f;
282    } else if (volIdx < curve[ApmGains::VOLKNEE1].mIndex) {
283        segment = 0;
284    } else if (volIdx < curve[ApmGains::VOLKNEE2].mIndex) {
285        segment = 1;
286    } else if (volIdx <= curve[ApmGains::VOLMAX].mIndex) {
287        segment = 2;
288    } else {                                                               // out of bounds
289        return 1.0f;
290    }
291
292    // linear interpolation in the attenuation table in dB
293    float decibels = curve[segment].mDBAttenuation +
294            ((float)(volIdx - curve[segment].mIndex)) *
295                ( (curve[segment+1].mDBAttenuation -
296                        curve[segment].mDBAttenuation) /
297                    ((float)(curve[segment+1].mIndex -
298                            curve[segment].mIndex)) );
299
300    float amplification = exp( decibels * 0.115129f); // exp( dB * ln(10) / 20 )
301
302    ALOGVV("VOLUME vol index=[%d %d %d], dB=[%.1f %.1f %.1f] ampl=%.5f",
303            curve[segment].mIndex, volIdx,
304            curve[segment+1].mIndex,
305            curve[segment].mDBAttenuation,
306            decibels,
307            curve[segment+1].mDBAttenuation,
308            amplification);
309
310    return amplification;
311}
312
313
314
315AudioGain::AudioGain(int index, bool useInChannelMask)
316{
317    mIndex = index;
318    mUseInChannelMask = useInChannelMask;
319    memset(&mGain, 0, sizeof(struct audio_gain));
320}
321
322void AudioGain::getDefaultConfig(struct audio_gain_config *config)
323{
324    config->index = mIndex;
325    config->mode = mGain.mode;
326    config->channel_mask = mGain.channel_mask;
327    if ((mGain.mode & AUDIO_GAIN_MODE_JOINT) == AUDIO_GAIN_MODE_JOINT) {
328        config->values[0] = mGain.default_value;
329    } else {
330        uint32_t numValues;
331        if (mUseInChannelMask) {
332            numValues = audio_channel_count_from_in_mask(mGain.channel_mask);
333        } else {
334            numValues = audio_channel_count_from_out_mask(mGain.channel_mask);
335        }
336        for (size_t i = 0; i < numValues; i++) {
337            config->values[i] = mGain.default_value;
338        }
339    }
340    if ((mGain.mode & AUDIO_GAIN_MODE_RAMP) == AUDIO_GAIN_MODE_RAMP) {
341        config->ramp_duration_ms = mGain.min_ramp_ms;
342    }
343}
344
345status_t AudioGain::checkConfig(const struct audio_gain_config *config)
346{
347    if ((config->mode & ~mGain.mode) != 0) {
348        return BAD_VALUE;
349    }
350    if ((config->mode & AUDIO_GAIN_MODE_JOINT) == AUDIO_GAIN_MODE_JOINT) {
351        if ((config->values[0] < mGain.min_value) ||
352                    (config->values[0] > mGain.max_value)) {
353            return BAD_VALUE;
354        }
355    } else {
356        if ((config->channel_mask & ~mGain.channel_mask) != 0) {
357            return BAD_VALUE;
358        }
359        uint32_t numValues;
360        if (mUseInChannelMask) {
361            numValues = audio_channel_count_from_in_mask(config->channel_mask);
362        } else {
363            numValues = audio_channel_count_from_out_mask(config->channel_mask);
364        }
365        for (size_t i = 0; i < numValues; i++) {
366            if ((config->values[i] < mGain.min_value) ||
367                    (config->values[i] > mGain.max_value)) {
368                return BAD_VALUE;
369            }
370        }
371    }
372    if ((config->mode & AUDIO_GAIN_MODE_RAMP) == AUDIO_GAIN_MODE_RAMP) {
373        if ((config->ramp_duration_ms < mGain.min_ramp_ms) ||
374                    (config->ramp_duration_ms > mGain.max_ramp_ms)) {
375            return BAD_VALUE;
376        }
377    }
378    return NO_ERROR;
379}
380
381void AudioGain::dump(int fd, int spaces, int index) const
382{
383    const size_t SIZE = 256;
384    char buffer[SIZE];
385    String8 result;
386
387    snprintf(buffer, SIZE, "%*sGain %d:\n", spaces, "", index+1);
388    result.append(buffer);
389    snprintf(buffer, SIZE, "%*s- mode: %08x\n", spaces, "", mGain.mode);
390    result.append(buffer);
391    snprintf(buffer, SIZE, "%*s- channel_mask: %08x\n", spaces, "", mGain.channel_mask);
392    result.append(buffer);
393    snprintf(buffer, SIZE, "%*s- min_value: %d mB\n", spaces, "", mGain.min_value);
394    result.append(buffer);
395    snprintf(buffer, SIZE, "%*s- max_value: %d mB\n", spaces, "", mGain.max_value);
396    result.append(buffer);
397    snprintf(buffer, SIZE, "%*s- default_value: %d mB\n", spaces, "", mGain.default_value);
398    result.append(buffer);
399    snprintf(buffer, SIZE, "%*s- step_value: %d mB\n", spaces, "", mGain.step_value);
400    result.append(buffer);
401    snprintf(buffer, SIZE, "%*s- min_ramp_ms: %d ms\n", spaces, "", mGain.min_ramp_ms);
402    result.append(buffer);
403    snprintf(buffer, SIZE, "%*s- max_ramp_ms: %d ms\n", spaces, "", mGain.max_ramp_ms);
404    result.append(buffer);
405
406    write(fd, result.string(), result.size());
407}
408
409
410// --- StreamDescriptor class implementation
411
412StreamDescriptor::StreamDescriptor()
413    :   mIndexMin(0), mIndexMax(1), mCanBeMuted(true)
414{
415    mIndexCur.add(AUDIO_DEVICE_OUT_DEFAULT, 0);
416}
417
418int StreamDescriptor::getVolumeIndex(audio_devices_t device)
419{
420    device = ApmGains::getDeviceForVolume(device);
421    // there is always a valid entry for AUDIO_DEVICE_OUT_DEFAULT
422    if (mIndexCur.indexOfKey(device) < 0) {
423        device = AUDIO_DEVICE_OUT_DEFAULT;
424    }
425    return mIndexCur.valueFor(device);
426}
427
428void StreamDescriptor::dump(int fd)
429{
430    const size_t SIZE = 256;
431    char buffer[SIZE];
432    String8 result;
433
434    snprintf(buffer, SIZE, "%s         %02d         %02d         ",
435             mCanBeMuted ? "true " : "false", mIndexMin, mIndexMax);
436    result.append(buffer);
437    for (size_t i = 0; i < mIndexCur.size(); i++) {
438        snprintf(buffer, SIZE, "%04x : %02d, ",
439                 mIndexCur.keyAt(i),
440                 mIndexCur.valueAt(i));
441        result.append(buffer);
442    }
443    result.append("\n");
444
445    write(fd, result.string(), result.size());
446}
447
448}; // namespace android
449