1dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie/*
2dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie * Copyright (C) 2015 The Android Open Source Project
3dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie *
4dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie * Licensed under the Apache License, Version 2.0 (the "License");
5dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie * you may not use this file except in compliance with the License.
6dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie * You may obtain a copy of the License at
7dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie *
8dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie *      http://www.apache.org/licenses/LICENSE-2.0
9dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie *
10dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie * Unless required by applicable law or agreed to in writing, software
11dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie * distributed under the License is distributed on an "AS IS" BASIS,
12dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie * See the License for the specific language governing permissions and
14dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie * limitations under the License.
15dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie */
16dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie
17dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie#pragma once
18dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie
19dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie#include <system/audio.h>
20dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie#include <utils/Log.h>
21ffbc80f5908eaf67a033c6e93a343c39dd6894ebEric Laurent#include <math.h>
22ffbc80f5908eaf67a033c6e93a343c39dd6894ebEric Laurent
23ffbc80f5908eaf67a033c6e93a343c39dd6894ebEric Laurent// Absolute min volume in dB (can be represented in single precision normal float value)
24ffbc80f5908eaf67a033c6e93a343c39dd6894ebEric Laurent#define VOLUME_MIN_DB (-758)
25dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie
26dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffieclass VolumeCurvePoint
27dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie{
28dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffiepublic:
29dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie    int mIndex;
30dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie    float mDBAttenuation;
31dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie};
32dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie
33d0609ad390ff8bb1cafebdf363bf1d15e63b949fFrançois Gaffie/**
34d0609ad390ff8bb1cafebdf363bf1d15e63b949fFrançois Gaffie * device categories used for volume curve management.
35d0609ad390ff8bb1cafebdf363bf1d15e63b949fFrançois Gaffie */
36d0609ad390ff8bb1cafebdf363bf1d15e63b949fFrançois Gaffieenum device_category {
37d0609ad390ff8bb1cafebdf363bf1d15e63b949fFrançois Gaffie    DEVICE_CATEGORY_HEADSET,
38d0609ad390ff8bb1cafebdf363bf1d15e63b949fFrançois Gaffie    DEVICE_CATEGORY_SPEAKER,
39d0609ad390ff8bb1cafebdf363bf1d15e63b949fFrançois Gaffie    DEVICE_CATEGORY_EARPIECE,
40d0609ad390ff8bb1cafebdf363bf1d15e63b949fFrançois Gaffie    DEVICE_CATEGORY_EXT_MEDIA,
41d0609ad390ff8bb1cafebdf363bf1d15e63b949fFrançois Gaffie    DEVICE_CATEGORY_CNT
42d0609ad390ff8bb1cafebdf363bf1d15e63b949fFrançois Gaffie};
43d0609ad390ff8bb1cafebdf363bf1d15e63b949fFrançois Gaffie
44dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffieclass Volume
45dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie{
46dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffiepublic:
47dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie    /**
48dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie     * 4 points to define the volume attenuation curve, each characterized by the volume
49dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie     * index (from 0 to 100) at which they apply, and the attenuation in dB at that index.
50ffbc80f5908eaf67a033c6e93a343c39dd6894ebEric Laurent     * we use 100 steps to avoid rounding errors when computing the volume in volIndexToDb()
51dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie     *
52dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie     * @todo shall become configurable
53dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie     */
54dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie    enum {
55dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie        VOLMIN = 0,
56dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie        VOLKNEE1 = 1,
57dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie        VOLKNEE2 = 2,
58dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie        VOLMAX = 3,
59dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie
60dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie        VOLCNT = 4
61dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie    };
62dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie
63dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie    /**
64dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie     * extract one device relevant for volume control from multiple device selection
65dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie     *
66dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie     * @param[in] device for which the volume category is associated
67dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie     *
68dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie     * @return subset of device required to limit the number of volume category per device
69dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie     */
70dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie    static audio_devices_t getDeviceForVolume(audio_devices_t device)
71dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie    {
72dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie        if (device == AUDIO_DEVICE_NONE) {
73dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie            // this happens when forcing a route update and no track is active on an output.
74dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie            // In this case the returned category is not important.
75dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie            device =  AUDIO_DEVICE_OUT_SPEAKER;
76dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie        } else if (popcount(device) > 1) {
77dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie            // Multiple device selection is either:
78dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie            //  - speaker + one other device: give priority to speaker in this case.
79dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie            //  - one A2DP device + another device: happens with duplicated output. In this case
80dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie            // retain the device on the A2DP output as the other must not correspond to an active
81dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie            // selection if not the speaker.
82dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie            //  - HDMI-CEC system audio mode only output: give priority to available item in order.
83dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie            if (device & AUDIO_DEVICE_OUT_SPEAKER) {
84dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie                device = AUDIO_DEVICE_OUT_SPEAKER;
859a7d922796c61353e30cea5878f41b921adc79b0Eric Laurent            } else if (device & AUDIO_DEVICE_OUT_SPEAKER_SAFE) {
869a7d922796c61353e30cea5878f41b921adc79b0Eric Laurent                device = AUDIO_DEVICE_OUT_SPEAKER_SAFE;
87dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie            } else if (device & AUDIO_DEVICE_OUT_HDMI_ARC) {
88dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie                device = AUDIO_DEVICE_OUT_HDMI_ARC;
89dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie            } else if (device & AUDIO_DEVICE_OUT_AUX_LINE) {
90dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie                device = AUDIO_DEVICE_OUT_AUX_LINE;
91dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie            } else if (device & AUDIO_DEVICE_OUT_SPDIF) {
92dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie                device = AUDIO_DEVICE_OUT_SPDIF;
93dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie            } else {
94dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie                device = (audio_devices_t)(device & AUDIO_DEVICE_OUT_ALL_A2DP);
95dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie            }
96dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie        }
97dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie
98dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie        /*SPEAKER_SAFE is an alias of SPEAKER for purposes of volume control*/
99dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie        if (device == AUDIO_DEVICE_OUT_SPEAKER_SAFE)
100dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie            device = AUDIO_DEVICE_OUT_SPEAKER;
101dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie
102dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie        ALOGW_IF(popcount(device) != 1,
103dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie                 "getDeviceForVolume() invalid device combination: %08x",
104dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie                 device);
105dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie
106dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie        return device;
107dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie    }
108dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie
109dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie    /**
110dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie     * returns the category the device belongs to with regard to volume curve management
111dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie     *
112dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie     * @param[in] device to check upon the category to whom it belongs to.
113dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie     *
114dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie     * @return device category.
115dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie     */
116dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie    static device_category getDeviceCategory(audio_devices_t device)
117dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie    {
118dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie        switch(getDeviceForVolume(device)) {
119dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie        case AUDIO_DEVICE_OUT_EARPIECE:
120dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie            return DEVICE_CATEGORY_EARPIECE;
121dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie        case AUDIO_DEVICE_OUT_WIRED_HEADSET:
122dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie        case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
123dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie        case AUDIO_DEVICE_OUT_BLUETOOTH_SCO:
124dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie        case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
125dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie        case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP:
126dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie        case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
127dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie            return DEVICE_CATEGORY_HEADSET;
128dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie        case AUDIO_DEVICE_OUT_LINE:
129dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie        case AUDIO_DEVICE_OUT_AUX_DIGITAL:
130dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie            /*USB?  Remote submix?*/
131dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie            return DEVICE_CATEGORY_EXT_MEDIA;
132dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie        case AUDIO_DEVICE_OUT_SPEAKER:
133dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie        case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
134dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie        case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER:
135dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie        case AUDIO_DEVICE_OUT_USB_ACCESSORY:
136dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie        case AUDIO_DEVICE_OUT_USB_DEVICE:
137dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie        case AUDIO_DEVICE_OUT_REMOTE_SUBMIX:
138dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie        default:
139dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie            return DEVICE_CATEGORY_SPEAKER;
140dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie        }
141dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie    }
142dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie
143ffbc80f5908eaf67a033c6e93a343c39dd6894ebEric Laurent    static inline float DbToAmpl(float decibels)
144ffbc80f5908eaf67a033c6e93a343c39dd6894ebEric Laurent    {
145ffbc80f5908eaf67a033c6e93a343c39dd6894ebEric Laurent        if (decibels <= VOLUME_MIN_DB) {
146ffbc80f5908eaf67a033c6e93a343c39dd6894ebEric Laurent            return 0.0f;
147ffbc80f5908eaf67a033c6e93a343c39dd6894ebEric Laurent        }
148ffbc80f5908eaf67a033c6e93a343c39dd6894ebEric Laurent        return exp( decibels * 0.115129f); // exp( dB * ln(10) / 20 )
149ffbc80f5908eaf67a033c6e93a343c39dd6894ebEric Laurent    }
150ffbc80f5908eaf67a033c6e93a343c39dd6894ebEric Laurent
151ffbc80f5908eaf67a033c6e93a343c39dd6894ebEric Laurent    static inline float AmplToDb(float amplification)
152ffbc80f5908eaf67a033c6e93a343c39dd6894ebEric Laurent    {
153ffbc80f5908eaf67a033c6e93a343c39dd6894ebEric Laurent        if (amplification == 0) {
154ffbc80f5908eaf67a033c6e93a343c39dd6894ebEric Laurent            return VOLUME_MIN_DB;
155ffbc80f5908eaf67a033c6e93a343c39dd6894ebEric Laurent        }
156ffbc80f5908eaf67a033c6e93a343c39dd6894ebEric Laurent        return 20 * log10(amplification);
157ffbc80f5908eaf67a033c6e93a343c39dd6894ebEric Laurent    }
158ffbc80f5908eaf67a033c6e93a343c39dd6894ebEric Laurent
159dfd7409c1b708f6c429aa43722ca8493a91d8df0François Gaffie};
160