Home | History | Annotate | Download | only in include
      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      */
     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      */
    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 
    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 
    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