blob: c3a02f9d202d1a6c955b1ac30effa435e92a6161 [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
François Gaffieaaac0fd2018-11-22 17:56:39 +010019#include <media/AudioCommonTypes.h>
jiabin9a3361e2019-10-01 09:38:30 -070020#include <media/AudioContainers.h>
François Gaffiedfd74092015-03-19 12:10:59 +010021#include <system/audio.h>
22#include <utils/Log.h>
Eric Laurentffbc80f2015-03-18 18:30:19 -070023#include <math.h>
24
François Gaffie1c878552018-11-22 16:53:21 +010025namespace android {
François Gaffie251c7f02018-11-07 10:41:08 +010026
François Gaffie1c878552018-11-22 16:53:21 +010027/**
28 * VolumeSource is the discriminent for volume management on an output.
29 * It used to be the stream type by legacy, it may be host volume group or a volume curves if
François Gaffieaaac0fd2018-11-22 17:56:39 +010030 * we allow to have more than one curve per volume group (mandatory to get rid of AudioServer
31 * stream aliases.
François Gaffie1c878552018-11-22 16:53:21 +010032 */
François Gaffieaaac0fd2018-11-22 17:56:39 +010033enum VolumeSource : std::underlying_type<volume_group_t>::type;
34static const VolumeSource VOLUME_SOURCE_NONE = static_cast<VolumeSource>(VOLUME_GROUP_NONE);
François Gaffie1c878552018-11-22 16:53:21 +010035
François Gaffie1c878552018-11-22 16:53:21 +010036} // namespace android
37
Eric Laurentffbc80f2015-03-18 18:30:19 -070038// Absolute min volume in dB (can be represented in single precision normal float value)
39#define VOLUME_MIN_DB (-758)
François Gaffiedfd74092015-03-19 12:10:59 +010040
41class VolumeCurvePoint
42{
43public:
44 int mIndex;
45 float mDBAttenuation;
46};
47
François Gaffied0609ad2015-12-01 17:56:08 +010048/**
49 * device categories used for volume curve management.
50 */
51enum device_category {
52 DEVICE_CATEGORY_HEADSET,
53 DEVICE_CATEGORY_SPEAKER,
54 DEVICE_CATEGORY_EARPIECE,
55 DEVICE_CATEGORY_EXT_MEDIA,
Jakub Pawlowski24b0a892018-04-02 19:17:11 -070056 DEVICE_CATEGORY_HEARING_AID,
François Gaffied0609ad2015-12-01 17:56:08 +010057 DEVICE_CATEGORY_CNT
58};
59
François Gaffiedfd74092015-03-19 12:10:59 +010060class Volume
61{
62public:
63 /**
64 * 4 points to define the volume attenuation curve, each characterized by the volume
65 * index (from 0 to 100) at which they apply, and the attenuation in dB at that index.
Eric Laurentffbc80f2015-03-18 18:30:19 -070066 * we use 100 steps to avoid rounding errors when computing the volume in volIndexToDb()
François Gaffiedfd74092015-03-19 12:10:59 +010067 *
68 * @todo shall become configurable
69 */
70 enum {
71 VOLMIN = 0,
72 VOLKNEE1 = 1,
73 VOLKNEE2 = 2,
74 VOLMAX = 3,
75
76 VOLCNT = 4
77 };
78
79 /**
François Gaffiedfd74092015-03-19 12:10:59 +010080 * extract one device relevant for volume control from multiple device selection
81 *
82 * @param[in] device for which the volume category is associated
83 *
84 * @return subset of device required to limit the number of volume category per device
85 */
jiabin9a3361e2019-10-01 09:38:30 -070086 static audio_devices_t getDeviceForVolume(const android::DeviceTypeSet& deviceTypes)
François Gaffiedfd74092015-03-19 12:10:59 +010087 {
jiabin9a3361e2019-10-01 09:38:30 -070088 audio_devices_t deviceType = AUDIO_DEVICE_NONE;
89 if (deviceTypes.empty()) {
François Gaffiedfd74092015-03-19 12:10:59 +010090 // this happens when forcing a route update and no track is active on an output.
91 // In this case the returned category is not important.
jiabin9a3361e2019-10-01 09:38:30 -070092 deviceType = AUDIO_DEVICE_OUT_SPEAKER;
93 } else if (deviceTypes.size() > 1) {
François Gaffiedfd74092015-03-19 12:10:59 +010094 // Multiple device selection is either:
95 // - speaker + one other device: give priority to speaker in this case.
96 // - one A2DP device + another device: happens with duplicated output. In this case
97 // retain the device on the A2DP output as the other must not correspond to an active
98 // selection if not the speaker.
99 // - HDMI-CEC system audio mode only output: give priority to available item in order.
jiabin9a3361e2019-10-01 09:38:30 -0700100 if (deviceTypes.count(AUDIO_DEVICE_OUT_SPEAKER) != 0) {
101 deviceType = AUDIO_DEVICE_OUT_SPEAKER;
102 } else if (deviceTypes.count(AUDIO_DEVICE_OUT_SPEAKER_SAFE) != 0) {
103 deviceType = AUDIO_DEVICE_OUT_SPEAKER_SAFE;
104 } else if (deviceTypes.count(AUDIO_DEVICE_OUT_HDMI_ARC) != 0) {
105 deviceType = AUDIO_DEVICE_OUT_HDMI_ARC;
106 } else if (deviceTypes.count(AUDIO_DEVICE_OUT_AUX_LINE) != 0) {
107 deviceType = AUDIO_DEVICE_OUT_AUX_LINE;
108 } else if (deviceTypes.count(AUDIO_DEVICE_OUT_SPDIF) != 0) {
109 deviceType = AUDIO_DEVICE_OUT_SPDIF;
François Gaffiedfd74092015-03-19 12:10:59 +0100110 } else {
jiabin9a3361e2019-10-01 09:38:30 -0700111 std::vector<audio_devices_t> a2dpDevices = android::Intersection(
112 deviceTypes, android::getAudioDeviceOutAllA2dpSet());
113 if (a2dpDevices.size() > 1) {
114 ALOGW("getDeviceForVolume() invalid device combination: %s",
115 android::dumpDeviceTypes(deviceTypes).c_str());
116 }
117 if (!a2dpDevices.empty()) {
118 deviceType = a2dpDevices[0];
119 }
François Gaffiedfd74092015-03-19 12:10:59 +0100120 }
jiabin9a3361e2019-10-01 09:38:30 -0700121 } else {
122 deviceType = *(deviceTypes.begin());
François Gaffiedfd74092015-03-19 12:10:59 +0100123 }
124
125 /*SPEAKER_SAFE is an alias of SPEAKER for purposes of volume control*/
jiabin9a3361e2019-10-01 09:38:30 -0700126 if (deviceType == AUDIO_DEVICE_OUT_SPEAKER_SAFE) {
127 deviceType = AUDIO_DEVICE_OUT_SPEAKER;
128 }
François Gaffiedfd74092015-03-19 12:10:59 +0100129
jiabin9a3361e2019-10-01 09:38:30 -0700130 ALOGW_IF(deviceType == AUDIO_DEVICE_NONE,
131 "getDeviceForVolume() invalid device combination: %s, returning AUDIO_DEVICE_NONE",
132 android::dumpDeviceTypes(deviceTypes).c_str());
François Gaffiedfd74092015-03-19 12:10:59 +0100133
jiabin9a3361e2019-10-01 09:38:30 -0700134 return deviceType;
François Gaffiedfd74092015-03-19 12:10:59 +0100135 }
136
137 /**
138 * returns the category the device belongs to with regard to volume curve management
139 *
140 * @param[in] device to check upon the category to whom it belongs to.
141 *
142 * @return device category.
143 */
jiabin9a3361e2019-10-01 09:38:30 -0700144 static device_category getDeviceCategory(const android::DeviceTypeSet& deviceTypes)
François Gaffiedfd74092015-03-19 12:10:59 +0100145 {
jiabin9a3361e2019-10-01 09:38:30 -0700146 switch(getDeviceForVolume(deviceTypes)) {
François Gaffiedfd74092015-03-19 12:10:59 +0100147 case AUDIO_DEVICE_OUT_EARPIECE:
148 return DEVICE_CATEGORY_EARPIECE;
149 case AUDIO_DEVICE_OUT_WIRED_HEADSET:
150 case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
151 case AUDIO_DEVICE_OUT_BLUETOOTH_SCO:
152 case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
153 case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP:
154 case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
Eric Laurent904d6322017-03-17 17:20:47 -0700155 case AUDIO_DEVICE_OUT_USB_HEADSET:
François Gaffiedfd74092015-03-19 12:10:59 +0100156 return DEVICE_CATEGORY_HEADSET;
Jakub Pawlowski24b0a892018-04-02 19:17:11 -0700157 case AUDIO_DEVICE_OUT_HEARING_AID:
158 return DEVICE_CATEGORY_HEARING_AID;
François Gaffiedfd74092015-03-19 12:10:59 +0100159 case AUDIO_DEVICE_OUT_LINE:
160 case AUDIO_DEVICE_OUT_AUX_DIGITAL:
Eric Laurent904d6322017-03-17 17:20:47 -0700161 case AUDIO_DEVICE_OUT_USB_DEVICE:
François Gaffiedfd74092015-03-19 12:10:59 +0100162 return DEVICE_CATEGORY_EXT_MEDIA;
163 case AUDIO_DEVICE_OUT_SPEAKER:
Jean-Michel Trivi227342a2018-09-14 11:42:37 -0700164 case AUDIO_DEVICE_OUT_SPEAKER_SAFE:
François Gaffiedfd74092015-03-19 12:10:59 +0100165 case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
166 case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER:
167 case AUDIO_DEVICE_OUT_USB_ACCESSORY:
François Gaffiedfd74092015-03-19 12:10:59 +0100168 case AUDIO_DEVICE_OUT_REMOTE_SUBMIX:
169 default:
170 return DEVICE_CATEGORY_SPEAKER;
171 }
172 }
173
Eric Laurentffbc80f2015-03-18 18:30:19 -0700174 static inline float DbToAmpl(float decibels)
175 {
176 if (decibels <= VOLUME_MIN_DB) {
177 return 0.0f;
178 }
179 return exp( decibels * 0.115129f); // exp( dB * ln(10) / 20 )
180 }
181
182 static inline float AmplToDb(float amplification)
183 {
184 if (amplification == 0) {
185 return VOLUME_MIN_DB;
186 }
187 return 20 * log10(amplification);
188 }
189
François Gaffiedfd74092015-03-19 12:10:59 +0100190};