François Gaffie | dfd7409 | 2015-03-19 12:10:59 +0100 | [diff] [blame] | 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 | #pragma once |
| 18 | |
François Gaffie | aaac0fd | 2018-11-22 17:56:39 +0100 | [diff] [blame] | 19 | #include <media/AudioCommonTypes.h> |
jiabin | 9a3361e | 2019-10-01 09:38:30 -0700 | [diff] [blame] | 20 | #include <media/AudioContainers.h> |
François Gaffie | dfd7409 | 2015-03-19 12:10:59 +0100 | [diff] [blame] | 21 | #include <system/audio.h> |
| 22 | #include <utils/Log.h> |
Eric Laurent | ffbc80f | 2015-03-18 18:30:19 -0700 | [diff] [blame] | 23 | #include <math.h> |
| 24 | |
jiabin | 4381040 | 2019-10-24 14:58:31 -0700 | [diff] [blame] | 25 | #include "policy.h" |
| 26 | |
François Gaffie | 1c87855 | 2018-11-22 16:53:21 +0100 | [diff] [blame] | 27 | namespace android { |
François Gaffie | 251c7f0 | 2018-11-07 10:41:08 +0100 | [diff] [blame] | 28 | |
François Gaffie | 1c87855 | 2018-11-22 16:53:21 +0100 | [diff] [blame] | 29 | /** |
| 30 | * VolumeSource is the discriminent for volume management on an output. |
| 31 | * It used to be the stream type by legacy, it may be host volume group or a volume curves if |
François Gaffie | aaac0fd | 2018-11-22 17:56:39 +0100 | [diff] [blame] | 32 | * we allow to have more than one curve per volume group (mandatory to get rid of AudioServer |
| 33 | * stream aliases. |
François Gaffie | 1c87855 | 2018-11-22 16:53:21 +0100 | [diff] [blame] | 34 | */ |
François Gaffie | aaac0fd | 2018-11-22 17:56:39 +0100 | [diff] [blame] | 35 | enum VolumeSource : std::underlying_type<volume_group_t>::type; |
| 36 | static const VolumeSource VOLUME_SOURCE_NONE = static_cast<VolumeSource>(VOLUME_GROUP_NONE); |
François Gaffie | 1c87855 | 2018-11-22 16:53:21 +0100 | [diff] [blame] | 37 | |
François Gaffie | 1c87855 | 2018-11-22 16:53:21 +0100 | [diff] [blame] | 38 | } // namespace android |
| 39 | |
Eric Laurent | ffbc80f | 2015-03-18 18:30:19 -0700 | [diff] [blame] | 40 | // Absolute min volume in dB (can be represented in single precision normal float value) |
| 41 | #define VOLUME_MIN_DB (-758) |
François Gaffie | dfd7409 | 2015-03-19 12:10:59 +0100 | [diff] [blame] | 42 | |
| 43 | class VolumeCurvePoint |
| 44 | { |
| 45 | public: |
| 46 | int mIndex; |
| 47 | float mDBAttenuation; |
| 48 | }; |
| 49 | |
François Gaffie | d0609ad | 2015-12-01 17:56:08 +0100 | [diff] [blame] | 50 | /** |
| 51 | * device categories used for volume curve management. |
| 52 | */ |
| 53 | enum device_category { |
| 54 | DEVICE_CATEGORY_HEADSET, |
| 55 | DEVICE_CATEGORY_SPEAKER, |
| 56 | DEVICE_CATEGORY_EARPIECE, |
| 57 | DEVICE_CATEGORY_EXT_MEDIA, |
Jakub Pawlowski | 24b0a89 | 2018-04-02 19:17:11 -0700 | [diff] [blame] | 58 | DEVICE_CATEGORY_HEARING_AID, |
François Gaffie | d0609ad | 2015-12-01 17:56:08 +0100 | [diff] [blame] | 59 | DEVICE_CATEGORY_CNT |
| 60 | }; |
| 61 | |
François Gaffie | dfd7409 | 2015-03-19 12:10:59 +0100 | [diff] [blame] | 62 | class Volume |
| 63 | { |
| 64 | public: |
| 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 Laurent | ffbc80f | 2015-03-18 18:30:19 -0700 | [diff] [blame] | 68 | * we use 100 steps to avoid rounding errors when computing the volume in volIndexToDb() |
François Gaffie | dfd7409 | 2015-03-19 12:10:59 +0100 | [diff] [blame] | 69 | * |
| 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 Gaffie | dfd7409 | 2015-03-19 12:10:59 +0100 | [diff] [blame] | 82 | * 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 | */ |
jiabin | 9a3361e | 2019-10-01 09:38:30 -0700 | [diff] [blame] | 88 | static audio_devices_t getDeviceForVolume(const android::DeviceTypeSet& deviceTypes) |
François Gaffie | dfd7409 | 2015-03-19 12:10:59 +0100 | [diff] [blame] | 89 | { |
jiabin | 9a3361e | 2019-10-01 09:38:30 -0700 | [diff] [blame] | 90 | if (deviceTypes.empty()) { |
François Gaffie | dfd7409 | 2015-03-19 12:10:59 +0100 | [diff] [blame] | 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. |
jiabin | 4381040 | 2019-10-24 14:58:31 -0700 | [diff] [blame] | 93 | return AUDIO_DEVICE_OUT_SPEAKER; |
François Gaffie | dfd7409 | 2015-03-19 12:10:59 +0100 | [diff] [blame] | 94 | } |
| 95 | |
jiabin | 4381040 | 2019-10-24 14:58:31 -0700 | [diff] [blame] | 96 | audio_devices_t deviceType = apm_extract_one_audio_device(deviceTypes); |
| 97 | |
François Gaffie | dfd7409 | 2015-03-19 12:10:59 +0100 | [diff] [blame] | 98 | /*SPEAKER_SAFE is an alias of SPEAKER for purposes of volume control*/ |
jiabin | 9a3361e | 2019-10-01 09:38:30 -0700 | [diff] [blame] | 99 | if (deviceType == AUDIO_DEVICE_OUT_SPEAKER_SAFE) { |
| 100 | deviceType = AUDIO_DEVICE_OUT_SPEAKER; |
| 101 | } |
François Gaffie | dfd7409 | 2015-03-19 12:10:59 +0100 | [diff] [blame] | 102 | |
jiabin | 9a3361e | 2019-10-01 09:38:30 -0700 | [diff] [blame] | 103 | ALOGW_IF(deviceType == AUDIO_DEVICE_NONE, |
| 104 | "getDeviceForVolume() invalid device combination: %s, returning AUDIO_DEVICE_NONE", |
| 105 | android::dumpDeviceTypes(deviceTypes).c_str()); |
François Gaffie | dfd7409 | 2015-03-19 12:10:59 +0100 | [diff] [blame] | 106 | |
jiabin | 9a3361e | 2019-10-01 09:38:30 -0700 | [diff] [blame] | 107 | return deviceType; |
François Gaffie | dfd7409 | 2015-03-19 12:10:59 +0100 | [diff] [blame] | 108 | } |
| 109 | |
| 110 | /** |
| 111 | * returns the category the device belongs to with regard to volume curve management |
| 112 | * |
| 113 | * @param[in] device to check upon the category to whom it belongs to. |
| 114 | * |
| 115 | * @return device category. |
| 116 | */ |
jiabin | 9a3361e | 2019-10-01 09:38:30 -0700 | [diff] [blame] | 117 | static device_category getDeviceCategory(const android::DeviceTypeSet& deviceTypes) |
François Gaffie | dfd7409 | 2015-03-19 12:10:59 +0100 | [diff] [blame] | 118 | { |
jiabin | 9a3361e | 2019-10-01 09:38:30 -0700 | [diff] [blame] | 119 | switch(getDeviceForVolume(deviceTypes)) { |
François Gaffie | dfd7409 | 2015-03-19 12:10:59 +0100 | [diff] [blame] | 120 | case AUDIO_DEVICE_OUT_EARPIECE: |
| 121 | return DEVICE_CATEGORY_EARPIECE; |
| 122 | case AUDIO_DEVICE_OUT_WIRED_HEADSET: |
| 123 | case AUDIO_DEVICE_OUT_WIRED_HEADPHONE: |
| 124 | case AUDIO_DEVICE_OUT_BLUETOOTH_SCO: |
| 125 | case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET: |
| 126 | case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP: |
| 127 | case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES: |
Eric Laurent | 904d632 | 2017-03-17 17:20:47 -0700 | [diff] [blame] | 128 | case AUDIO_DEVICE_OUT_USB_HEADSET: |
François Gaffie | dfd7409 | 2015-03-19 12:10:59 +0100 | [diff] [blame] | 129 | return DEVICE_CATEGORY_HEADSET; |
Jakub Pawlowski | 24b0a89 | 2018-04-02 19:17:11 -0700 | [diff] [blame] | 130 | case AUDIO_DEVICE_OUT_HEARING_AID: |
| 131 | return DEVICE_CATEGORY_HEARING_AID; |
François Gaffie | dfd7409 | 2015-03-19 12:10:59 +0100 | [diff] [blame] | 132 | case AUDIO_DEVICE_OUT_LINE: |
| 133 | case AUDIO_DEVICE_OUT_AUX_DIGITAL: |
Eric Laurent | 904d632 | 2017-03-17 17:20:47 -0700 | [diff] [blame] | 134 | case AUDIO_DEVICE_OUT_USB_DEVICE: |
François Gaffie | dfd7409 | 2015-03-19 12:10:59 +0100 | [diff] [blame] | 135 | return DEVICE_CATEGORY_EXT_MEDIA; |
| 136 | case AUDIO_DEVICE_OUT_SPEAKER: |
Jean-Michel Trivi | 227342a | 2018-09-14 11:42:37 -0700 | [diff] [blame] | 137 | case AUDIO_DEVICE_OUT_SPEAKER_SAFE: |
François Gaffie | dfd7409 | 2015-03-19 12:10:59 +0100 | [diff] [blame] | 138 | case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT: |
| 139 | case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER: |
| 140 | case AUDIO_DEVICE_OUT_USB_ACCESSORY: |
François Gaffie | dfd7409 | 2015-03-19 12:10:59 +0100 | [diff] [blame] | 141 | case AUDIO_DEVICE_OUT_REMOTE_SUBMIX: |
| 142 | default: |
| 143 | return DEVICE_CATEGORY_SPEAKER; |
| 144 | } |
| 145 | } |
| 146 | |
Eric Laurent | ffbc80f | 2015-03-18 18:30:19 -0700 | [diff] [blame] | 147 | static inline float DbToAmpl(float decibels) |
| 148 | { |
| 149 | if (decibels <= VOLUME_MIN_DB) { |
| 150 | return 0.0f; |
| 151 | } |
| 152 | return exp( decibels * 0.115129f); // exp( dB * ln(10) / 20 ) |
| 153 | } |
| 154 | |
| 155 | static inline float AmplToDb(float amplification) |
| 156 | { |
| 157 | if (amplification == 0) { |
| 158 | return VOLUME_MIN_DB; |
| 159 | } |
| 160 | return 20 * log10(amplification); |
| 161 | } |
| 162 | |
François Gaffie | dfd7409 | 2015-03-19 12:10:59 +0100 | [diff] [blame] | 163 | }; |