1/*
2 * Copyright (C) 2009 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#define LOG_TAG "AudioPolicyManager"
18//#define LOG_NDEBUG 0
19#include <utils/Log.h>
20#include "AudioPolicyManager.h"
21#include <media/mediarecorder.h>
22
23namespace android {
24
25
26// Max volume for streams when playing over bluetooth SCO device while in call: -18dB
27#define IN_CALL_SCO_VOLUME_MAX  0.126
28// Min music volume for 3.5mm jack in car dock: -10dB
29#define CAR_DOCK_MUSIC_MINI_JACK_VOLUME_MIN 0.316
30
31// ----------------------------------------------------------------------------
32// AudioPolicyManager implementation for qsd8k platform
33// Common audio policy manager code is implemented in AudioPolicyManagerBase class
34// ----------------------------------------------------------------------------
35
36// ---  class factory
37
38
39extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface)
40{
41    return new AudioPolicyManager(clientInterface);
42}
43
44extern "C" void destroyAudioPolicyManager(AudioPolicyInterface *interface)
45{
46    delete interface;
47}
48
49// ---
50
51
52uint32_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strategy, bool fromCache)
53{
54    uint32_t device = 0;
55
56    if (fromCache) {
57        device = mDeviceForStrategy[strategy];
58        ALOGV("getDeviceForStrategy() from cache strategy %d, device %x", strategy, device);
59        return device;
60    }
61
62    switch (strategy) {
63    case STRATEGY_DTMF:
64        if (mPhoneState != AudioSystem::MODE_IN_CALL) {
65            // when off call, DTMF strategy follows the same rules as MEDIA strategy
66            device = getDeviceForStrategy(STRATEGY_MEDIA, false);
67            break;
68        }
69        // when in call, DTMF and PHONE strategies follow the same rules
70        // FALL THROUGH
71
72    case STRATEGY_PHONE:
73        // for phone strategy, we first consider the forced use and then the available devices by order
74        // of priority
75        switch (mForceUse[AudioSystem::FOR_COMMUNICATION]) {
76        case AudioSystem::FORCE_BT_SCO:
77            if (mPhoneState != AudioSystem::MODE_IN_CALL || strategy != STRATEGY_DTMF) {
78                device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
79                if (device) break;
80            }
81            // otherwise (not docked) continue with selection
82            device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
83            if (device) break;
84            device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO;
85            if (device) break;
86            // if SCO device is requested but no SCO device is available, fall back to default case
87            // FALL THROUGH
88
89        default:    // FORCE_NONE
90            device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE;
91            if (device) break;
92            device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET;
93            if (device) break;
94            // when not in call:
95            if (mPhoneState != AudioSystem::MODE_IN_CALL) {
96                // - if we are docked to a BT CAR dock, give A2DP preference over earpiece
97                // - if we are docked to a BT DESK dock, give speaker preference over earpiece
98                if (mForceUse[AudioSystem::FOR_DOCK] == AudioSystem::FORCE_BT_CAR_DOCK) {
99                    device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP;
100                } else if (mForceUse[AudioSystem::FOR_DOCK] == AudioSystem::FORCE_BT_DESK_DOCK) {
101                    device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER;
102                }
103                if (device) break;
104                // - phone strategy should route STREAM_VOICE_CALL to A2DP
105                device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP;
106                if (device) break;
107                device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
108                if (device) break;
109            }
110            device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_EARPIECE;
111            if (device == 0) {
112                ALOGE("getDeviceForStrategy() earpiece device not found");
113            }
114            break;
115
116        case AudioSystem::FORCE_SPEAKER:
117            if (mPhoneState != AudioSystem::MODE_IN_CALL || strategy != STRATEGY_DTMF) {
118                device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
119                if (device) break;
120            }
121            // when not in call:
122            if (mPhoneState != AudioSystem::MODE_IN_CALL) {
123                // - if we are docked to a BT CAR dock, give A2DP preference over phone spkr
124                if (mForceUse[AudioSystem::FOR_DOCK] == AudioSystem::FORCE_BT_CAR_DOCK) {
125                    device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP;
126                    if (device) break;
127                }
128                // - phone strategy should route STREAM_VOICE_CALL to A2DP speaker
129                //   when forcing to speaker output
130                device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
131                if (device) break;
132            }
133            device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER;
134            if (device == 0) {
135                ALOGE("getDeviceForStrategy() speaker device not found");
136            }
137            break;
138        }
139    break;
140
141    case STRATEGY_SONIFICATION:
142
143        // If incall, just select the STRATEGY_PHONE device: The rest of the behavior is handled by
144        // handleIncallSonification().
145        if (mPhoneState == AudioSystem::MODE_IN_CALL) {
146            device = getDeviceForStrategy(STRATEGY_PHONE, false);
147            break;
148        }
149        // If not incall:
150        // - if we are docked to a BT CAR dock, don't duplicate for the sonification strategy
151        // - if we are docked to a BT DESK dock, use only speaker for the sonification strategy
152        if (mForceUse[AudioSystem::FOR_DOCK] != AudioSystem::FORCE_BT_CAR_DOCK) {
153            device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER;
154            if (device == 0) {
155                ALOGE("getDeviceForStrategy() speaker device not found");
156            }
157            if (mForceUse[AudioSystem::FOR_DOCK] == AudioSystem::FORCE_BT_DESK_DOCK) {
158                if (mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE) {
159                    device |= AudioSystem::DEVICE_OUT_WIRED_HEADPHONE;
160                } else if (mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET) {
161                    device |= AudioSystem::DEVICE_OUT_WIRED_HEADSET;
162                }
163                break;
164            }
165        } else {
166            device = 0;
167        }
168        // The second device used for sonification is the same as the device used by media strategy
169        // Note that when docked, we pick the device below (no duplication)
170        // FALL THROUGH
171
172    case STRATEGY_MEDIA: {
173        uint32_t device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_AUX_DIGITAL;
174#ifdef WITH_A2DP
175        if (mA2dpOutput != 0) {
176            if (device2 == 0) {
177                // play ringtone over speaker (or speaker + headset) if in car dock
178                // because A2DP is suspended in this case
179                if (mForceUse[AudioSystem::FOR_DOCK] == AudioSystem::FORCE_BT_CAR_DOCK &&
180                    strategy == STRATEGY_SONIFICATION &&
181                    mPhoneState == AudioSystem::MODE_RINGTONE) {
182                    device2 = mAvailableOutputDevices &
183                              (AudioSystem::DEVICE_OUT_SPEAKER |
184                               AudioSystem::DEVICE_OUT_WIRED_HEADPHONE |
185                               AudioSystem::DEVICE_OUT_WIRED_HEADSET);
186                }
187            }
188        }
189#endif
190        if (device2 == 0) {
191            device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE;
192        }
193        if (device2 == 0) {
194            device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET;
195        }
196#ifdef WITH_A2DP
197        if (mA2dpOutput != 0) {
198            if (device2 == 0) {
199                device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP;
200            }
201            if (device2 == 0) {
202                device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
203            }
204            if (device2 == 0) {
205                device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
206            }
207        }
208#endif
209        if (device2 == 0) {
210            device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER;
211        }
212        // device is DEVICE_OUT_SPEAKER if we come from case STRATEGY_SONIFICATION, 0 otherwise
213        device |= device2;
214        if (device == 0) {
215            ALOGE("getDeviceForStrategy() speaker device not found");
216        }
217        // Do not play media stream if in call and the requested device would change the hardware
218        // output routing
219        if (mPhoneState == AudioSystem::MODE_IN_CALL &&
220            !AudioSystem::isA2dpDevice((AudioSystem::audio_devices)device) &&
221            device != getDeviceForStrategy(STRATEGY_PHONE, false)) {
222            device = 0;
223            ALOGV("getDeviceForStrategy() incompatible media and phone devices");
224        }
225        } break;
226
227    default:
228        ALOGW("getDeviceForStrategy() unknown strategy: %d", strategy);
229        break;
230    }
231
232    ALOGV("getDeviceForStrategy() strategy %d, device %x", strategy, device);
233    return device;
234}
235
236float AudioPolicyManager::computeVolume(int stream, int index, audio_io_handle_t output, uint32_t device)
237{
238    // if requested volume index is the minimum possible value, we must honor this value as this
239    // means the stream is muted. This overrides condition-specific modifications to the volume
240    // computed in the generic APM
241    if (index == mStreams[stream].mIndexMin) {
242        return AudioPolicyManagerBase::computeVolume(stream, index, output, device);
243    }
244
245    // force volume on A2DP output to maximum if playing through car dock speakers
246    // as volume is applied on the car dock and controlled via car dock keys.
247#ifdef WITH_A2DP
248    if (output == mA2dpOutput &&
249        mForceUse[AudioSystem::FOR_DOCK] == AudioSystem::FORCE_BT_CAR_DOCK) {
250        return 1.0;
251    }
252#endif
253
254    float volume = AudioPolicyManagerBase::computeVolume(stream, index, output, device);
255
256    // limit stream volume when in call and playing over bluetooth SCO device to
257    // avoid saturation
258    if (mPhoneState == AudioSystem::MODE_IN_CALL && AudioSystem::isBluetoothScoDevice((AudioSystem::audio_devices)device)) {
259        if (volume > IN_CALL_SCO_VOLUME_MAX) {
260            ALOGV("computeVolume limiting SYSTEM volume %f to %f",volume, IN_CALL_SCO_VOLUME_MAX);
261            volume = IN_CALL_SCO_VOLUME_MAX;
262        }
263    }
264
265    // in car dock: when using the 3.5mm jack to play media, set a minimum volume as access to the
266    // physical volume keys is blocked by the car dock frame.
267    if ((mForceUse[AudioSystem::FOR_DOCK] == AudioSystem::FORCE_BT_CAR_DOCK) &&
268            (volume < CAR_DOCK_MUSIC_MINI_JACK_VOLUME_MIN) &&
269            (stream == AudioSystem::MUSIC) &&
270            (device & (AudioSystem::DEVICE_OUT_WIRED_HEADPHONE |
271                AudioSystem::DEVICE_OUT_WIRED_HEADSET))) {
272        volume = CAR_DOCK_MUSIC_MINI_JACK_VOLUME_MIN;
273    }
274
275    return volume;
276}
277
278
279
280
281}; // namespace android
282