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