Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2009 The Android Open Source Project |
| 3 | * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. |
| 4 | * |
| 5 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 6 | * you may not use this file except in compliance with the License. |
| 7 | * You may obtain a copy of the License at |
| 8 | * |
| 9 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | * |
| 11 | * Unless required by applicable law or agreed to in writing, software |
| 12 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | * See the License for the specific language governing permissions and |
| 15 | * limitations under the License. |
| 16 | */ |
| 17 | |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 18 | #define LOG_TAG "audio_policy.msm8960" |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 19 | //#define LOG_NDEBUG 0 |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 20 | #include <utils/Log.h> |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 21 | |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 22 | #include "AudioPolicyManagerALSA.h" |
| 23 | #include <media/mediarecorder.h> |
| 24 | |
| 25 | namespace android_audio_legacy { |
| 26 | |
| 27 | // ---------------------------------------------------------------------------- |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 28 | audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strategy, bool fromCache) |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 29 | { |
| 30 | uint32_t device = 0; |
| 31 | |
| 32 | if (fromCache) { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 33 | ALOGV("getDeviceForStrategy() from cache strategy %d, device %x", strategy, mDeviceForStrategy[strategy]); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 34 | return mDeviceForStrategy[strategy]; |
| 35 | } |
| 36 | |
| 37 | switch (strategy) { |
| 38 | case STRATEGY_DTMF: |
| 39 | if (!isInCall()) { |
| 40 | // when off call, DTMF strategy follows the same rules as MEDIA strategy |
| 41 | device = getDeviceForStrategy(STRATEGY_MEDIA, false); |
| 42 | break; |
| 43 | } |
| 44 | // when in call, DTMF and PHONE strategies follow the same rules |
| 45 | // FALL THROUGH |
| 46 | |
| 47 | case STRATEGY_PHONE: |
| 48 | // for phone strategy, we first consider the forced use and then the available devices by order |
| 49 | // of priority |
| 50 | switch (mForceUse[AudioSystem::FOR_COMMUNICATION]) { |
| 51 | case AudioSystem::FORCE_BT_SCO: |
| 52 | if (!isInCall() || strategy != STRATEGY_DTMF) { |
| 53 | device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT; |
| 54 | if (device) break; |
| 55 | } |
| 56 | device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET; |
| 57 | if (device) break; |
| 58 | device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO; |
| 59 | if (device) break; |
| 60 | // if SCO device is requested but no SCO device is available, fall back to default case |
| 61 | // FALL THROUGH |
| 62 | |
| 63 | default: // FORCE_NONE |
| 64 | device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_PROXY; |
| 65 | if (device) break; |
| 66 | #ifdef WITH_A2DP |
| 67 | // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to A2DP |
| 68 | if (!isInCall()) { |
| 69 | device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP; |
| 70 | if (device) break; |
| 71 | device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES; |
| 72 | if (device) break; |
| 73 | } |
| 74 | #endif |
| 75 | device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET; |
| 76 | if (device) break; |
| 77 | device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_AUX_DIGITAL; |
| 78 | if (device) break; |
| 79 | device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET; |
| 80 | if (device) break; |
| 81 | device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE; |
| 82 | if (device) break; |
| 83 | device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET; |
| 84 | if (device) break; |
| 85 | device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_ANC_HEADPHONE; |
| 86 | if (device) break; |
| 87 | device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_ANC_HEADSET; |
| 88 | if (device) break; |
| 89 | device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_EARPIECE; |
| 90 | if (device == 0) { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 91 | ALOGE("getDeviceForStrategy() earpiece device not found"); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 92 | } |
| 93 | break; |
| 94 | |
| 95 | case AudioSystem::FORCE_SPEAKER: |
| 96 | if (!isInCall() || strategy != STRATEGY_DTMF) { |
| 97 | device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT; |
| 98 | if (device) break; |
| 99 | } |
| 100 | #ifdef WITH_A2DP |
| 101 | // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to |
| 102 | // A2DP speaker when forcing to speaker output |
| 103 | if (!isInCall()) { |
| 104 | device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER; |
| 105 | if (device) break; |
| 106 | } |
| 107 | #endif |
| 108 | device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET; |
| 109 | if (device) break; |
| 110 | device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET; |
| 111 | if (device) break; |
| 112 | device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER; |
| 113 | if (device == 0) { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 114 | ALOGE("getDeviceForStrategy() speaker device not found"); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 115 | } |
| 116 | break; |
| 117 | } |
| 118 | #ifdef FM_ENABLED |
| 119 | if (mAvailableOutputDevices & AudioSystem::DEVICE_OUT_FM) { |
| 120 | device |= AudioSystem::DEVICE_OUT_FM; |
| 121 | if (mForceUse[AudioSystem::FOR_MEDIA] == AudioSystem::FORCE_SPEAKER) { |
| 122 | device &= ~(AudioSystem::DEVICE_OUT_WIRED_HEADSET); |
| 123 | device &= ~(AudioSystem::DEVICE_OUT_WIRED_HEADPHONE); |
| 124 | device |= AudioSystem::DEVICE_OUT_SPEAKER; |
| 125 | } |
| 126 | } |
| 127 | #endif |
| 128 | break; |
| 129 | |
| 130 | case STRATEGY_SONIFICATION: |
| 131 | |
| 132 | // If incall, just select the STRATEGY_PHONE device: The rest of the behavior is handled by |
| 133 | // handleIncallSonification(). |
| 134 | if (isInCall()) { |
| 135 | device = getDeviceForStrategy(STRATEGY_PHONE, false); |
| 136 | break; |
| 137 | } |
| 138 | // FALL THROUGH |
| 139 | |
| 140 | case STRATEGY_ENFORCED_AUDIBLE: |
| 141 | // strategy STRATEGY_ENFORCED_AUDIBLE uses same routing policy as STRATEGY_SONIFICATION |
| 142 | // except when in call where it doesn't default to STRATEGY_PHONE behavior |
| 143 | |
| 144 | device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER; |
| 145 | if (device == 0) { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 146 | ALOGE("getDeviceForStrategy() speaker device not found"); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 147 | } |
| 148 | // The second device used for sonification is the same as the device used by media strategy |
| 149 | // FALL THROUGH |
| 150 | |
| 151 | case STRATEGY_MEDIA: { |
| 152 | //To route FM stream to speaker when headset is connected, a new switch case is added. |
| 153 | //case AudioSystem::FORCE_SPEAKER for STRATEGY_MEDIA will come only when we need to route |
| 154 | //FM stream to speaker. |
| 155 | switch (mForceUse[AudioSystem::FOR_MEDIA]) { |
| 156 | default:{ |
| 157 | uint32_t device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_PROXY; |
| 158 | if(device2 != 0) { |
| 159 | // No combo device allowed with proxy device |
| 160 | device = 0; |
| 161 | } |
| 162 | #ifdef WITH_A2DP |
| 163 | if (mA2dpOutput != 0) { |
| 164 | if (strategy == STRATEGY_SONIFICATION && !a2dpUsedForSonification()) { |
| 165 | break; |
| 166 | } |
| 167 | if (device2 == 0) { |
| 168 | device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP; |
| 169 | } |
| 170 | if (device2 == 0) { |
| 171 | device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES; |
| 172 | } |
| 173 | if (device2 == 0) { |
| 174 | device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER; |
| 175 | } |
| 176 | } |
| 177 | #endif |
| 178 | if (device2 == 0) { |
| 179 | device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET; |
| 180 | } |
| 181 | if (device2 == 0) { |
| 182 | device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_AUX_DIGITAL; |
| 183 | } |
| 184 | if (device2 == 0) { |
| 185 | device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET; |
| 186 | } |
| 187 | if (device2 == 0) { |
| 188 | device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE; |
| 189 | } |
| 190 | if (device2 == 0) { |
| 191 | device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET; |
| 192 | } |
| 193 | if (device2 == 0) { |
| 194 | device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_ANC_HEADPHONE; |
| 195 | } |
| 196 | if (device2 == 0) { |
| 197 | device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_ANC_HEADSET; |
| 198 | } |
| 199 | if (device2 == 0) { |
| 200 | device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_FM_TX; |
| 201 | } |
| 202 | if (device2 == 0) { |
| 203 | device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER; |
| 204 | } |
| 205 | |
| 206 | if (device2 == 0) { |
| 207 | device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_EARPIECE; |
| 208 | } |
| 209 | |
| 210 | // device is DEVICE_OUT_SPEAKER if we come from case STRATEGY_SONIFICATION or |
| 211 | // STRATEGY_ENFORCED_AUDIBLE, 0 otherwise |
| 212 | device |= device2; |
| 213 | } |
| 214 | break; |
| 215 | case AudioSystem::FORCE_SPEAKER: |
| 216 | device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER; |
| 217 | break; |
| 218 | } |
| 219 | #ifdef FM_ENABLED |
| 220 | if (mAvailableOutputDevices & AudioSystem::DEVICE_OUT_FM) { |
| 221 | device |= AudioSystem::DEVICE_OUT_FM; |
| 222 | } |
| 223 | #endif |
| 224 | if (mAvailableOutputDevices & AudioSystem::DEVICE_OUT_ANC_HEADSET) { |
| 225 | device |= AudioSystem::DEVICE_OUT_ANC_HEADSET; |
| 226 | } |
| 227 | if (mAvailableOutputDevices & AudioSystem::DEVICE_OUT_ANC_HEADPHONE) { |
| 228 | device |= AudioSystem::DEVICE_OUT_ANC_HEADPHONE; |
| 229 | } |
| 230 | // Do not play media stream if in call and the requested device would change the hardware |
| 231 | // output routing |
| 232 | if (mPhoneState == AudioSystem::MODE_IN_CALL && |
| 233 | !AudioSystem::isA2dpDevice((AudioSystem::audio_devices)device) && |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 234 | device != getDeviceForStrategy(STRATEGY_PHONE, true)) { |
| 235 | device = getDeviceForStrategy(STRATEGY_PHONE, true); |
| 236 | ALOGV("getDeviceForStrategy() incompatible media and phone devices"); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 237 | } |
| 238 | } break; |
| 239 | |
| 240 | default: |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 241 | ALOGW("getDeviceForStrategy() unknown strategy: %d", strategy); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 242 | break; |
| 243 | } |
| 244 | |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 245 | ALOGV("getDeviceForStrategy() strategy %d, device %x", strategy, device); |
| 246 | return (audio_devices_t)device; |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 247 | } |
| 248 | |
| 249 | |
| 250 | status_t AudioPolicyManager::setDeviceConnectionState(AudioSystem::audio_devices device, |
| 251 | AudioSystem::device_connection_state state, |
| 252 | const char *device_address) |
| 253 | { |
| 254 | |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 255 | ALOGV("setDeviceConnectionState() device: %x, state %d, address %s", device, state, device_address); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 256 | |
| 257 | // connect/disconnect only 1 device at a time |
| 258 | if (AudioSystem::popCount(device) != 1) return BAD_VALUE; |
| 259 | |
| 260 | if (strlen(device_address) >= MAX_DEVICE_ADDRESS_LEN) { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 261 | ALOGE("setDeviceConnectionState() invalid address: %s", device_address); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 262 | return BAD_VALUE; |
| 263 | } |
| 264 | |
| 265 | // handle output devices |
| 266 | if (AudioSystem::isOutputDevice(device)) { |
| 267 | |
| 268 | #ifndef WITH_A2DP |
| 269 | if (AudioSystem::isA2dpDevice(device)) { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 270 | ALOGE("setDeviceConnectionState() invalid device: %x", device); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 271 | return BAD_VALUE; |
| 272 | } |
| 273 | #endif |
| 274 | |
| 275 | switch (state) |
| 276 | { |
| 277 | // handle output device connection |
| 278 | case AudioSystem::DEVICE_STATE_AVAILABLE: |
| 279 | if (mAvailableOutputDevices & device) { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 280 | ALOGW("setDeviceConnectionState() device already connected: %x", device); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 281 | return INVALID_OPERATION; |
| 282 | } |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 283 | ALOGV("setDeviceConnectionState() connecting device %x", device); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 284 | |
| 285 | // register new device as available |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 286 | mAvailableOutputDevices = (audio_devices_t)((uint32_t)mAvailableOutputDevices | device); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 287 | |
| 288 | #ifdef WITH_A2DP |
| 289 | // handle A2DP device connection |
| 290 | if (AudioSystem::isA2dpDevice(device)) { |
| 291 | status_t status = AudioPolicyManagerBase::handleA2dpConnection(device, device_address); |
| 292 | if (status != NO_ERROR) { |
| 293 | mAvailableOutputDevices &= ~device; |
| 294 | return status; |
| 295 | } |
| 296 | } else |
| 297 | #endif |
| 298 | { |
| 299 | if (AudioSystem::isBluetoothScoDevice(device)) { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 300 | ALOGV("setDeviceConnectionState() BT SCO device, address %s", device_address); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 301 | // keep track of SCO device address |
| 302 | mScoDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN); |
| 303 | } |
| 304 | } |
| 305 | break; |
| 306 | // handle output device disconnection |
| 307 | case AudioSystem::DEVICE_STATE_UNAVAILABLE: { |
| 308 | if (!(mAvailableOutputDevices & device)) { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 309 | ALOGW("setDeviceConnectionState() device not connected: %x", device); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 310 | return INVALID_OPERATION; |
| 311 | } |
| 312 | |
| 313 | |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 314 | ALOGV("setDeviceConnectionState() disconnecting device %x", device); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 315 | // remove device from available output devices |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 316 | mAvailableOutputDevices = (audio_devices_t)((uint32_t)mAvailableOutputDevices & ~device); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 317 | |
| 318 | #ifdef WITH_A2DP |
| 319 | // handle A2DP device disconnection |
| 320 | if (AudioSystem::isA2dpDevice(device)) { |
| 321 | status_t status = AudioPolicyManagerBase::handleA2dpDisconnection(device, device_address); |
| 322 | if (status != NO_ERROR) { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 323 | mAvailableOutputDevices = (audio_devices_t)((uint32_t)mAvailableOutputDevices | device); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 324 | return status; |
| 325 | } |
| 326 | } else |
| 327 | #endif |
| 328 | { |
| 329 | if (AudioSystem::isBluetoothScoDevice(device)) { |
| 330 | mScoDeviceAddress = ""; |
| 331 | } |
| 332 | } |
| 333 | } break; |
| 334 | |
| 335 | default: |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 336 | ALOGE("setDeviceConnectionState() invalid state: %x", state); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 337 | return BAD_VALUE; |
| 338 | } |
| 339 | |
| 340 | // request routing change if necessary |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 341 | uint32_t newDevice = AudioPolicyManagerBase::getNewDevice(mPrimaryOutput, false); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 342 | |
| 343 | if(newDevice == 0 && mLPADecodeOutput != -1) { |
| 344 | newDevice = AudioPolicyManagerBase::getNewDevice(mLPADecodeOutput, false); |
| 345 | } |
| 346 | #ifdef FM_ENABLED |
| 347 | if(device == AudioSystem::DEVICE_OUT_FM) { |
| 348 | if (state == AudioSystem::DEVICE_STATE_AVAILABLE) { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 349 | mOutputs.valueFor(mPrimaryOutput)->changeRefCount(AudioSystem::FM, 1); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 350 | } |
| 351 | else { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 352 | mOutputs.valueFor(mPrimaryOutput)->changeRefCount(AudioSystem::FM, -1); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 353 | } |
| 354 | if(newDevice == 0){ |
| 355 | newDevice = getDeviceForStrategy(STRATEGY_MEDIA, false); |
| 356 | } |
| 357 | AudioParameter param = AudioParameter(); |
| 358 | param.addInt(String8(AudioParameter::keyHandleFm), (int)newDevice); |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 359 | mpClientInterface->setParameters(mPrimaryOutput, param.toString()); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 360 | } |
| 361 | #endif |
| 362 | if(device == AudioSystem::DEVICE_OUT_ANC_HEADPHONE || |
| 363 | device == AudioSystem::DEVICE_OUT_ANC_HEADSET) { |
| 364 | if(newDevice == 0){ |
| 365 | newDevice = getDeviceForStrategy(STRATEGY_MEDIA, false); |
| 366 | } |
| 367 | } |
| 368 | #ifdef WITH_A2DP |
| 369 | AudioPolicyManagerBase::checkA2dpSuspend(); |
| 370 | AudioPolicyManagerBase::checkOutputForAllStrategies(); |
| 371 | // A2DP outputs must be closed after checkOutputForAllStrategies() is executed |
| 372 | if (state == AudioSystem::DEVICE_STATE_UNAVAILABLE && AudioSystem::isA2dpDevice(device)) { |
| 373 | AudioPolicyManagerBase::closeA2dpOutputs(); |
| 374 | } |
| 375 | #endif |
| 376 | AudioPolicyManagerBase::updateDeviceForStrategy(); |
| 377 | |
| 378 | int delayMs = 0; |
| 379 | if (AudioSystem::DEVICE_OUT_SPEAKER == newDevice |
| 380 | && AudioSystem::DEVICE_OUT_WIRED_HEADSET == device) { |
| 381 | //Add some delay(192ms) while switching from wired headset to speaker before pause |
| 382 | //music keeps playing from speaker if there's not delay or delay is too small. |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 383 | delayMs = mOutputs.valueFor(mPrimaryOutput)->mLatency*8; |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 384 | } |
| 385 | |
| 386 | if(mLPADecodeOutput != -1) |
| 387 | setOutputDevice(mLPADecodeOutput, newDevice, false, delayMs); |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 388 | setOutputDevice(mPrimaryOutput, newDevice, false, delayMs); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 389 | |
| 390 | if (device == AudioSystem::DEVICE_OUT_WIRED_HEADSET) { |
| 391 | device = AudioSystem::DEVICE_IN_WIRED_HEADSET; |
| 392 | } else if (device == AudioSystem::DEVICE_OUT_BLUETOOTH_SCO || |
| 393 | device == AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET || |
| 394 | device == AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT) { |
| 395 | device = AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET; |
| 396 | } else if(device == AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET){ |
| 397 | device = AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET; |
| 398 | } else if(device == AudioSystem::DEVICE_OUT_ANC_HEADSET){ |
| 399 | device = AudioSystem::DEVICE_IN_ANC_HEADSET; //wait for actual ANC device |
| 400 | } else { |
| 401 | return NO_ERROR; |
| 402 | } |
| 403 | } |
| 404 | // handle input devices |
| 405 | if (AudioSystem::isInputDevice(device)) { |
| 406 | |
| 407 | switch (state) |
| 408 | { |
| 409 | // handle input device connection |
| 410 | case AudioSystem::DEVICE_STATE_AVAILABLE: { |
| 411 | if (mAvailableInputDevices & device) { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 412 | ALOGW("setDeviceConnectionState() device already connected: %d", device); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 413 | return INVALID_OPERATION; |
| 414 | } |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 415 | mAvailableInputDevices = (audio_devices_t)(mAvailableInputDevices | device); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 416 | } |
| 417 | break; |
| 418 | |
| 419 | // handle input device disconnection |
| 420 | case AudioSystem::DEVICE_STATE_UNAVAILABLE: { |
| 421 | if (!(mAvailableInputDevices & device)) { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 422 | ALOGW("setDeviceConnectionState() device not connected: %d", device); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 423 | return INVALID_OPERATION; |
| 424 | } |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 425 | mAvailableInputDevices = (audio_devices_t)((uint32_t)mAvailableInputDevices & ~device); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 426 | } break; |
| 427 | |
| 428 | default: |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 429 | ALOGE("setDeviceConnectionState() invalid state: %x", state); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 430 | return BAD_VALUE; |
| 431 | } |
| 432 | |
| 433 | audio_io_handle_t activeInput = AudioPolicyManagerBase::getActiveInput(); |
| 434 | if (activeInput != 0) { |
| 435 | AudioInputDescriptor *inputDesc = mInputs.valueFor(activeInput); |
| 436 | uint32_t newDevice = AudioPolicyManagerBase::getDeviceForInputSource(inputDesc->mInputSource); |
| 437 | if (newDevice != inputDesc->mDevice) { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 438 | ALOGV("setDeviceConnectionState() changing device from %x to %x for input %d", |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 439 | inputDesc->mDevice, newDevice, activeInput); |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 440 | inputDesc->mDevice = (audio_devices_t)newDevice; |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 441 | AudioParameter param = AudioParameter(); |
| 442 | param.addInt(String8(AudioParameter::keyRouting), (int)newDevice); |
| 443 | mpClientInterface->setParameters(activeInput, param.toString()); |
| 444 | } |
| 445 | } |
| 446 | |
| 447 | return NO_ERROR; |
| 448 | } |
| 449 | |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 450 | ALOGW("setDeviceConnectionState() invalid device: %x", device); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 451 | return BAD_VALUE; |
| 452 | } |
| 453 | |
| 454 | |
| 455 | void AudioPolicyManager::setPhoneState(int state) |
| 456 | { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 457 | ALOGD("setPhoneState() state %d", state); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 458 | uint32_t newDevice = 0; |
| 459 | if (state < 0 || state >= AudioSystem::NUM_MODES) { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 460 | ALOGW("setPhoneState() invalid state %d", state); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 461 | return; |
| 462 | } |
| 463 | |
| 464 | if (state == mPhoneState ) { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 465 | ALOGW("setPhoneState() setting same state %d", state); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 466 | return; |
| 467 | } |
| 468 | |
| 469 | // if leaving call state, handle special case of active streams |
| 470 | // pertaining to sonification strategy see handleIncallSonification() |
| 471 | if (isInCall()) { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 472 | ALOGV("setPhoneState() in call state management: new state is %d", state); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 473 | for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) { |
| 474 | AudioPolicyManagerBase::handleIncallSonification(stream, false, true); |
| 475 | } |
| 476 | } |
| 477 | |
| 478 | // store previous phone state for management of sonification strategy below |
| 479 | int oldState = mPhoneState; |
| 480 | mPhoneState = state; |
| 481 | // force routing command to audio hardware when starting call |
| 482 | // even if no device change is needed |
| 483 | bool force = (mPhoneState == AudioSystem::MODE_IN_CALL); |
| 484 | |
| 485 | // are we entering or starting a call |
| 486 | if (!isStateInCall(oldState) && isStateInCall(state)) { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 487 | ALOGV(" Entering call in setPhoneState()"); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 488 | // force routing command to audio hardware when starting a call |
| 489 | // even if no device change is needed |
| 490 | force = true; |
| 491 | } else if (isStateInCall(oldState) && (state == AudioSystem::MODE_NORMAL)) { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 492 | ALOGV(" Exiting call in setPhoneState()"); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 493 | // force routing command to audio hardware when exiting a call |
| 494 | // even if no device change is needed |
| 495 | force = true; |
| 496 | } else if (isStateInCall(state) && (state != oldState)) { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 497 | ALOGV(" Switching between telephony and VoIP in setPhoneState()"); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 498 | // force routing command to audio hardware when switching between telephony and VoIP |
| 499 | // even if no device change is needed |
| 500 | force = true; |
| 501 | } |
| 502 | |
| 503 | // check for device and output changes triggered by new phone state |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 504 | newDevice = AudioPolicyManagerBase::getNewDevice(mPrimaryOutput, false); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 505 | if (newDevice == 0 && (mLPADecodeOutput != -1 && |
| 506 | mOutputs.valueFor(mLPADecodeOutput)->isUsedByStrategy(STRATEGY_MEDIA))) { |
| 507 | newDevice = getDeviceForStrategy(STRATEGY_MEDIA, false); |
| 508 | } |
| 509 | |
| 510 | #ifdef WITH_A2DP |
| 511 | AudioPolicyManagerBase::checkA2dpSuspend(); |
| 512 | AudioPolicyManagerBase::checkOutputForAllStrategies(); |
| 513 | #endif |
| 514 | AudioPolicyManagerBase::updateDeviceForStrategy(); |
| 515 | |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 516 | AudioOutputDescriptor *hwOutputDesc = mOutputs.valueFor(mPrimaryOutput); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 517 | |
| 518 | // force routing command to audio hardware when ending call |
| 519 | // even if no device change is needed |
| 520 | if (isStateInCall(oldState) && newDevice == 0) { |
| 521 | newDevice = hwOutputDesc->device(); |
| 522 | if(state == AudioSystem::MODE_NORMAL) { |
| 523 | force = true; |
| 524 | } |
| 525 | } |
| 526 | |
| 527 | // when changing from ring tone to in call mode, mute the ringing tone |
| 528 | // immediately and delay the route change to avoid sending the ring tone |
| 529 | // tail into the earpiece or headset. |
| 530 | int delayMs = 0; |
| 531 | if (isStateInCall(state) && oldState == AudioSystem::MODE_RINGTONE) { |
| 532 | // delay the device change command by twice the output latency to have some margin |
| 533 | // and be sure that audio buffers not yet affected by the mute are out when |
| 534 | // we actually apply the route change |
| 535 | delayMs = hwOutputDesc->mLatency*2; |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 536 | setStreamMute(AudioSystem::RING, true, mPrimaryOutput); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 537 | } |
| 538 | |
| 539 | // change routing is necessary |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 540 | setOutputDevice(mPrimaryOutput, newDevice, force, delayMs); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 541 | |
| 542 | // if entering in call state, handle special case of active streams |
| 543 | // pertaining to sonification strategy see handleIncallSonification() |
| 544 | if (isStateInCall(state)) { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 545 | ALOGV("setPhoneState() in call state management: new state is %d", state); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 546 | // unmute the ringing tone after a sufficient delay if it was muted before |
| 547 | // setting output device above |
| 548 | if (oldState == AudioSystem::MODE_RINGTONE) { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 549 | setStreamMute(AudioSystem::RING, false, mPrimaryOutput, MUTE_TIME_MS); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 550 | } |
| 551 | for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) { |
| 552 | AudioPolicyManagerBase::handleIncallSonification(stream, true, true); |
| 553 | } |
| 554 | } |
| 555 | |
| 556 | // Flag that ringtone volume must be limited to music volume until we exit MODE_RINGTONE |
| 557 | if (state == AudioSystem::MODE_RINGTONE && |
| 558 | (hwOutputDesc->mRefCount[AudioSystem::MUSIC] || |
| 559 | (systemTime() - hwOutputDesc->mStopTime[AudioSystem::MUSIC]) < seconds(SONIFICATION_HEADSET_MUSIC_DELAY))) { |
| 560 | // (systemTime() - mMusicStopTime) < seconds(SONIFICATION_HEADSET_MUSIC_DELAY))) { |
| 561 | mLimitRingtoneVolume = true; |
| 562 | } else { |
| 563 | mLimitRingtoneVolume = false; |
| 564 | } |
| 565 | } |
| 566 | |
| 567 | #ifdef TUNNEL_LPA_ENABLED |
| 568 | audio_io_handle_t AudioPolicyManager::getSession(AudioSystem::stream_type stream, |
| 569 | uint32_t format, |
| 570 | AudioSystem::output_flags flags, |
| 571 | int32_t sessionId, |
| 572 | uint32_t samplingRate, |
| 573 | uint32_t channels) |
| 574 | { |
| 575 | audio_io_handle_t output = 0; |
| 576 | uint32_t latency = 0; |
| 577 | routing_strategy strategy = getStrategy((AudioSystem::stream_type)stream); |
| 578 | uint32_t device = getDeviceForStrategy(strategy); |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 579 | ALOGV("getSession() stream %d, format %d, sessionId %x, flags %x device %d", stream, format, sessionId, flags, device); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 580 | AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(); |
| 581 | outputDesc->mDevice = device; |
| 582 | outputDesc->mSamplingRate = 0; |
| 583 | outputDesc->mFormat = format; |
| 584 | outputDesc->mChannels = 2; |
| 585 | outputDesc->mLatency = 0; |
| 586 | outputDesc->mFlags = (AudioSystem::output_flags)(flags | AudioSystem::OUTPUT_FLAG_DIRECT); |
| 587 | outputDesc->mRefCount[stream] = 0; |
| 588 | output = mpClientInterface->openSession(&outputDesc->mDevice, |
| 589 | &outputDesc->mFormat, |
| 590 | outputDesc->mFlags, |
| 591 | stream, |
| 592 | sessionId, |
| 593 | samplingRate, |
| 594 | channels); |
| 595 | |
| 596 | // only accept an output with the requeted parameters |
| 597 | if ((format != 0 && format != outputDesc->mFormat) || !output) { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 598 | ALOGE("openSession() failed opening a session: format %d, sessionId %d output %d", |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 599 | format, sessionId, output); |
| 600 | if(output) { |
| 601 | mpClientInterface->closeSession(output); |
| 602 | } |
| 603 | delete outputDesc; |
| 604 | return 0; |
| 605 | } |
| 606 | |
| 607 | //reset it here, it will get updated in startoutput |
| 608 | outputDesc->mDevice = 0; |
| 609 | |
| 610 | mOutputs.add(output, outputDesc); |
| 611 | mLPADecodeOutput = output; |
| 612 | mLPAStreamType = stream; |
| 613 | return output; |
| 614 | } |
| 615 | |
| 616 | void AudioPolicyManager::pauseSession(audio_io_handle_t output, AudioSystem::stream_type stream) |
| 617 | { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 618 | ALOGV("pauseSession() Output [%d] and stream is [%d]", output, stream); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 619 | |
| 620 | if ( (output == mLPADecodeOutput) && |
| 621 | (stream == mLPAStreamType) ) { |
| 622 | AudioPolicyManager::stopOutput(output, mLPAStreamType); |
| 623 | mLPAActiveOuput = mLPADecodeOutput; |
| 624 | mLPAActiveStreamType = mLPAStreamType; |
| 625 | mLPADecodeOutput = -1; |
| 626 | mLPAStreamType = AudioSystem::DEFAULT; |
| 627 | mLPAMuted = false; |
| 628 | } |
| 629 | } |
| 630 | |
| 631 | void AudioPolicyManager::resumeSession(audio_io_handle_t output, AudioSystem::stream_type stream) |
| 632 | { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 633 | ALOGV("resumeSession() Output [%d] and stream is [%d]", output, stream); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 634 | |
| 635 | if (output == mLPAActiveOuput) |
| 636 | { |
| 637 | mLPADecodeOutput = mLPAActiveOuput; |
| 638 | mLPAStreamType = stream; |
| 639 | AudioPolicyManager::startOutput(mLPADecodeOutput, mLPAStreamType); |
| 640 | |
| 641 | // Set Volume if the music stream volume is changed in the Pause state of LPA Jagan |
| 642 | mLPAActiveOuput = -1; |
| 643 | mLPAActiveStreamType = AudioSystem::DEFAULT; |
| 644 | } |
| 645 | } |
| 646 | |
| 647 | void AudioPolicyManager::releaseSession(audio_io_handle_t output) |
| 648 | { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 649 | ALOGV("releaseSession() %d", output); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 650 | |
| 651 | // This means the Output is put into Pause state |
| 652 | if (output == mLPAActiveOuput && mLPADecodeOutput == -1) { |
| 653 | mLPADecodeOutput = mLPAActiveOuput; |
| 654 | mLPAStreamType = mLPAActiveStreamType; |
| 655 | } |
| 656 | |
| 657 | ssize_t index = mOutputs.indexOfKey(output); |
| 658 | if (index < 0) { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 659 | ALOGW("releaseSession() releasing unknown output %d", output); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 660 | return; |
| 661 | } |
| 662 | |
| 663 | AudioPolicyManager::stopOutput(output, mLPAStreamType); |
| 664 | delete mOutputs.valueAt(index); |
| 665 | mOutputs.removeItem(output); |
| 666 | mLPADecodeOutput = -1; |
| 667 | mLPAActiveOuput = -1; |
| 668 | mLPAStreamType = AudioSystem::DEFAULT; |
| 669 | mLPAActiveStreamType = AudioSystem::DEFAULT; |
| 670 | mLPAMuted = false; |
| 671 | } |
| 672 | #endif |
| 673 | |
| 674 | status_t AudioPolicyManager::startOutput(audio_io_handle_t output, AudioSystem::stream_type stream, int session) |
| 675 | { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 676 | ALOGV("startOutput() output %d, stream %d", output, stream); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 677 | ssize_t index = mOutputs.indexOfKey(output); |
| 678 | if (index < 0) { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 679 | ALOGW("startOutput() unknow output %d", output); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 680 | return BAD_VALUE; |
| 681 | } |
| 682 | |
| 683 | AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index); |
| 684 | routing_strategy strategy = getStrategy((AudioSystem::stream_type)stream); |
| 685 | |
| 686 | #ifdef WITH_A2DP |
| 687 | if (mA2dpOutput != 0 && !a2dpUsedForSonification() && |
| 688 | (strategy == STRATEGY_SONIFICATION || strategy == STRATEGY_ENFORCED_AUDIBLE)) { |
| 689 | setStrategyMute(STRATEGY_MEDIA, true, mA2dpOutput); |
| 690 | } |
| 691 | #endif |
| 692 | |
| 693 | // incremenent usage count for this stream on the requested output: |
| 694 | // NOTE that the usage count is the same for duplicated output and hardware output which is |
| 695 | // necassary for a correct control of hardware output routing by startOutput() and stopOutput() |
| 696 | outputDesc->changeRefCount(stream, 1); |
| 697 | #ifdef FM_ENABLED |
| 698 | if(stream == AudioSystem::FM && output == mA2dpOutput) { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 699 | setOutputDevice(output, AudioPolicyManagerBase::getNewDevice(output, true), true); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 700 | } else |
| 701 | #endif |
| 702 | #ifdef TUNNEL_LPA_ENABLED |
| 703 | if (output != mLPADecodeOutput) { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 704 | setOutputDevice(output, AudioPolicyManagerBase::getNewDevice(output, true)); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 705 | } else |
| 706 | #endif |
| 707 | { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 708 | setOutputDevice(output, AudioPolicyManagerBase::getNewDevice(output, true), true); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 709 | } |
| 710 | |
| 711 | // handle special case for sonification while in call |
| 712 | if (isInCall()) { |
| 713 | AudioPolicyManagerBase::handleIncallSonification(stream, true, false); |
| 714 | } |
| 715 | |
| 716 | // apply volume rules for current stream and device if necessary |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 717 | checkAndSetVolume((int)stream, mStreams[stream].mIndexCur.valueFor(outputDesc->device()), output, outputDesc->device()); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 718 | |
| 719 | return NO_ERROR; |
| 720 | } |
| 721 | |
| 722 | status_t AudioPolicyManager::stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream, int session) |
| 723 | { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 724 | ALOGV("stopOutput() output %d, stream %d", output, stream); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 725 | ssize_t index = mOutputs.indexOfKey(output); |
| 726 | if (index < 0) { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 727 | ALOGW("stopOutput() unknow output %d", output); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 728 | return BAD_VALUE; |
| 729 | } |
| 730 | |
| 731 | AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index); |
| 732 | routing_strategy strategy = AudioPolicyManagerBase::getStrategy((AudioSystem::stream_type)stream); |
| 733 | |
| 734 | // handle special case for sonification while in call |
| 735 | if (isInCall()) { |
| 736 | AudioPolicyManagerBase::handleIncallSonification(stream, false, false); |
| 737 | } |
| 738 | |
| 739 | if (outputDesc->mRefCount[stream] > 0) { |
| 740 | // decrement usage count of this stream on the output |
| 741 | outputDesc->changeRefCount(stream, -1); |
| 742 | // store time at which the last music track was stopped - see computeVolume() |
| 743 | if (stream == AudioSystem::MUSIC) { |
| 744 | outputDesc->mStopTime[stream] = systemTime(); |
| 745 | // mMusicStopTime = systemTime(); |
| 746 | } |
| 747 | |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 748 | uint32_t newDevice = AudioPolicyManagerBase::getNewDevice(mPrimaryOutput, false); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 749 | |
| 750 | if(newDevice == 0 && mLPADecodeOutput != -1) { |
| 751 | newDevice = AudioPolicyManagerBase::getNewDevice(mLPADecodeOutput, false); |
| 752 | } |
| 753 | |
| 754 | setOutputDevice(output, newDevice); |
| 755 | |
| 756 | #ifdef WITH_A2DP |
| 757 | if (mA2dpOutput != 0 && !a2dpUsedForSonification() && |
| 758 | (strategy == STRATEGY_SONIFICATION || strategy == STRATEGY_ENFORCED_AUDIBLE)) { |
| 759 | setStrategyMute(STRATEGY_MEDIA, |
| 760 | false, |
| 761 | mA2dpOutput, |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 762 | mOutputs.valueFor(mPrimaryOutput)->mLatency*2); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 763 | } |
| 764 | #endif |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 765 | if (output != mPrimaryOutput) { |
| 766 | setOutputDevice(mPrimaryOutput, AudioPolicyManagerBase::getNewDevice(mPrimaryOutput, true), true); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 767 | } |
| 768 | return NO_ERROR; |
| 769 | } else { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 770 | ALOGW("stopOutput() refcount is already 0 for output %d", output); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 771 | return INVALID_OPERATION; |
| 772 | } |
| 773 | } |
| 774 | // ---------------------------------------------------------------------------- |
| 775 | // AudioPolicyManagerALSA |
| 776 | // ---------------------------------------------------------------------------- |
| 777 | |
| 778 | // --- class factory |
| 779 | |
| 780 | extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface) |
| 781 | { |
| 782 | return new AudioPolicyManager(clientInterface); |
| 783 | } |
| 784 | |
| 785 | extern "C" void destroyAudioPolicyManager(AudioPolicyInterface *interface) |
| 786 | { |
| 787 | delete interface; |
| 788 | } |
| 789 | |
| 790 | // --- |
| 791 | |
| 792 | void AudioPolicyManager::setOutputDevice(audio_io_handle_t output, uint32_t device, bool force, int delayMs) |
| 793 | { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 794 | ALOGV("setOutputDevice() output %d device %x delayMs %d", output, device, delayMs); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 795 | AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output); |
| 796 | |
| 797 | |
| 798 | if (outputDesc->isDuplicated()) { |
| 799 | setOutputDevice(outputDesc->mOutput1->mId, device, force, delayMs); |
| 800 | setOutputDevice(outputDesc->mOutput2->mId, device, force, delayMs); |
| 801 | return; |
| 802 | } |
| 803 | #ifdef WITH_A2DP |
| 804 | // filter devices according to output selected |
| 805 | if (output == mA2dpOutput) { |
| 806 | device &= AudioSystem::DEVICE_OUT_ALL_A2DP; |
| 807 | } else { |
| 808 | device &= ~AudioSystem::DEVICE_OUT_ALL_A2DP; |
| 809 | } |
| 810 | #endif |
| 811 | |
| 812 | uint32_t prevDevice = (uint32_t)outputDesc->device(); |
| 813 | // Do not change the routing if: |
| 814 | // - the requestede device is 0 |
| 815 | // - the requested device is the same as current device and force is not specified. |
| 816 | // Doing this check here allows the caller to call setOutputDevice() without conditions |
| 817 | if ((device == 0 || device == prevDevice) && !force) { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 818 | ALOGV("setOutputDevice() setting same device %x or null device for output %d", device, output); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 819 | return; |
| 820 | } |
| 821 | |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 822 | outputDesc->mDevice = (audio_devices_t)device; |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 823 | // mute media streams if both speaker and headset are selected |
| 824 | if (device == (AudioSystem::DEVICE_OUT_SPEAKER | AudioSystem::DEVICE_OUT_WIRED_HEADSET) |
| 825 | || device == (AudioSystem::DEVICE_OUT_SPEAKER | AudioSystem::DEVICE_OUT_ANC_HEADSET) |
| 826 | || device == (AudioSystem::DEVICE_OUT_SPEAKER | AudioSystem::DEVICE_OUT_ANC_HEADPHONE) |
| 827 | || device == (AudioSystem::DEVICE_OUT_SPEAKER | AudioSystem::DEVICE_OUT_WIRED_HEADPHONE) |
| 828 | || device == (AudioSystem::DEVICE_OUT_SPEAKER | AudioSystem::DEVICE_OUT_WIRED_HEADSET | AudioSystem::DEVICE_OUT_FM) |
| 829 | || device == (AudioSystem::DEVICE_OUT_SPEAKER | AudioSystem::DEVICE_OUT_WIRED_HEADPHONE | AudioSystem::DEVICE_OUT_FM) |
| 830 | || device == (AudioSystem::DEVICE_OUT_SPEAKER | AudioSystem::DEVICE_OUT_FM_TX)) { |
| 831 | setStrategyMute(STRATEGY_MEDIA, true, output); |
| 832 | // Mute LPA output also if it belongs to STRATEGY_MEDIA |
| 833 | if(((mLPADecodeOutput != -1) && (mLPADecodeOutput != output) && |
| 834 | mOutputs.valueFor(mLPADecodeOutput)->isUsedByStrategy(STRATEGY_MEDIA))) { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 835 | ALOGV("setOutputDevice: Muting mLPADecodeOutput:%d",mLPADecodeOutput); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 836 | setStrategyMute(STRATEGY_MEDIA, true, mLPADecodeOutput); |
| 837 | } |
| 838 | // Mute hardware output also if it belongs to STRATEGY_MEDIA |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 839 | if(((mPrimaryOutput != -1) && (mPrimaryOutput != output) && |
| 840 | mOutputs.valueFor(mPrimaryOutput)->isUsedByStrategy(STRATEGY_MEDIA))) { |
| 841 | ALOGV("setOutputDevice: Muting mPrimaryOutput:%d",mPrimaryOutput); |
| 842 | setStrategyMute(STRATEGY_MEDIA, true, mPrimaryOutput); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 843 | } |
| 844 | // wait for the PCM output buffers to empty before proceeding with the rest of the command |
| 845 | usleep(outputDesc->mLatency*2*1000); |
| 846 | } |
| 847 | |
| 848 | // wait for output buffers to be played on the HDMI device before routing to new device |
| 849 | if(prevDevice == AudioSystem::DEVICE_OUT_AUX_DIGITAL) { |
| 850 | if((mLPADecodeOutput != -1 && output == mLPADecodeOutput && |
| 851 | mOutputs.valueFor(mLPADecodeOutput)->isUsedByStrategy(STRATEGY_MEDIA))) { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 852 | checkAndSetVolume(AudioSystem::MUSIC, |
| 853 | mStreams[AudioSystem::MUSIC].mIndexCur.valueFor((audio_devices_t)device), |
| 854 | mLPADecodeOutput, (audio_devices_t)device, delayMs, force); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 855 | usleep(150*1000); |
| 856 | } else { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 857 | checkAndSetVolume(AudioSystem::MUSIC, |
| 858 | mStreams[AudioSystem::MUSIC].mIndexCur.valueFor((audio_devices_t)device), |
| 859 | output, (audio_devices_t)device, delayMs, force); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 860 | usleep(outputDesc->mLatency*6*1000); |
| 861 | } |
| 862 | } |
| 863 | |
| 864 | // do the routing |
| 865 | AudioParameter param = AudioParameter(); |
| 866 | param.addInt(String8(AudioParameter::keyRouting), (int)device); |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 867 | mpClientInterface->setParameters(mPrimaryOutput, param.toString(), delayMs); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 868 | // update stream volumes according to new device |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 869 | AudioPolicyManagerBase::applyStreamVolumes(output, (audio_devices_t)device, delayMs); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 870 | if((mLPADecodeOutput != -1 && |
| 871 | mOutputs.valueFor(mLPADecodeOutput)->isUsedByStrategy(STRATEGY_MEDIA))) { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 872 | AudioPolicyManagerBase::applyStreamVolumes(mLPADecodeOutput, (audio_devices_t)device, delayMs); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 873 | } |
| 874 | |
| 875 | // if changing from a combined headset + speaker route, unmute media streams |
| 876 | if (prevDevice == (AudioSystem::DEVICE_OUT_SPEAKER | AudioSystem::DEVICE_OUT_WIRED_HEADSET) |
| 877 | || prevDevice == (AudioSystem::DEVICE_OUT_SPEAKER | AudioSystem::DEVICE_OUT_ANC_HEADSET) |
| 878 | || prevDevice == (AudioSystem::DEVICE_OUT_SPEAKER | AudioSystem::DEVICE_OUT_ANC_HEADPHONE) |
| 879 | || prevDevice == (AudioSystem::DEVICE_OUT_SPEAKER | AudioSystem::DEVICE_OUT_WIRED_HEADPHONE) |
| 880 | || prevDevice == (AudioSystem::DEVICE_OUT_SPEAKER | AudioSystem::DEVICE_OUT_WIRED_HEADSET | AudioSystem::DEVICE_OUT_FM) |
| 881 | || prevDevice == (AudioSystem::DEVICE_OUT_SPEAKER | AudioSystem::DEVICE_OUT_WIRED_HEADPHONE | AudioSystem::DEVICE_OUT_FM) |
| 882 | || prevDevice == (AudioSystem::DEVICE_OUT_SPEAKER | AudioSystem::DEVICE_OUT_FM_TX)) { |
| 883 | setStrategyMute(STRATEGY_MEDIA, false, output, delayMs); |
| 884 | // Unmute LPA output also if it belongs to STRATEGY_MEDIA |
| 885 | if(((mLPADecodeOutput != -1) && (mLPADecodeOutput != output) && |
| 886 | mOutputs.valueFor(mLPADecodeOutput)->isUsedByStrategy(STRATEGY_MEDIA))) { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 887 | ALOGV("setOutputDevice: Unmuting mLPADecodeOutput:%d delayMs:%d",mLPADecodeOutput,delayMs); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 888 | setStrategyMute(STRATEGY_MEDIA, false, mLPADecodeOutput, delayMs); |
| 889 | } |
| 890 | // Unmute hardware output also if it belongs to STRATEGY_MEDIA |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 891 | if(((mPrimaryOutput != -1) && (mPrimaryOutput != output) && |
| 892 | mOutputs.valueFor(mPrimaryOutput)->isUsedByStrategy(STRATEGY_MEDIA))) { |
| 893 | ALOGV("setOutputDevice: Unmuting mPrimaryOutput:%d delayMs:%d",mPrimaryOutput,delayMs); |
| 894 | setStrategyMute(STRATEGY_MEDIA, false, mPrimaryOutput, delayMs); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 895 | } |
| 896 | } |
| 897 | } |
| 898 | |
| 899 | status_t AudioPolicyManager::checkAndSetVolume(int stream, int index, audio_io_handle_t output, uint32_t device, int delayMs, bool force) |
| 900 | { |
| 901 | // do not change actual stream volume if the stream is muted |
| 902 | if ((mOutputs.valueFor(output)->mMuteCount[stream] != 0 && output != mLPADecodeOutput) || |
| 903 | (output == mLPADecodeOutput && stream == mLPAStreamType && mLPAMuted == true)) { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 904 | ALOGV("checkAndSetVolume() stream %d muted count %d", stream, mOutputs.valueFor(output)->mMuteCount[stream]); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 905 | return NO_ERROR; |
| 906 | } |
| 907 | |
| 908 | // do not change in call volume if bluetooth is connected and vice versa |
| 909 | if ((stream == AudioSystem::VOICE_CALL && mForceUse[AudioSystem::FOR_COMMUNICATION] == AudioSystem::FORCE_BT_SCO) || |
| 910 | (stream == AudioSystem::BLUETOOTH_SCO && mForceUse[AudioSystem::FOR_COMMUNICATION] != AudioSystem::FORCE_BT_SCO)) { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 911 | ALOGV("checkAndSetVolume() cannot set stream %d volume with force use = %d for comm", |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 912 | stream, mForceUse[AudioSystem::FOR_COMMUNICATION]); |
| 913 | return INVALID_OPERATION; |
| 914 | } |
| 915 | |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 916 | float volume = computeVolume(stream, index, output, (audio_devices_t)device); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 917 | // do not set volume if the float value did not change |
| 918 | if ((volume != mOutputs.valueFor(output)->mCurVolume[stream]) || (stream == AudioSystem::VOICE_CALL) || |
| 919 | #ifdef FM_ENABLED |
| 920 | (stream == AudioSystem::FM) || |
| 921 | #endif |
| 922 | force) { |
| 923 | mOutputs.valueFor(output)->mCurVolume[stream] = volume; |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 924 | ALOGD("setStreamVolume() for output %d stream %d, volume %f, delay %d", output, stream, volume, delayMs); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 925 | if (stream == AudioSystem::VOICE_CALL || |
| 926 | stream == AudioSystem::DTMF || |
| 927 | stream == AudioSystem::BLUETOOTH_SCO) { |
| 928 | float voiceVolume = -1.0; |
| 929 | // offset value to reflect actual hardware volume that never reaches 0 |
| 930 | // 1% corresponds roughly to first step in VOICE_CALL stream volume setting (see AudioService.java) |
| 931 | volume = 0.01 + 0.99 * volume; |
| 932 | if (stream == AudioSystem::VOICE_CALL) { |
| 933 | voiceVolume = (float)index/(float)mStreams[stream].mIndexMax; |
| 934 | } else if (stream == AudioSystem::BLUETOOTH_SCO) { |
| 935 | String8 key ("bt_headset_vgs"); |
| 936 | mpClientInterface->getParameters(output,key); |
| 937 | AudioParameter result(mpClientInterface->getParameters(0,key)); |
| 938 | int value; |
| 939 | if(result.getInt(String8("isVGS"),value) == NO_ERROR){ |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 940 | ALOGD("BT-SCO Voice Volume %f",(float)index/(float)mStreams[stream].mIndexMax); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 941 | voiceVolume = 1.0; |
| 942 | } else { |
| 943 | voiceVolume = (float)index/(float)mStreams[stream].mIndexMax; |
| 944 | } |
| 945 | } |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 946 | if (voiceVolume >= 0 && output == mPrimaryOutput) { |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 947 | mpClientInterface->setVoiceVolume(voiceVolume, delayMs); |
| 948 | } |
| 949 | } |
| 950 | #ifdef FM_ENABLED |
| 951 | else if (stream == AudioSystem::FM) { |
| 952 | float fmVolume = -1.0; |
| 953 | fmVolume = computeVolume(stream, index, output, device); |
| 954 | if (fmVolume >= 0) { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 955 | if(output == mPrimaryOutput) |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 956 | mpClientInterface->setFmVolume(fmVolume, delayMs); |
| 957 | else if(output == mA2dpOutput) |
| 958 | mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, volume, output, delayMs); |
| 959 | } |
| 960 | return NO_ERROR; |
| 961 | } |
| 962 | #endif |
| 963 | mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, volume, output, delayMs); |
| 964 | } |
| 965 | |
| 966 | return NO_ERROR; |
| 967 | } |
| 968 | |
| 969 | void AudioPolicyManager::setStreamMute(int stream, bool on, audio_io_handle_t output, int delayMs) |
| 970 | { |
| 971 | StreamDescriptor &streamDesc = mStreams[stream]; |
| 972 | AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output); |
| 973 | |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 974 | ALOGV("setStreamMute() stream %d, mute %d, output %d, mMuteCount %d", stream, on, output, outputDesc->mMuteCount[stream]); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 975 | |
| 976 | if (on) { |
| 977 | if ((outputDesc->mMuteCount[stream] == 0 && output != mLPADecodeOutput) || |
| 978 | (output == mLPADecodeOutput && stream == mLPAStreamType && false == mLPAMuted)) { |
| 979 | if (streamDesc.mCanBeMuted) { |
| 980 | checkAndSetVolume(stream, 0, output, outputDesc->device(), delayMs); |
| 981 | } |
| 982 | } |
| 983 | // increment mMuteCount after calling checkAndSetVolume() so that volume change is not ignored |
| 984 | if(output == mLPADecodeOutput) { |
| 985 | if(stream == mLPAStreamType && false == mLPAMuted) { |
| 986 | mLPAMuted = true; |
| 987 | } |
| 988 | } else { |
| 989 | outputDesc->mMuteCount[stream]++; |
| 990 | } |
| 991 | } else { |
| 992 | if ((outputDesc->mMuteCount[stream] == 0 && output != mLPADecodeOutput) || |
| 993 | (output == mLPADecodeOutput && stream == mLPAStreamType && false == mLPAMuted)) { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 994 | ALOGW("setStreamMute() unmuting non muted stream!"); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 995 | return; |
| 996 | } |
| 997 | if(output == mLPADecodeOutput) { |
| 998 | if(stream == mLPAStreamType && true == mLPAMuted) { |
| 999 | mLPAMuted = false; |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 1000 | checkAndSetVolume(stream, streamDesc.mIndexCur.valueFor(outputDesc->device()), output, outputDesc->device(), delayMs); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 1001 | } |
| 1002 | } else { |
| 1003 | if(--outputDesc->mMuteCount[stream] == 0){ |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 1004 | checkAndSetVolume(stream, streamDesc.mIndexCur.valueFor(outputDesc->device()), output, outputDesc->device(), delayMs); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 1005 | } |
| 1006 | } |
| 1007 | } |
| 1008 | } |
| 1009 | |
| 1010 | void AudioPolicyManager::setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config) |
| 1011 | { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 1012 | ALOGD("setForceUse() usage %d, config %d, mPhoneState %d", usage, config, mPhoneState); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 1013 | |
| 1014 | bool forceVolumeReeval = false; |
| 1015 | switch(usage) { |
| 1016 | case AudioSystem::FOR_COMMUNICATION: |
| 1017 | if (config != AudioSystem::FORCE_SPEAKER && config != AudioSystem::FORCE_BT_SCO && |
| 1018 | config != AudioSystem::FORCE_NONE) { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 1019 | ALOGW("setForceUse() invalid config %d for FOR_COMMUNICATION", config); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 1020 | return; |
| 1021 | } |
| 1022 | mForceUse[usage] = config; |
| 1023 | break; |
| 1024 | case AudioSystem::FOR_MEDIA: |
| 1025 | if (config != AudioSystem::FORCE_HEADPHONES && config != AudioSystem::FORCE_BT_A2DP && |
| 1026 | config != AudioSystem::FORCE_WIRED_ACCESSORY && config != AudioSystem::FORCE_NONE && |
| 1027 | config != AudioSystem::FORCE_SPEAKER) { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 1028 | ALOGW("setForceUse() invalid config %d for FOR_MEDIA", config); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 1029 | return; |
| 1030 | } |
| 1031 | mForceUse[usage] = config; |
| 1032 | { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 1033 | uint32_t device = getDeviceForStrategy(STRATEGY_MEDIA, true); |
| 1034 | setOutputDevice(mPrimaryOutput, device); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 1035 | } |
| 1036 | break; |
| 1037 | case AudioSystem::FOR_RECORD: |
| 1038 | if (config != AudioSystem::FORCE_BT_SCO && config != AudioSystem::FORCE_WIRED_ACCESSORY && |
| 1039 | config != AudioSystem::FORCE_NONE) { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 1040 | ALOGW("setForceUse() invalid config %d for FOR_RECORD", config); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 1041 | return; |
| 1042 | } |
| 1043 | mForceUse[usage] = config; |
| 1044 | break; |
| 1045 | case AudioSystem::FOR_DOCK: |
| 1046 | if (config != AudioSystem::FORCE_NONE && config != AudioSystem::FORCE_BT_CAR_DOCK && |
| 1047 | config != AudioSystem::FORCE_BT_DESK_DOCK && config != AudioSystem::FORCE_WIRED_ACCESSORY) { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 1048 | ALOGW("setForceUse() invalid config %d for FOR_DOCK", config); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 1049 | } |
| 1050 | forceVolumeReeval = true; |
| 1051 | mForceUse[usage] = config; |
| 1052 | break; |
| 1053 | default: |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 1054 | ALOGW("setForceUse() invalid usage %d", usage); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 1055 | break; |
| 1056 | } |
| 1057 | |
| 1058 | // check for device and output changes triggered by new phone state |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 1059 | uint32_t newDevice = getNewDevice(mPrimaryOutput, false); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 1060 | #ifdef WITH_A2DP |
| 1061 | AudioPolicyManagerBase::checkA2dpSuspend(); |
| 1062 | checkOutputForAllStrategies(); |
| 1063 | #endif |
| 1064 | updateDeviceForStrategy(); |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 1065 | setOutputDevice(mPrimaryOutput, newDevice); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 1066 | if (forceVolumeReeval) { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 1067 | applyStreamVolumes(mPrimaryOutput, (audio_devices_t)newDevice); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 1068 | } |
| 1069 | } |
| 1070 | |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 1071 | audio_devices_t AudioPolicyManager::getDeviceForInputSource(int inputSource) |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 1072 | { |
| 1073 | uint32_t device; |
| 1074 | |
| 1075 | switch(inputSource) { |
| 1076 | case AUDIO_SOURCE_DEFAULT: |
| 1077 | case AUDIO_SOURCE_MIC: |
| 1078 | case AUDIO_SOURCE_VOICE_RECOGNITION: |
| 1079 | if (mForceUse[AudioSystem::FOR_RECORD] == AudioSystem::FORCE_BT_SCO && |
| 1080 | mAvailableInputDevices & AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET) { |
| 1081 | device = AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET; |
| 1082 | } else if (mAvailableInputDevices & AudioSystem::DEVICE_IN_WIRED_HEADSET) { |
| 1083 | device = AudioSystem::DEVICE_IN_WIRED_HEADSET; |
| 1084 | } else if (mAvailableInputDevices & AudioSystem::DEVICE_IN_ANC_HEADSET) { |
| 1085 | device = AudioSystem::DEVICE_IN_ANC_HEADSET; |
| 1086 | } else if (mAvailableInputDevices & AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET) { |
| 1087 | device = AudioSystem::DEVICE_IN_PROXY; |
| 1088 | } else { |
| 1089 | device = AudioSystem::DEVICE_IN_BUILTIN_MIC; |
| 1090 | } |
| 1091 | break; |
| 1092 | case AUDIO_SOURCE_VOICE_COMMUNICATION: |
| 1093 | device = AudioSystem::DEVICE_IN_COMMUNICATION; |
| 1094 | break; |
| 1095 | case AUDIO_SOURCE_CAMCORDER: |
| 1096 | if (hasBackMicrophone()) { |
| 1097 | device = AudioSystem::DEVICE_IN_BACK_MIC; |
| 1098 | } else { |
| 1099 | device = AudioSystem::DEVICE_IN_BUILTIN_MIC; |
| 1100 | } |
| 1101 | break; |
| 1102 | case AUDIO_SOURCE_VOICE_UPLINK: |
| 1103 | case AUDIO_SOURCE_VOICE_DOWNLINK: |
| 1104 | case AUDIO_SOURCE_VOICE_CALL: |
| 1105 | device = AudioSystem::DEVICE_IN_VOICE_CALL; |
| 1106 | break; |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 1107 | #if 0 |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 1108 | case AUDIO_SOURCE_FM_RX: |
| 1109 | device = AudioSystem::DEVICE_IN_FM_RX; |
| 1110 | break; |
| 1111 | case AUDIO_SOURCE_FM_RX_A2DP: |
| 1112 | device = AudioSystem::DEVICE_IN_FM_RX_A2DP; |
| 1113 | break; |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 1114 | #endif |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 1115 | default: |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 1116 | ALOGW("getInput() invalid input source %d", inputSource); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 1117 | device = 0; |
| 1118 | break; |
| 1119 | } |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 1120 | ALOGV("getDeviceForInputSource()input source %d, device %08x", inputSource, device); |
| 1121 | if (!device) |
| 1122 | ALOGE("%s: did not select device for input source %d", |
| 1123 | __FUNCTION__, inputSource); |
| 1124 | return (audio_devices_t)device; |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 1125 | } |
| 1126 | |
| 1127 | /* |
| 1128 | Overwriting this function from base class to allow 2 acitve AudioRecord clients in case of FM. |
| 1129 | One for FM A2DP playbck and other for FM recording. |
| 1130 | */ |
| 1131 | status_t AudioPolicyManager::startInput(audio_io_handle_t input) |
| 1132 | { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 1133 | ALOGV("startInput() input %d", input); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 1134 | ssize_t index = mInputs.indexOfKey(input); |
| 1135 | if (index < 0) { |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 1136 | ALOGW("startInput() unknow input %d", input); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 1137 | return BAD_VALUE; |
| 1138 | } |
| 1139 | AudioInputDescriptor *inputDesc = mInputs.valueAt(index); |
| 1140 | AudioParameter param = AudioParameter(); |
| 1141 | param.addInt(String8(AudioParameter::keyRouting), (int)inputDesc->mDevice); |
| 1142 | // use Voice Recognition mode or not for this input based on input source |
| 1143 | int vr_enabled = inputDesc->mInputSource == AUDIO_SOURCE_VOICE_RECOGNITION ? 1 : 0; |
| 1144 | param.addInt(String8("vr_mode"), vr_enabled); |
Iliyan Malchev | 4113f34 | 2012-06-11 14:39:47 -0700 | [diff] [blame^] | 1145 | ALOGV("AudioPolicyManager::startInput(%d), setting vr_mode to %d", inputDesc->mInputSource, vr_enabled); |
Iliyan Malchev | 4765c43 | 2012-06-11 14:36:16 -0700 | [diff] [blame] | 1146 | mpClientInterface->setParameters(input, param.toString()); |
| 1147 | inputDesc->mRefCount = 1; |
| 1148 | return NO_ERROR; |
| 1149 | } |
| 1150 | |
| 1151 | }; // namespace androidi_audio_legacy |