blob: 712f7a7ea09181b9408215c3dcd9020dbd9f6f5a [file] [log] [blame]
François Gaffiedfd74092015-03-19 12:10:59 +01001/*
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#pragma once
18
19#include <system/audio.h>
20#include <utils/Log.h>
Eric Laurentffbc80f2015-03-18 18:30:19 -070021#include <math.h>
22
23// Absolute min volume in dB (can be represented in single precision normal float value)
24#define VOLUME_MIN_DB (-758)
François Gaffiedfd74092015-03-19 12:10:59 +010025
26class VolumeCurvePoint
27{
28public:
29 int mIndex;
30 float mDBAttenuation;
31};
32
33class Volume
34{
35public:
36 /**
37 * 4 points to define the volume attenuation curve, each characterized by the volume
38 * index (from 0 to 100) at which they apply, and the attenuation in dB at that index.
Eric Laurentffbc80f2015-03-18 18:30:19 -070039 * we use 100 steps to avoid rounding errors when computing the volume in volIndexToDb()
François Gaffiedfd74092015-03-19 12:10:59 +010040 *
41 * @todo shall become configurable
42 */
43 enum {
44 VOLMIN = 0,
45 VOLKNEE1 = 1,
46 VOLKNEE2 = 2,
47 VOLMAX = 3,
48
49 VOLCNT = 4
50 };
51
52 /**
53 * device categories used for volume curve management.
54 */
55 enum device_category {
56 DEVICE_CATEGORY_HEADSET,
57 DEVICE_CATEGORY_SPEAKER,
58 DEVICE_CATEGORY_EARPIECE,
59 DEVICE_CATEGORY_EXT_MEDIA,
60 DEVICE_CATEGORY_CNT
61 };
62
63 /**
64 * extract one device relevant for volume control from multiple device selection
65 *
66 * @param[in] device for which the volume category is associated
67 *
68 * @return subset of device required to limit the number of volume category per device
69 */
70 static audio_devices_t getDeviceForVolume(audio_devices_t device)
71 {
72 if (device == AUDIO_DEVICE_NONE) {
73 // this happens when forcing a route update and no track is active on an output.
74 // In this case the returned category is not important.
75 device = AUDIO_DEVICE_OUT_SPEAKER;
76 } else if (popcount(device) > 1) {
77 // Multiple device selection is either:
78 // - speaker + one other device: give priority to speaker in this case.
79 // - one A2DP device + another device: happens with duplicated output. In this case
80 // retain the device on the A2DP output as the other must not correspond to an active
81 // selection if not the speaker.
82 // - HDMI-CEC system audio mode only output: give priority to available item in order.
83 if (device & AUDIO_DEVICE_OUT_SPEAKER) {
84 device = AUDIO_DEVICE_OUT_SPEAKER;
Eric Laurent9a7d9222015-07-02 15:30:23 -070085 } else if (device & AUDIO_DEVICE_OUT_SPEAKER_SAFE) {
86 device = AUDIO_DEVICE_OUT_SPEAKER_SAFE;
François Gaffiedfd74092015-03-19 12:10:59 +010087 } else if (device & AUDIO_DEVICE_OUT_HDMI_ARC) {
88 device = AUDIO_DEVICE_OUT_HDMI_ARC;
89 } else if (device & AUDIO_DEVICE_OUT_AUX_LINE) {
90 device = AUDIO_DEVICE_OUT_AUX_LINE;
91 } else if (device & AUDIO_DEVICE_OUT_SPDIF) {
92 device = AUDIO_DEVICE_OUT_SPDIF;
93 } else {
94 device = (audio_devices_t)(device & AUDIO_DEVICE_OUT_ALL_A2DP);
95 }
96 }
97
98 /*SPEAKER_SAFE is an alias of SPEAKER for purposes of volume control*/
99 if (device == AUDIO_DEVICE_OUT_SPEAKER_SAFE)
100 device = AUDIO_DEVICE_OUT_SPEAKER;
101
102 ALOGW_IF(popcount(device) != 1,
103 "getDeviceForVolume() invalid device combination: %08x",
104 device);
105
106 return device;
107 }
108
109 /**
110 * returns the category the device belongs to with regard to volume curve management
111 *
112 * @param[in] device to check upon the category to whom it belongs to.
113 *
114 * @return device category.
115 */
116 static device_category getDeviceCategory(audio_devices_t device)
117 {
118 switch(getDeviceForVolume(device)) {
119 case AUDIO_DEVICE_OUT_EARPIECE:
120 return DEVICE_CATEGORY_EARPIECE;
121 case AUDIO_DEVICE_OUT_WIRED_HEADSET:
122 case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
123 case AUDIO_DEVICE_OUT_BLUETOOTH_SCO:
124 case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
125 case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP:
126 case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
127 return DEVICE_CATEGORY_HEADSET;
128 case AUDIO_DEVICE_OUT_LINE:
129 case AUDIO_DEVICE_OUT_AUX_DIGITAL:
130 /*USB? Remote submix?*/
131 return DEVICE_CATEGORY_EXT_MEDIA;
132 case AUDIO_DEVICE_OUT_SPEAKER:
133 case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
134 case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER:
135 case AUDIO_DEVICE_OUT_USB_ACCESSORY:
136 case AUDIO_DEVICE_OUT_USB_DEVICE:
137 case AUDIO_DEVICE_OUT_REMOTE_SUBMIX:
138 default:
139 return DEVICE_CATEGORY_SPEAKER;
140 }
141 }
142
Eric Laurentffbc80f2015-03-18 18:30:19 -0700143 static inline float DbToAmpl(float decibels)
144 {
145 if (decibels <= VOLUME_MIN_DB) {
146 return 0.0f;
147 }
148 return exp( decibels * 0.115129f); // exp( dB * ln(10) / 20 )
149 }
150
151 static inline float AmplToDb(float amplification)
152 {
153 if (amplification == 0) {
154 return VOLUME_MIN_DB;
155 }
156 return 20 * log10(amplification);
157 }
158
François Gaffiedfd74092015-03-19 12:10:59 +0100159};