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