blob: 48b5271932e76998c9d03b1b72376f732bac1a1d [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
François Gaffie1c878552018-11-22 16:53:21 +010023namespace android {
François Gaffie251c7f02018-11-07 10:41:08 +010024
François Gaffie1c878552018-11-22 16:53:21 +010025/**
26 * VolumeSource is the discriminent for volume management on an output.
27 * It used to be the stream type by legacy, it may be host volume group or a volume curves if
28 * we allow to have more than one curve per volume group.
29 */
30enum VolumeSource : std::underlying_type<audio_stream_type_t>::type;
31static const VolumeSource VOLUME_SOURCE_NONE = static_cast<VolumeSource>(AUDIO_STREAM_DEFAULT);
32
33static inline VolumeSource streamToVolumeSource(audio_stream_type_t stream) {
34 return static_cast<VolumeSource>(stream);
35}
36
37
38} // namespace android
39
Eric Laurentffbc80f2015-03-18 18:30:19 -070040// Absolute min volume in dB (can be represented in single precision normal float value)
41#define VOLUME_MIN_DB (-758)
François Gaffiedfd74092015-03-19 12:10:59 +010042
43class VolumeCurvePoint
44{
45public:
46 int mIndex;
47 float mDBAttenuation;
48};
49
François Gaffied0609ad2015-12-01 17:56:08 +010050/**
51 * device categories used for volume curve management.
52 */
53enum device_category {
54 DEVICE_CATEGORY_HEADSET,
55 DEVICE_CATEGORY_SPEAKER,
56 DEVICE_CATEGORY_EARPIECE,
57 DEVICE_CATEGORY_EXT_MEDIA,
Jakub Pawlowski24b0a892018-04-02 19:17:11 -070058 DEVICE_CATEGORY_HEARING_AID,
François Gaffied0609ad2015-12-01 17:56:08 +010059 DEVICE_CATEGORY_CNT
60};
61
François Gaffiedfd74092015-03-19 12:10:59 +010062class Volume
63{
64public:
65 /**
66 * 4 points to define the volume attenuation curve, each characterized by the volume
67 * index (from 0 to 100) at which they apply, and the attenuation in dB at that index.
Eric Laurentffbc80f2015-03-18 18:30:19 -070068 * we use 100 steps to avoid rounding errors when computing the volume in volIndexToDb()
François Gaffiedfd74092015-03-19 12:10:59 +010069 *
70 * @todo shall become configurable
71 */
72 enum {
73 VOLMIN = 0,
74 VOLKNEE1 = 1,
75 VOLKNEE2 = 2,
76 VOLMAX = 3,
77
78 VOLCNT = 4
79 };
80
81 /**
François Gaffiedfd74092015-03-19 12:10:59 +010082 * extract one device relevant for volume control from multiple device selection
83 *
84 * @param[in] device for which the volume category is associated
85 *
86 * @return subset of device required to limit the number of volume category per device
87 */
88 static audio_devices_t getDeviceForVolume(audio_devices_t device)
89 {
90 if (device == AUDIO_DEVICE_NONE) {
91 // this happens when forcing a route update and no track is active on an output.
92 // In this case the returned category is not important.
93 device = AUDIO_DEVICE_OUT_SPEAKER;
94 } else if (popcount(device) > 1) {
95 // Multiple device selection is either:
96 // - speaker + one other device: give priority to speaker in this case.
97 // - one A2DP device + another device: happens with duplicated output. In this case
98 // retain the device on the A2DP output as the other must not correspond to an active
99 // selection if not the speaker.
100 // - HDMI-CEC system audio mode only output: give priority to available item in order.
101 if (device & AUDIO_DEVICE_OUT_SPEAKER) {
102 device = AUDIO_DEVICE_OUT_SPEAKER;
Eric Laurent9a7d9222015-07-02 15:30:23 -0700103 } else if (device & AUDIO_DEVICE_OUT_SPEAKER_SAFE) {
104 device = AUDIO_DEVICE_OUT_SPEAKER_SAFE;
François Gaffiedfd74092015-03-19 12:10:59 +0100105 } else if (device & AUDIO_DEVICE_OUT_HDMI_ARC) {
106 device = AUDIO_DEVICE_OUT_HDMI_ARC;
107 } else if (device & AUDIO_DEVICE_OUT_AUX_LINE) {
108 device = AUDIO_DEVICE_OUT_AUX_LINE;
109 } else if (device & AUDIO_DEVICE_OUT_SPDIF) {
110 device = AUDIO_DEVICE_OUT_SPDIF;
111 } else {
112 device = (audio_devices_t)(device & AUDIO_DEVICE_OUT_ALL_A2DP);
113 }
114 }
115
116 /*SPEAKER_SAFE is an alias of SPEAKER for purposes of volume control*/
117 if (device == AUDIO_DEVICE_OUT_SPEAKER_SAFE)
118 device = AUDIO_DEVICE_OUT_SPEAKER;
119
120 ALOGW_IF(popcount(device) != 1,
121 "getDeviceForVolume() invalid device combination: %08x",
122 device);
123
124 return device;
125 }
126
127 /**
128 * returns the category the device belongs to with regard to volume curve management
129 *
130 * @param[in] device to check upon the category to whom it belongs to.
131 *
132 * @return device category.
133 */
134 static device_category getDeviceCategory(audio_devices_t device)
135 {
136 switch(getDeviceForVolume(device)) {
137 case AUDIO_DEVICE_OUT_EARPIECE:
138 return DEVICE_CATEGORY_EARPIECE;
139 case AUDIO_DEVICE_OUT_WIRED_HEADSET:
140 case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
141 case AUDIO_DEVICE_OUT_BLUETOOTH_SCO:
142 case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
143 case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP:
144 case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
Eric Laurent904d6322017-03-17 17:20:47 -0700145 case AUDIO_DEVICE_OUT_USB_HEADSET:
François Gaffiedfd74092015-03-19 12:10:59 +0100146 return DEVICE_CATEGORY_HEADSET;
Jakub Pawlowski24b0a892018-04-02 19:17:11 -0700147 case AUDIO_DEVICE_OUT_HEARING_AID:
148 return DEVICE_CATEGORY_HEARING_AID;
François Gaffiedfd74092015-03-19 12:10:59 +0100149 case AUDIO_DEVICE_OUT_LINE:
150 case AUDIO_DEVICE_OUT_AUX_DIGITAL:
Eric Laurent904d6322017-03-17 17:20:47 -0700151 case AUDIO_DEVICE_OUT_USB_DEVICE:
François Gaffiedfd74092015-03-19 12:10:59 +0100152 return DEVICE_CATEGORY_EXT_MEDIA;
153 case AUDIO_DEVICE_OUT_SPEAKER:
Jean-Michel Trivi227342a2018-09-14 11:42:37 -0700154 case AUDIO_DEVICE_OUT_SPEAKER_SAFE:
François Gaffiedfd74092015-03-19 12:10:59 +0100155 case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
156 case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER:
157 case AUDIO_DEVICE_OUT_USB_ACCESSORY:
François Gaffiedfd74092015-03-19 12:10:59 +0100158 case AUDIO_DEVICE_OUT_REMOTE_SUBMIX:
159 default:
160 return DEVICE_CATEGORY_SPEAKER;
161 }
162 }
163
Eric Laurentffbc80f2015-03-18 18:30:19 -0700164 static inline float DbToAmpl(float decibels)
165 {
166 if (decibels <= VOLUME_MIN_DB) {
167 return 0.0f;
168 }
169 return exp( decibels * 0.115129f); // exp( dB * ln(10) / 20 )
170 }
171
172 static inline float AmplToDb(float amplification)
173 {
174 if (amplification == 0) {
175 return VOLUME_MIN_DB;
176 }
177 return 20 * log10(amplification);
178 }
179
François Gaffiedfd74092015-03-19 12:10:59 +0100180};