Eric Laurent | 9d91ad5 | 2009-07-17 12:17:14 -0700 | [diff] [blame] | 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 "AudioPolicyManagerGeneric" |
| 18 | //#define LOG_NDEBUG 0 |
| 19 | #include <utils/Log.h> |
| 20 | #include "AudioPolicyManagerGeneric.h" |
| 21 | #include <media/mediarecorder.h> |
| 22 | |
| 23 | namespace android { |
| 24 | |
| 25 | |
| 26 | // ---------------------------------------------------------------------------- |
| 27 | // AudioPolicyInterface implementation |
| 28 | // ---------------------------------------------------------------------------- |
| 29 | |
| 30 | |
| 31 | status_t AudioPolicyManagerGeneric::setDeviceConnectionState(AudioSystem::audio_devices device, |
| 32 | AudioSystem::device_connection_state state, |
| 33 | const char *device_address) |
| 34 | { |
| 35 | |
| 36 | LOGV("setDeviceConnectionState() device: %x, state %d, address %s", device, state, device_address); |
| 37 | |
| 38 | // connect/disconnect only 1 device at a time |
| 39 | if (AudioSystem::popCount(device) != 1) return BAD_VALUE; |
| 40 | |
| 41 | if (strlen(device_address) >= MAX_DEVICE_ADDRESS_LEN) { |
| 42 | LOGE("setDeviceConnectionState() invalid address: %s", device_address); |
| 43 | return BAD_VALUE; |
| 44 | } |
| 45 | |
| 46 | // handle output devices |
| 47 | if (AudioSystem::isOutputDevice(device)) { |
| 48 | switch (state) |
| 49 | { |
| 50 | // handle output device connection |
| 51 | case AudioSystem::DEVICE_STATE_AVAILABLE: |
| 52 | if (mAvailableOutputDevices & device) { |
| 53 | LOGW("setDeviceConnectionState() device already connected: %x", device); |
| 54 | return INVALID_OPERATION; |
| 55 | } |
| 56 | LOGV("setDeviceConnectionState() connecting device %x", device); |
| 57 | |
| 58 | // register new device as available |
| 59 | mAvailableOutputDevices |= device; |
| 60 | break; |
| 61 | // handle output device disconnection |
| 62 | case AudioSystem::DEVICE_STATE_UNAVAILABLE: |
| 63 | if (!(mAvailableOutputDevices & device)) { |
| 64 | LOGW("setDeviceConnectionState() device not connected: %x", device); |
| 65 | return INVALID_OPERATION; |
| 66 | } |
| 67 | LOGV("setDeviceConnectionState() disconnecting device %x", device); |
| 68 | // remove device from available output devices |
| 69 | mAvailableOutputDevices &= ~device; |
| 70 | break; |
| 71 | |
| 72 | default: |
| 73 | LOGE("setDeviceConnectionState() invalid state: %x", state); |
| 74 | return BAD_VALUE; |
| 75 | } |
| 76 | return NO_ERROR; |
| 77 | } |
| 78 | // handle input devices |
| 79 | if (AudioSystem::isInputDevice(device)) { |
| 80 | switch (state) |
| 81 | { |
| 82 | // handle input device connection |
| 83 | case AudioSystem::DEVICE_STATE_AVAILABLE: |
| 84 | if (mAvailableInputDevices & device) { |
| 85 | LOGW("setDeviceConnectionState() device already connected: %d", device); |
| 86 | return INVALID_OPERATION; |
| 87 | } |
| 88 | mAvailableInputDevices |= device; |
| 89 | break; |
| 90 | |
| 91 | // handle input device disconnection |
| 92 | case AudioSystem::DEVICE_STATE_UNAVAILABLE: |
| 93 | if (!(mAvailableInputDevices & device)) { |
| 94 | LOGW("setDeviceConnectionState() device not connected: %d", device); |
| 95 | return INVALID_OPERATION; |
| 96 | } |
| 97 | mAvailableInputDevices &= ~device; |
| 98 | break; |
| 99 | |
| 100 | default: |
| 101 | LOGE("setDeviceConnectionState() invalid state: %x", state); |
| 102 | return BAD_VALUE; |
| 103 | } |
| 104 | return NO_ERROR; |
| 105 | } |
| 106 | |
| 107 | LOGW("setDeviceConnectionState() invalid device: %x", device); |
| 108 | return BAD_VALUE; |
| 109 | } |
| 110 | |
| 111 | AudioSystem::device_connection_state AudioPolicyManagerGeneric::getDeviceConnectionState(AudioSystem::audio_devices device, |
| 112 | const char *device_address) |
| 113 | { |
| 114 | AudioSystem::device_connection_state state = AudioSystem::DEVICE_STATE_UNAVAILABLE; |
| 115 | String8 address = String8(device_address); |
| 116 | if (AudioSystem::isOutputDevice(device)) { |
| 117 | if (device & mAvailableOutputDevices) { |
| 118 | state = AudioSystem::DEVICE_STATE_AVAILABLE; |
| 119 | } |
| 120 | } else if (AudioSystem::isInputDevice(device)) { |
| 121 | if (device & mAvailableInputDevices) { |
| 122 | state = AudioSystem::DEVICE_STATE_AVAILABLE; |
| 123 | } |
| 124 | } |
| 125 | |
| 126 | return state; |
| 127 | } |
| 128 | |
| 129 | void AudioPolicyManagerGeneric::setPhoneState(int state) |
| 130 | { |
| 131 | LOGV("setPhoneState() state %d", state); |
| 132 | uint32_t newDevice = 0; |
| 133 | if (state < 0 || state >= AudioSystem::NUM_MODES) { |
| 134 | LOGW("setPhoneState() invalid state %d", state); |
| 135 | return; |
| 136 | } |
| 137 | |
| 138 | if (state == mPhoneState ) { |
| 139 | LOGW("setPhoneState() setting same state %d", state); |
| 140 | return; |
| 141 | } |
| 142 | // store previous phone state for management of sonification strategy below |
| 143 | int oldState = mPhoneState; |
| 144 | mPhoneState = state; |
| 145 | |
| 146 | // if leaving or entering in call state, handle special case of active streams |
| 147 | // pertaining to sonification strategy see handleIncallSonification() |
| 148 | if (state == AudioSystem::MODE_IN_CALL || |
| 149 | oldState == AudioSystem::MODE_IN_CALL) { |
| 150 | bool starting = (state == AudioSystem::MODE_IN_CALL) ? true : false; |
| 151 | LOGV("setPhoneState() in call state management: new state is %d", state); |
| 152 | for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) { |
| 153 | handleIncallSonification(stream, starting); |
| 154 | } |
| 155 | } |
| 156 | } |
| 157 | |
| 158 | void AudioPolicyManagerGeneric::setRingerMode(uint32_t mode, uint32_t mask) |
| 159 | { |
| 160 | LOGV("setRingerMode() mode %x, mask %x", mode, mask); |
| 161 | |
| 162 | mRingerMode = mode; |
| 163 | } |
| 164 | |
| 165 | void AudioPolicyManagerGeneric::setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config) |
| 166 | { |
| 167 | LOGV("setForceUse) usage %d, config %d, mPhoneState %d", usage, config, mPhoneState); |
| 168 | mForceUse[usage] = config; |
| 169 | } |
| 170 | |
| 171 | AudioSystem::forced_config AudioPolicyManagerGeneric::getForceUse(AudioSystem::force_use usage) |
| 172 | { |
| 173 | return mForceUse[usage]; |
| 174 | } |
| 175 | |
| 176 | void AudioPolicyManagerGeneric::setSystemProperty(const char* property, const char* value) |
| 177 | { |
| 178 | LOGV("setSystemProperty() property %s, value %s", property, value); |
| 179 | if (strcmp(property, "ro.camera.sound.forced") == 0) { |
| 180 | if (atoi(value)) { |
| 181 | LOGV("ENFORCED_AUDIBLE cannot be muted"); |
| 182 | mStreams[AudioSystem::ENFORCED_AUDIBLE].mCanBeMuted = false; |
| 183 | } else { |
| 184 | LOGV("ENFORCED_AUDIBLE can be muted"); |
| 185 | mStreams[AudioSystem::ENFORCED_AUDIBLE].mCanBeMuted = true; |
| 186 | } |
| 187 | } |
| 188 | } |
| 189 | |
| 190 | audio_io_handle_t AudioPolicyManagerGeneric::getOutput(AudioSystem::stream_type stream, |
| 191 | uint32_t samplingRate, |
| 192 | uint32_t format, |
| 193 | uint32_t channels, |
| 194 | AudioSystem::output_flags flags) |
| 195 | { |
| 196 | LOGV("getOutput() stream %d, samplingRate %d, format %d, channels %x, flags %x", stream, samplingRate, format, channels, flags); |
| 197 | |
| 198 | #ifdef AUDIO_POLICY_TEST |
| 199 | if (mCurOutput != 0) { |
| 200 | LOGV("getOutput() test output mCurOutput %d, samplingRate %d, format %d, channelcount %d, mDirectOutput %d", |
| 201 | mCurOutput, mTestSamplingRate, mTestFormat, mTestChannelcount, mDirectOutput); |
| 202 | |
| 203 | if (mTestOutputs[mCurOutput] == 0) { |
| 204 | LOGV("getOutput() opening test output"); |
| 205 | AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(); |
| 206 | outputDesc->mDevice = mTestDevice; |
| 207 | outputDesc->mSamplingRate = mTestSamplingRate; |
| 208 | outputDesc->mFormat = mTestFormat; |
| 209 | outputDesc->mChannels = (mTestChannelcount == 1) ? AudioSystem::CHANNEL_OUT_MONO : AudioSystem::CHANNEL_OUT_STEREO; |
| 210 | outputDesc->mLatency = mTestLatencyMs; |
| 211 | outputDesc->mFlags = (AudioSystem::output_flags)(mDirectOutput ? AudioSystem::OUTPUT_FLAG_DIRECT : 0); |
| 212 | outputDesc->mRefCount[stream] = 0; |
| 213 | mTestOutputs[mCurOutput] = mpClientInterface->openOutput(&outputDesc->mDevice, |
| 214 | &outputDesc->mSamplingRate, |
| 215 | &outputDesc->mFormat, |
| 216 | &outputDesc->mChannels, |
| 217 | &outputDesc->mLatency, |
| 218 | outputDesc->mFlags); |
| 219 | mOutputs.add(mTestOutputs[mCurOutput], outputDesc); |
| 220 | } |
| 221 | return mTestOutputs[mCurOutput]; |
| 222 | } |
| 223 | #endif //AUDIO_POLICY_TEST |
| 224 | if ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) || |
| 225 | (format != 0 && !AudioSystem::isLinearPCM(format)) || |
| 226 | (channels != 0 && channels != AudioSystem::CHANNEL_OUT_MONO && channels != AudioSystem::CHANNEL_OUT_STEREO)) { |
Eric Laurent | e0e9ecc | 2009-07-28 08:44:33 -0700 | [diff] [blame^] | 227 | return 0; |
Eric Laurent | 9d91ad5 | 2009-07-17 12:17:14 -0700 | [diff] [blame] | 228 | } |
| 229 | |
| 230 | return mHardwareOutput; |
| 231 | } |
| 232 | |
| 233 | status_t AudioPolicyManagerGeneric::startOutput(audio_io_handle_t output, AudioSystem::stream_type stream) |
| 234 | { |
Eric Laurent | e0e9ecc | 2009-07-28 08:44:33 -0700 | [diff] [blame^] | 235 | LOGV("startOutput() output %d, stream %d", output, stream); |
Eric Laurent | 9d91ad5 | 2009-07-17 12:17:14 -0700 | [diff] [blame] | 236 | ssize_t index = mOutputs.indexOfKey(output); |
| 237 | if (index < 0) { |
Eric Laurent | e0e9ecc | 2009-07-28 08:44:33 -0700 | [diff] [blame^] | 238 | LOGW("startOutput() unknow output %d", output); |
Eric Laurent | 9d91ad5 | 2009-07-17 12:17:14 -0700 | [diff] [blame] | 239 | return BAD_VALUE; |
| 240 | } |
| 241 | |
| 242 | AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index); |
| 243 | |
| 244 | // handle special case for sonification while in call |
| 245 | if (mPhoneState == AudioSystem::MODE_IN_CALL) { |
| 246 | handleIncallSonification(stream, true); |
| 247 | } |
| 248 | |
| 249 | // incremenent usage count for this stream on the requested output: |
| 250 | outputDesc->changeRefCount(stream, 1); |
| 251 | return NO_ERROR; |
| 252 | } |
| 253 | |
| 254 | status_t AudioPolicyManagerGeneric::stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream) |
| 255 | { |
Eric Laurent | e0e9ecc | 2009-07-28 08:44:33 -0700 | [diff] [blame^] | 256 | LOGV("stopOutput() output %d, stream %d", output, stream); |
Eric Laurent | 9d91ad5 | 2009-07-17 12:17:14 -0700 | [diff] [blame] | 257 | ssize_t index = mOutputs.indexOfKey(output); |
| 258 | if (index < 0) { |
Eric Laurent | e0e9ecc | 2009-07-28 08:44:33 -0700 | [diff] [blame^] | 259 | LOGW("stopOutput() unknow output %d", output); |
Eric Laurent | 9d91ad5 | 2009-07-17 12:17:14 -0700 | [diff] [blame] | 260 | return BAD_VALUE; |
| 261 | } |
| 262 | |
| 263 | AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index); |
| 264 | |
| 265 | // handle special case for sonification while in call |
| 266 | if (mPhoneState == AudioSystem::MODE_IN_CALL) { |
| 267 | handleIncallSonification(stream, false); |
| 268 | } |
| 269 | |
| 270 | if (outputDesc->isUsedByStream(stream)) { |
| 271 | // decrement usage count of this stream on the output |
| 272 | outputDesc->changeRefCount(stream, -1); |
| 273 | return NO_ERROR; |
| 274 | } else { |
Eric Laurent | e0e9ecc | 2009-07-28 08:44:33 -0700 | [diff] [blame^] | 275 | LOGW("stopOutput() refcount is already 0 for output %d", output); |
Eric Laurent | 9d91ad5 | 2009-07-17 12:17:14 -0700 | [diff] [blame] | 276 | return INVALID_OPERATION; |
| 277 | } |
| 278 | } |
| 279 | |
| 280 | void AudioPolicyManagerGeneric::releaseOutput(audio_io_handle_t output) |
| 281 | { |
Eric Laurent | e0e9ecc | 2009-07-28 08:44:33 -0700 | [diff] [blame^] | 282 | LOGV("releaseOutput() %d", output); |
Eric Laurent | 9d91ad5 | 2009-07-17 12:17:14 -0700 | [diff] [blame] | 283 | ssize_t index = mOutputs.indexOfKey(output); |
| 284 | if (index < 0) { |
Eric Laurent | e0e9ecc | 2009-07-28 08:44:33 -0700 | [diff] [blame^] | 285 | LOGW("releaseOutput() releasing unknown output %d", output); |
Eric Laurent | 9d91ad5 | 2009-07-17 12:17:14 -0700 | [diff] [blame] | 286 | return; |
| 287 | } |
| 288 | |
| 289 | #ifdef AUDIO_POLICY_TEST |
| 290 | int testIndex = testOutputIndex(output); |
| 291 | if (testIndex != 0) { |
| 292 | AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index); |
| 293 | if (outputDesc->refCount() == 0) { |
| 294 | mpClientInterface->closeOutput(output); |
| 295 | delete mOutputs.valueAt(index); |
| 296 | mOutputs.removeItem(output); |
| 297 | mTestOutputs[testIndex] = 0; |
| 298 | } |
| 299 | } |
| 300 | #endif //AUDIO_POLICY_TEST |
| 301 | } |
| 302 | |
| 303 | audio_io_handle_t AudioPolicyManagerGeneric::getInput(int inputSource, |
| 304 | uint32_t samplingRate, |
| 305 | uint32_t format, |
| 306 | uint32_t channels, |
| 307 | AudioSystem::audio_in_acoustics acoustics) |
| 308 | { |
| 309 | audio_io_handle_t input = 0; |
| 310 | uint32_t device; |
| 311 | |
| 312 | LOGV("getInput() inputSource %d, samplingRate %d, format %d, channels %x, acoustics %x", inputSource, samplingRate, format, channels, acoustics); |
| 313 | |
| 314 | AudioInputDescriptor *inputDesc = new AudioInputDescriptor(); |
| 315 | inputDesc->mDevice = AudioSystem::DEVICE_IN_BUILTIN_MIC; |
| 316 | inputDesc->mSamplingRate = samplingRate; |
| 317 | inputDesc->mFormat = format; |
| 318 | inputDesc->mChannels = channels; |
| 319 | inputDesc->mAcoustics = acoustics; |
| 320 | inputDesc->mRefCount = 0; |
| 321 | input = mpClientInterface->openInput(&inputDesc->mDevice, |
| 322 | &inputDesc->mSamplingRate, |
| 323 | &inputDesc->mFormat, |
| 324 | &inputDesc->mChannels, |
| 325 | inputDesc->mAcoustics); |
| 326 | |
| 327 | // only accept input with the exact requested set of parameters |
| 328 | if ((samplingRate != inputDesc->mSamplingRate) || |
| 329 | (format != inputDesc->mFormat) || |
| 330 | (channels != inputDesc->mChannels)) { |
| 331 | LOGV("getOutput() failed opening input: samplingRate %d, format %d, channels %d", |
| 332 | samplingRate, format, channels); |
| 333 | mpClientInterface->closeInput(input); |
| 334 | delete inputDesc; |
Eric Laurent | e0e9ecc | 2009-07-28 08:44:33 -0700 | [diff] [blame^] | 335 | return 0; |
Eric Laurent | 9d91ad5 | 2009-07-17 12:17:14 -0700 | [diff] [blame] | 336 | } |
| 337 | mInputs.add(input, inputDesc); |
| 338 | return input; |
| 339 | } |
| 340 | |
| 341 | status_t AudioPolicyManagerGeneric::startInput(audio_io_handle_t input) |
| 342 | { |
Eric Laurent | e0e9ecc | 2009-07-28 08:44:33 -0700 | [diff] [blame^] | 343 | LOGV("startInput() input %d", input); |
Eric Laurent | 9d91ad5 | 2009-07-17 12:17:14 -0700 | [diff] [blame] | 344 | ssize_t index = mInputs.indexOfKey(input); |
| 345 | if (index < 0) { |
Eric Laurent | e0e9ecc | 2009-07-28 08:44:33 -0700 | [diff] [blame^] | 346 | LOGW("startInput() unknow input %d", input); |
Eric Laurent | 9d91ad5 | 2009-07-17 12:17:14 -0700 | [diff] [blame] | 347 | return BAD_VALUE; |
| 348 | } |
| 349 | AudioInputDescriptor *inputDesc = mInputs.valueAt(index); |
| 350 | |
| 351 | #ifdef AUDIO_POLICY_TEST |
| 352 | if (mTestInput == 0) |
| 353 | #endif //AUDIO_POLICY_TEST |
| 354 | { |
| 355 | // refuse 2 active AudioRecord clients at the same time |
| 356 | for (size_t i = 0; i < mInputs.size(); i++) { |
| 357 | if (mInputs.valueAt(i)->mRefCount > 0) { |
Eric Laurent | e0e9ecc | 2009-07-28 08:44:33 -0700 | [diff] [blame^] | 358 | LOGW("startInput() input %d, other input %d already started", input, mInputs.keyAt(i)); |
Eric Laurent | 9d91ad5 | 2009-07-17 12:17:14 -0700 | [diff] [blame] | 359 | return INVALID_OPERATION; |
| 360 | } |
| 361 | } |
| 362 | } |
| 363 | |
| 364 | inputDesc->mRefCount = 1; |
| 365 | return NO_ERROR; |
| 366 | } |
| 367 | |
| 368 | status_t AudioPolicyManagerGeneric::stopInput(audio_io_handle_t input) |
| 369 | { |
Eric Laurent | e0e9ecc | 2009-07-28 08:44:33 -0700 | [diff] [blame^] | 370 | LOGV("stopInput() input %d", input); |
Eric Laurent | 9d91ad5 | 2009-07-17 12:17:14 -0700 | [diff] [blame] | 371 | ssize_t index = mInputs.indexOfKey(input); |
| 372 | if (index < 0) { |
Eric Laurent | e0e9ecc | 2009-07-28 08:44:33 -0700 | [diff] [blame^] | 373 | LOGW("stopInput() unknow input %d", input); |
Eric Laurent | 9d91ad5 | 2009-07-17 12:17:14 -0700 | [diff] [blame] | 374 | return BAD_VALUE; |
| 375 | } |
| 376 | AudioInputDescriptor *inputDesc = mInputs.valueAt(index); |
| 377 | |
| 378 | if (inputDesc->mRefCount == 0) { |
Eric Laurent | e0e9ecc | 2009-07-28 08:44:33 -0700 | [diff] [blame^] | 379 | LOGW("stopInput() input %d already stopped", input); |
Eric Laurent | 9d91ad5 | 2009-07-17 12:17:14 -0700 | [diff] [blame] | 380 | return INVALID_OPERATION; |
| 381 | } else { |
| 382 | inputDesc->mRefCount = 0; |
| 383 | return NO_ERROR; |
| 384 | } |
| 385 | } |
| 386 | |
| 387 | void AudioPolicyManagerGeneric::releaseInput(audio_io_handle_t input) |
| 388 | { |
Eric Laurent | e0e9ecc | 2009-07-28 08:44:33 -0700 | [diff] [blame^] | 389 | LOGV("releaseInput() %d", input); |
Eric Laurent | 9d91ad5 | 2009-07-17 12:17:14 -0700 | [diff] [blame] | 390 | ssize_t index = mInputs.indexOfKey(input); |
| 391 | if (index < 0) { |
Eric Laurent | e0e9ecc | 2009-07-28 08:44:33 -0700 | [diff] [blame^] | 392 | LOGW("releaseInput() releasing unknown input %d", input); |
Eric Laurent | 9d91ad5 | 2009-07-17 12:17:14 -0700 | [diff] [blame] | 393 | return; |
| 394 | } |
| 395 | mpClientInterface->closeInput(input); |
| 396 | delete mInputs.valueAt(index); |
| 397 | mInputs.removeItem(input); |
| 398 | } |
| 399 | |
| 400 | |
| 401 | |
| 402 | void AudioPolicyManagerGeneric::initStreamVolume(AudioSystem::stream_type stream, |
| 403 | int indexMin, |
| 404 | int indexMax) |
| 405 | { |
| 406 | LOGV("initStreamVolume() stream %d, min %d, max %d", stream , indexMin, indexMax); |
| 407 | mStreams[stream].mIndexMin = indexMin; |
| 408 | mStreams[stream].mIndexMax = indexMax; |
| 409 | } |
| 410 | |
| 411 | status_t AudioPolicyManagerGeneric::setStreamVolumeIndex(AudioSystem::stream_type stream, int index) |
| 412 | { |
| 413 | |
| 414 | if ((index < mStreams[stream].mIndexMin) || (index > mStreams[stream].mIndexMax)) { |
| 415 | return BAD_VALUE; |
| 416 | } |
| 417 | |
| 418 | LOGV("setStreamVolumeIndex() stream %d, index %d", stream, index); |
| 419 | mStreams[stream].mIndexCur = index; |
| 420 | |
| 421 | // do not change actual stream volume if the stream is muted |
| 422 | if (mStreams[stream].mMuteCount != 0) { |
| 423 | return NO_ERROR; |
| 424 | } |
| 425 | |
| 426 | // Do not changed in call volume if bluetooth is connected and vice versa |
| 427 | if ((stream == AudioSystem::VOICE_CALL && mForceUse[AudioSystem::FOR_COMMUNICATION] == AudioSystem::FORCE_BT_SCO) || |
| 428 | (stream == AudioSystem::BLUETOOTH_SCO && mForceUse[AudioSystem::FOR_COMMUNICATION] != AudioSystem::FORCE_BT_SCO)) { |
| 429 | LOGV("setStreamVolumeIndex() cannot set stream %d volume with force use = %d for comm", |
| 430 | stream, mForceUse[AudioSystem::FOR_COMMUNICATION]); |
| 431 | return INVALID_OPERATION; |
| 432 | } |
| 433 | |
| 434 | // compute and apply stream volume on all outputs according to connected device |
| 435 | for (size_t i = 0; i < mOutputs.size(); i++) { |
| 436 | AudioOutputDescriptor *outputDesc = mOutputs.valueAt(i); |
| 437 | uint32_t device = outputDesc->device(); |
| 438 | |
| 439 | float volume = computeVolume((int)stream, index, device); |
| 440 | |
Eric Laurent | e0e9ecc | 2009-07-28 08:44:33 -0700 | [diff] [blame^] | 441 | LOGV("setStreamVolume() for output %d stream %d, volume %f", mOutputs.keyAt(i), stream, volume); |
Eric Laurent | 9d91ad5 | 2009-07-17 12:17:14 -0700 | [diff] [blame] | 442 | mpClientInterface->setStreamVolume(stream, volume, mOutputs.keyAt(i)); |
| 443 | } |
| 444 | return NO_ERROR; |
| 445 | } |
| 446 | |
| 447 | status_t AudioPolicyManagerGeneric::getStreamVolumeIndex(AudioSystem::stream_type stream, int *index) |
| 448 | { |
| 449 | if (index == 0) { |
| 450 | return BAD_VALUE; |
| 451 | } |
| 452 | LOGV("getStreamVolumeIndex() stream %d", stream); |
| 453 | *index = mStreams[stream].mIndexCur; |
| 454 | return NO_ERROR; |
| 455 | } |
| 456 | |
| 457 | // ---------------------------------------------------------------------------- |
| 458 | // AudioPolicyManagerGeneric |
| 459 | // ---------------------------------------------------------------------------- |
| 460 | |
| 461 | // --- class factory |
| 462 | |
Eric Laurent | 9d91ad5 | 2009-07-17 12:17:14 -0700 | [diff] [blame] | 463 | AudioPolicyManagerGeneric::AudioPolicyManagerGeneric(AudioPolicyClientInterface *clientInterface) |
| 464 | : |
| 465 | #ifdef AUDIO_POLICY_TEST |
| 466 | Thread(false), |
| 467 | #endif //AUDIO_POLICY_TEST |
| 468 | mPhoneState(AudioSystem::MODE_NORMAL), mRingerMode(0) |
| 469 | { |
| 470 | mpClientInterface = clientInterface; |
| 471 | |
| 472 | for (int i = 0; i < AudioSystem::NUM_FORCE_USE; i++) { |
| 473 | mForceUse[i] = AudioSystem::FORCE_NONE; |
| 474 | } |
| 475 | |
| 476 | // devices available by default are speaker, ear piece and microphone |
| 477 | mAvailableOutputDevices = AudioSystem::DEVICE_OUT_SPEAKER; |
| 478 | mAvailableInputDevices = AudioSystem::DEVICE_IN_BUILTIN_MIC; |
| 479 | |
| 480 | // open hardware output |
| 481 | AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(); |
| 482 | outputDesc->mDevice = (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER; |
| 483 | mHardwareOutput = mpClientInterface->openOutput(&outputDesc->mDevice, |
| 484 | &outputDesc->mSamplingRate, |
| 485 | &outputDesc->mFormat, |
| 486 | &outputDesc->mChannels, |
| 487 | &outputDesc->mLatency, |
| 488 | outputDesc->mFlags); |
| 489 | |
| 490 | if (mHardwareOutput == 0) { |
| 491 | LOGE("Failed to initialize hardware output stream, samplingRate: %d, format %d, channels %d", |
| 492 | outputDesc->mSamplingRate, outputDesc->mFormat, outputDesc->mChannels); |
| 493 | } else { |
| 494 | mOutputs.add(mHardwareOutput, outputDesc); |
| 495 | } |
| 496 | |
| 497 | #ifdef AUDIO_POLICY_TEST |
| 498 | mTestDevice = AudioSystem::DEVICE_OUT_SPEAKER; |
| 499 | mTestSamplingRate = 44100; |
| 500 | mTestFormat = AudioSystem::PCM_16_BIT; |
| 501 | mTestChannelcount = 2; |
| 502 | mTestLatencyMs = 0; |
| 503 | mCurOutput = 0; |
| 504 | mDirectOutput = false; |
| 505 | for (int i = 0; i < NUM_TEST_OUTPUTS; i++) { |
| 506 | mTestOutputs[i] = 0; |
| 507 | } |
| 508 | |
| 509 | const size_t SIZE = 256; |
| 510 | char buffer[SIZE]; |
| 511 | snprintf(buffer, SIZE, "AudioPolicyManagerTest"); |
| 512 | run(buffer, ANDROID_PRIORITY_AUDIO); |
| 513 | #endif //AUDIO_POLICY_TEST |
| 514 | } |
| 515 | |
| 516 | AudioPolicyManagerGeneric::~AudioPolicyManagerGeneric() |
| 517 | { |
| 518 | #ifdef AUDIO_POLICY_TEST |
| 519 | exit(); |
| 520 | #endif //AUDIO_POLICY_TEST |
| 521 | |
| 522 | for (size_t i = 0; i < mOutputs.size(); i++) { |
| 523 | mpClientInterface->closeOutput(mOutputs.keyAt(i)); |
| 524 | delete mOutputs.valueAt(i); |
| 525 | } |
| 526 | mOutputs.clear(); |
| 527 | for (size_t i = 0; i < mInputs.size(); i++) { |
| 528 | mpClientInterface->closeInput(mInputs.keyAt(i)); |
| 529 | delete mInputs.valueAt(i); |
| 530 | } |
| 531 | mInputs.clear(); |
| 532 | } |
| 533 | |
| 534 | #ifdef AUDIO_POLICY_TEST |
| 535 | bool AudioPolicyManagerGeneric::threadLoop() |
| 536 | { |
| 537 | LOGV("entering threadLoop()"); |
| 538 | while (!exitPending()) |
| 539 | { |
| 540 | Mutex::Autolock _l(mLock); |
| 541 | mWaitWorkCV.waitRelative(mLock, milliseconds(50)); |
| 542 | String8 command; |
| 543 | command = mpClientInterface->getParameters(0, String8("test_cmd_policy")); |
| 544 | if (command != "") { |
| 545 | LOGV("Test command %s received", command.string()); |
| 546 | AudioParameter param = AudioParameter(command); |
| 547 | int valueInt; |
| 548 | String8 value; |
| 549 | if (param.getInt(String8("test_cmd_policy_output"), valueInt) == NO_ERROR) { |
| 550 | param.remove(String8("test_cmd_policy_output")); |
| 551 | mCurOutput = valueInt; |
| 552 | } |
| 553 | if (param.get(String8("test_cmd_policy_direct"), value) == NO_ERROR) { |
| 554 | param.remove(String8("test_cmd_policy_direct")); |
| 555 | if (value == "false") { |
| 556 | mDirectOutput = false; |
| 557 | } else if (value == "true") { |
| 558 | mDirectOutput = true; |
| 559 | } |
| 560 | } |
| 561 | if (param.getInt(String8("test_cmd_policy_input"), valueInt) == NO_ERROR) { |
| 562 | param.remove(String8("test_cmd_policy_input")); |
| 563 | mTestInput = valueInt; |
| 564 | } |
| 565 | |
| 566 | if (param.get(String8("test_cmd_policy_format"), value) == NO_ERROR) { |
| 567 | param.remove(String8("test_cmd_policy_format")); |
| 568 | if (value == "PCM 16 bits") { |
| 569 | mTestFormat = AudioSystem::PCM_16_BIT; |
| 570 | } else if (value == "PCM 8 bits") { |
| 571 | mTestFormat = AudioSystem::PCM_8_BIT; |
| 572 | } else if (value == "Compressed MP3") { |
| 573 | mTestFormat = AudioSystem::MP3; |
| 574 | } |
| 575 | } |
| 576 | if (param.get(String8("test_cmd_policy_channels"), value) == NO_ERROR) { |
| 577 | param.remove(String8("test_cmd_policy_channels")); |
| 578 | if (value == "Channels Stereo") { |
| 579 | mTestChannelcount = 2; |
| 580 | } else if (value == "Channels Mono") { |
| 581 | mTestChannelcount = 1; |
| 582 | } |
| 583 | } |
| 584 | if (param.getInt(String8("test_cmd_policy_sampleRate"), valueInt) == NO_ERROR) { |
| 585 | param.remove(String8("test_cmd_policy_sampleRate")); |
| 586 | if (valueInt >= 0 && valueInt <= 96000) { |
| 587 | mTestSamplingRate = valueInt; |
| 588 | } |
| 589 | } |
| 590 | mpClientInterface->setParameters(0, String8("test_cmd_policy=")); |
| 591 | } |
| 592 | } |
| 593 | return false; |
| 594 | } |
| 595 | |
| 596 | void AudioPolicyManagerGeneric::exit() |
| 597 | { |
| 598 | { |
| 599 | AutoMutex _l(mLock); |
| 600 | requestExit(); |
| 601 | mWaitWorkCV.signal(); |
| 602 | } |
| 603 | requestExitAndWait(); |
| 604 | } |
| 605 | |
| 606 | int AudioPolicyManagerGeneric::testOutputIndex(audio_io_handle_t output) |
| 607 | { |
| 608 | for (int i = 0; i < NUM_TEST_OUTPUTS; i++) { |
| 609 | if (output == mTestOutputs[i]) return i; |
| 610 | } |
| 611 | return 0; |
| 612 | } |
| 613 | #endif //AUDIO_POLICY_TEST |
| 614 | |
| 615 | // --- |
| 616 | |
| 617 | AudioPolicyManagerGeneric::routing_strategy AudioPolicyManagerGeneric::getStrategy(AudioSystem::stream_type stream) |
| 618 | { |
| 619 | // stream to strategy mapping |
| 620 | switch (stream) { |
| 621 | case AudioSystem::VOICE_CALL: |
| 622 | case AudioSystem::BLUETOOTH_SCO: |
| 623 | return STRATEGY_PHONE; |
| 624 | case AudioSystem::RING: |
| 625 | case AudioSystem::NOTIFICATION: |
| 626 | case AudioSystem::ALARM: |
| 627 | case AudioSystem::ENFORCED_AUDIBLE: |
| 628 | return STRATEGY_SONIFICATION; |
| 629 | case AudioSystem::DTMF: |
| 630 | return STRATEGY_DTMF; |
| 631 | default: |
| 632 | LOGE("unknown stream type"); |
| 633 | case AudioSystem::SYSTEM: |
| 634 | // NOTE: SYSTEM stream uses MEDIA strategy because muting music and switching outputs |
| 635 | // while key clicks are played produces a poor result |
| 636 | case AudioSystem::TTS: |
| 637 | case AudioSystem::MUSIC: |
| 638 | return STRATEGY_MEDIA; |
| 639 | } |
| 640 | } |
| 641 | |
| 642 | |
| 643 | float AudioPolicyManagerGeneric::computeVolume(int stream, int index, uint32_t device) |
| 644 | { |
| 645 | float volume = 1.0; |
| 646 | |
| 647 | StreamDescriptor &streamDesc = mStreams[stream]; |
| 648 | |
| 649 | // Force max volume if stream cannot be muted |
| 650 | if (!streamDesc.mCanBeMuted) index = streamDesc.mIndexMax; |
| 651 | |
| 652 | int volInt = (100 * (index - streamDesc.mIndexMin)) / (streamDesc.mIndexMax - streamDesc.mIndexMin); |
| 653 | volume = AudioSystem::linearToLog(volInt); |
| 654 | |
| 655 | return volume; |
| 656 | } |
| 657 | |
| 658 | void AudioPolicyManagerGeneric::setStreamMute(int stream, bool on, audio_io_handle_t output) |
| 659 | { |
Eric Laurent | e0e9ecc | 2009-07-28 08:44:33 -0700 | [diff] [blame^] | 660 | LOGV("setStreamMute() stream %d, mute %d, output %d", stream, on, output); |
Eric Laurent | 9d91ad5 | 2009-07-17 12:17:14 -0700 | [diff] [blame] | 661 | |
| 662 | StreamDescriptor &streamDesc = mStreams[stream]; |
| 663 | |
| 664 | if (on) { |
| 665 | if (streamDesc.mMuteCount++ == 0) { |
| 666 | if (streamDesc.mCanBeMuted) { |
| 667 | mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, 0, output); |
| 668 | } |
| 669 | } |
| 670 | } else { |
| 671 | if (streamDesc.mMuteCount == 0) { |
| 672 | LOGW("setStreamMute() unmuting non muted stream!"); |
| 673 | return; |
| 674 | } |
| 675 | if (--streamDesc.mMuteCount == 0) { |
| 676 | uint32_t device = mOutputs.valueFor(output)->mDevice; |
| 677 | float volume = computeVolume(stream, streamDesc.mIndexCur, device); |
| 678 | mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, volume, output); |
| 679 | } |
| 680 | } |
| 681 | } |
| 682 | |
| 683 | void AudioPolicyManagerGeneric::handleIncallSonification(int stream, bool starting) |
| 684 | { |
| 685 | // if the stream pertains to sonification strategy and we are in call we must |
| 686 | // mute the stream if it is low visibility. If it is high visibility, we must play a tone |
| 687 | // in the device used for phone strategy and play the tone if the selected device does not |
| 688 | // interfere with the device used for phone strategy |
| 689 | if (getStrategy((AudioSystem::stream_type)stream) == STRATEGY_SONIFICATION) { |
| 690 | AudioOutputDescriptor *outputDesc = mOutputs.valueFor(mHardwareOutput); |
| 691 | LOGV("handleIncallSonification() stream %d starting %d device %x", stream, starting, outputDesc->mDevice); |
| 692 | if (outputDesc->isUsedByStream((AudioSystem::stream_type)stream)) { |
| 693 | if (AudioSystem::isLowVisibility((AudioSystem::stream_type)stream)) { |
| 694 | LOGV("handleIncallSonification() low visibility"); |
| 695 | setStreamMute(stream, starting, mHardwareOutput); |
| 696 | } else { |
| 697 | if (starting) { |
| 698 | mpClientInterface->startTone(ToneGenerator::TONE_SUP_CALL_WAITING, AudioSystem::VOICE_CALL); |
| 699 | } else { |
| 700 | mpClientInterface->stopTone(); |
| 701 | } |
| 702 | } |
| 703 | } |
| 704 | } |
| 705 | } |
| 706 | |
| 707 | |
| 708 | // --- AudioOutputDescriptor class implementation |
| 709 | |
| 710 | AudioPolicyManagerGeneric::AudioOutputDescriptor::AudioOutputDescriptor() |
| 711 | : mSamplingRate(0), mFormat(0), mChannels(0), mLatency(0), |
| 712 | mFlags((AudioSystem::output_flags)0), mDevice(0) |
| 713 | { |
| 714 | // clear usage count for all stream types |
| 715 | for (int i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) { |
| 716 | mRefCount[i] = 0; |
| 717 | } |
| 718 | } |
| 719 | |
| 720 | uint32_t AudioPolicyManagerGeneric::AudioOutputDescriptor::device() |
| 721 | { |
| 722 | return mDevice; |
| 723 | } |
| 724 | |
| 725 | void AudioPolicyManagerGeneric::AudioOutputDescriptor::changeRefCount(AudioSystem::stream_type stream, int delta) |
| 726 | { |
| 727 | if ((delta + (int)mRefCount[stream]) < 0) { |
| 728 | LOGW("changeRefCount() invalid delta %d for stream %d, refCount %d", delta, stream, mRefCount[stream]); |
| 729 | mRefCount[stream] = 0; |
| 730 | return; |
| 731 | } |
| 732 | mRefCount[stream] += delta; |
| 733 | LOGV("changeRefCount() stream %d, count %d", stream, mRefCount[stream]); |
| 734 | } |
| 735 | |
| 736 | uint32_t AudioPolicyManagerGeneric::AudioOutputDescriptor::refCount() |
| 737 | { |
| 738 | uint32_t refcount = 0; |
| 739 | for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) { |
| 740 | refcount += mRefCount[i]; |
| 741 | } |
| 742 | return refcount; |
| 743 | } |
| 744 | |
| 745 | // --- AudioInputDescriptor class implementation |
| 746 | |
| 747 | AudioPolicyManagerGeneric::AudioInputDescriptor::AudioInputDescriptor() |
| 748 | : mSamplingRate(0), mFormat(0), mChannels(0), |
| 749 | mAcoustics((AudioSystem::audio_in_acoustics)0), mDevice(0), mRefCount(0) |
| 750 | { |
| 751 | } |
| 752 | |
| 753 | }; // namespace android |