diff options
Diffstat (limited to 'services/audiopolicy')
-rw-r--r-- | services/audiopolicy/AudioPolicyEffects.cpp | 90 | ||||
-rw-r--r-- | services/audiopolicy/AudioPolicyEffects.h | 2 | ||||
-rw-r--r-- | services/audiopolicy/AudioPolicyInterface.h | 36 | ||||
-rw-r--r-- | services/audiopolicy/AudioPolicyInterfaceImpl.cpp | 115 | ||||
-rw-r--r-- | services/audiopolicy/AudioPolicyInterfaceImplLegacy.cpp | 126 | ||||
-rw-r--r-- | services/audiopolicy/AudioPolicyManager.cpp | 549 | ||||
-rw-r--r-- | services/audiopolicy/AudioPolicyManager.h | 74 | ||||
-rw-r--r-- | services/audiopolicy/AudioPolicyService.cpp | 27 | ||||
-rw-r--r-- | services/audiopolicy/AudioPolicyService.h | 54 |
9 files changed, 791 insertions, 282 deletions
diff --git a/services/audiopolicy/AudioPolicyEffects.cpp b/services/audiopolicy/AudioPolicyEffects.cpp index 3c1c042..4fbe042 100644 --- a/services/audiopolicy/AudioPolicyEffects.cpp +++ b/services/audiopolicy/AudioPolicyEffects.cpp @@ -105,26 +105,28 @@ status_t AudioPolicyEffects::addInputEffects(audio_io_handle_t input, inputDesc->mRefCount++; ALOGV("addInputEffects(): input: %d, refCount: %d", input, inputDesc->mRefCount); - - Vector <EffectDesc *> effects = mInputSources.valueAt(index)->mEffects; - for (size_t i = 0; i < effects.size(); i++) { - EffectDesc *effect = effects[i]; - sp<AudioEffect> fx = new AudioEffect(NULL, &effect->mUuid, -1, 0, 0, audioSession, input); - status_t status = fx->initCheck(); - if (status != NO_ERROR && status != ALREADY_EXISTS) { - ALOGW("addInputEffects(): failed to create Fx %s on source %d", + if (inputDesc->mRefCount == 1) { + Vector <EffectDesc *> effects = mInputSources.valueAt(index)->mEffects; + for (size_t i = 0; i < effects.size(); i++) { + EffectDesc *effect = effects[i]; + sp<AudioEffect> fx = new AudioEffect(NULL, &effect->mUuid, -1, 0, 0, + audioSession, input); + status_t status = fx->initCheck(); + if (status != NO_ERROR && status != ALREADY_EXISTS) { + ALOGW("addInputEffects(): failed to create Fx %s on source %d", + effect->mName, (int32_t)aliasSource); + // fx goes out of scope and strong ref on AudioEffect is released + continue; + } + for (size_t j = 0; j < effect->mParams.size(); j++) { + fx->setParameter(effect->mParams[j]); + } + ALOGV("addInputEffects(): added Fx %s on source: %d", effect->mName, (int32_t)aliasSource); - // fx goes out of scope and strong ref on AudioEffect is released - continue; - } - for (size_t j = 0; j < effect->mParams.size(); j++) { - fx->setParameter(effect->mParams[j]); + inputDesc->mEffects.add(fx); } - ALOGV("addInputEffects(): added Fx %s on source: %d", effect->mName, (int32_t)aliasSource); - inputDesc->mEffects.add(fx); + inputDesc->setProcessorEnabled(true); } - inputDesc->setProcessorEnabled(true); - return status; } @@ -224,6 +226,11 @@ status_t AudioPolicyEffects::addOutputSessionEffects(audio_io_handle_t output, Mutex::Autolock _l(mLock); // create audio processors according to stream + // FIXME: should we have specific post processing settings for internal streams? + // default to media for now. + if (stream >= AUDIO_STREAM_PUBLIC_CNT) { + stream = AUDIO_STREAM_MUSIC; + } ssize_t index = mOutputStreams.indexOfKey(stream); if (index < 0) { ALOGV("addOutputSessionEffects(): no output processing needed for this stream"); @@ -241,26 +248,28 @@ status_t AudioPolicyEffects::addOutputSessionEffects(audio_io_handle_t output, } procDesc->mRefCount++; - ALOGV("addOutputSessionEffects(): session: %d, refCount: %d", audioSession, procDesc->mRefCount); - - Vector <EffectDesc *> effects = mOutputStreams.valueAt(index)->mEffects; - for (size_t i = 0; i < effects.size(); i++) { - EffectDesc *effect = effects[i]; - sp<AudioEffect> fx = new AudioEffect(NULL, &effect->mUuid, 0, 0, 0, audioSession, output); - status_t status = fx->initCheck(); - if (status != NO_ERROR && status != ALREADY_EXISTS) { - ALOGE("addOutputSessionEffects(): failed to create Fx %s on session %d", - effect->mName, audioSession); - // fx goes out of scope and strong ref on AudioEffect is released - continue; + ALOGV("addOutputSessionEffects(): session: %d, refCount: %d", + audioSession, procDesc->mRefCount); + if (procDesc->mRefCount == 1) { + Vector <EffectDesc *> effects = mOutputStreams.valueAt(index)->mEffects; + for (size_t i = 0; i < effects.size(); i++) { + EffectDesc *effect = effects[i]; + sp<AudioEffect> fx = new AudioEffect(NULL, &effect->mUuid, 0, 0, 0, + audioSession, output); + status_t status = fx->initCheck(); + if (status != NO_ERROR && status != ALREADY_EXISTS) { + ALOGE("addOutputSessionEffects(): failed to create Fx %s on session %d", + effect->mName, audioSession); + // fx goes out of scope and strong ref on AudioEffect is released + continue; + } + ALOGV("addOutputSessionEffects(): added Fx %s on session: %d for stream: %d", + effect->mName, audioSession, (int32_t)stream); + procDesc->mEffects.add(fx); } - ALOGV("addOutputSessionEffects(): added Fx %s on session: %d for stream: %d", - effect->mName, audioSession, (int32_t)stream); - procDesc->mEffects.add(fx); - } - - procDesc->setProcessorEnabled(true); + procDesc->setProcessorEnabled(true); + } return status; } @@ -281,7 +290,8 @@ status_t AudioPolicyEffects::releaseOutputSessionEffects(audio_io_handle_t outpu EffectVector *procDesc = mOutputSessions.valueAt(index); procDesc->mRefCount--; - ALOGV("releaseOutputSessionEffects(): session: %d, refCount: %d", audioSession, procDesc->mRefCount); + ALOGV("releaseOutputSessionEffects(): session: %d, refCount: %d", + audioSession, procDesc->mRefCount); if (procDesc->mRefCount == 0) { procDesc->setProcessorEnabled(false); procDesc->mEffects.clear(); @@ -330,7 +340,7 @@ void AudioPolicyEffects::EffectVector::setProcessorEnabled(bool enabled) return (audio_source_t)i; } -const char *AudioPolicyEffects::kStreamNames[AUDIO_STREAM_CNT+1] = { +const char *AudioPolicyEffects::kStreamNames[AUDIO_STREAM_PUBLIC_CNT+1] = { AUDIO_STREAM_DEFAULT_TAG, AUDIO_STREAM_VOICE_CALL_TAG, AUDIO_STREAM_SYSTEM_TAG, @@ -345,11 +355,11 @@ const char *AudioPolicyEffects::kStreamNames[AUDIO_STREAM_CNT+1] = { }; // returns the audio_stream_t enum corresponding to the output stream name or -// AUDIO_STREAM_CNT is no match found +// AUDIO_STREAM_PUBLIC_CNT is no match found audio_stream_type_t AudioPolicyEffects::streamNameToEnum(const char *name) { int i; - for (i = AUDIO_STREAM_DEFAULT; i < AUDIO_STREAM_CNT; i++) { + for (i = AUDIO_STREAM_DEFAULT; i < AUDIO_STREAM_PUBLIC_CNT; i++) { if (strcmp(name, kStreamNames[i - AUDIO_STREAM_DEFAULT]) == 0) { ALOGV("streamNameToEnum found stream %s %d", name, i); break; @@ -580,7 +590,7 @@ status_t AudioPolicyEffects::loadStreamEffectConfigurations(cnode *root, node = node->first_child; while (node) { audio_stream_type_t stream = streamNameToEnum(node->name); - if (stream == AUDIO_STREAM_CNT) { + if (stream == AUDIO_STREAM_PUBLIC_CNT) { ALOGW("loadStreamEffectConfigurations() invalid output stream %s", node->name); node = node->next; continue; diff --git a/services/audiopolicy/AudioPolicyEffects.h b/services/audiopolicy/AudioPolicyEffects.h index 6b0d538..3dec437 100644 --- a/services/audiopolicy/AudioPolicyEffects.h +++ b/services/audiopolicy/AudioPolicyEffects.h @@ -151,7 +151,7 @@ private: static const char * const kInputSourceNames[AUDIO_SOURCE_CNT -1]; static audio_source_t inputSourceNameToEnum(const char *name); - static const char *kStreamNames[AUDIO_STREAM_CNT+1]; //+1 required as streams start from -1 + static const char *kStreamNames[AUDIO_STREAM_PUBLIC_CNT+1]; //+1 required as streams start from -1 audio_stream_type_t streamNameToEnum(const char *name); // Parse audio_effects.conf diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h index 5524463..5bcbca8 100644 --- a/services/audiopolicy/AudioPolicyInterface.h +++ b/services/audiopolicy/AudioPolicyInterface.h @@ -90,30 +90,36 @@ public: audio_channel_mask_t channelMask, audio_output_flags_t flags, const audio_offload_info_t *offloadInfo) = 0; - virtual audio_io_handle_t getOutputForAttr(const audio_attributes_t *attr, - uint32_t samplingRate, - audio_format_t format, - audio_channel_mask_t channelMask, - audio_output_flags_t flags, - const audio_offload_info_t *offloadInfo) = 0; + virtual status_t getOutputForAttr(const audio_attributes_t *attr, + audio_io_handle_t *output, + audio_session_t session, + audio_stream_type_t *stream, + uint32_t samplingRate, + audio_format_t format, + audio_channel_mask_t channelMask, + audio_output_flags_t flags, + const audio_offload_info_t *offloadInfo) = 0; // indicates to the audio policy manager that the output starts being used by corresponding stream. virtual status_t startOutput(audio_io_handle_t output, audio_stream_type_t stream, - int session = 0) = 0; + audio_session_t session) = 0; // indicates to the audio policy manager that the output stops being used by corresponding stream. virtual status_t stopOutput(audio_io_handle_t output, audio_stream_type_t stream, - int session = 0) = 0; + audio_session_t session) = 0; // releases the output. - virtual void releaseOutput(audio_io_handle_t output) = 0; + virtual void releaseOutput(audio_io_handle_t output, + audio_stream_type_t stream, + audio_session_t session) = 0; // request an input appropriate for record from the supplied device with supplied parameters. - virtual audio_io_handle_t getInput(audio_source_t inputSource, - uint32_t samplingRate, - audio_format_t format, - audio_channel_mask_t channelMask, - audio_session_t session, - audio_input_flags_t flags) = 0; + virtual status_t getInputForAttr(const audio_attributes_t *attr, + audio_io_handle_t *input, + audio_session_t session, + uint32_t samplingRate, + audio_format_t format, + audio_channel_mask_t channelMask, + audio_input_flags_t flags) = 0; // indicates to the audio policy manager that the input starts being used. virtual status_t startInput(audio_io_handle_t input, audio_session_t session) = 0; diff --git a/services/audiopolicy/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/AudioPolicyInterfaceImpl.cpp index 6cd0ac8..abb1b21 100644 --- a/services/audiopolicy/AudioPolicyInterfaceImpl.cpp +++ b/services/audiopolicy/AudioPolicyInterfaceImpl.cpp @@ -129,8 +129,11 @@ audio_io_handle_t AudioPolicyService::getOutput(audio_stream_type_t stream, audio_output_flags_t flags, const audio_offload_info_t *offloadInfo) { + if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) { + return AUDIO_IO_HANDLE_NONE; + } if (mAudioPolicyManager == NULL) { - return 0; + return AUDIO_IO_HANDLE_NONE; } ALOGV("getOutput()"); Mutex::Autolock _l(mLock); @@ -138,26 +141,32 @@ audio_io_handle_t AudioPolicyService::getOutput(audio_stream_type_t stream, format, channelMask, flags, offloadInfo); } -audio_io_handle_t AudioPolicyService::getOutputForAttr(const audio_attributes_t *attr, - uint32_t samplingRate, - audio_format_t format, - audio_channel_mask_t channelMask, - audio_output_flags_t flags, - const audio_offload_info_t *offloadInfo) +status_t AudioPolicyService::getOutputForAttr(const audio_attributes_t *attr, + audio_io_handle_t *output, + audio_session_t session, + audio_stream_type_t *stream, + uint32_t samplingRate, + audio_format_t format, + audio_channel_mask_t channelMask, + audio_output_flags_t flags, + const audio_offload_info_t *offloadInfo) { if (mAudioPolicyManager == NULL) { - return 0; + return NO_INIT; } ALOGV("getOutput()"); Mutex::Autolock _l(mLock); - return mAudioPolicyManager->getOutputForAttr(attr, samplingRate, + return mAudioPolicyManager->getOutputForAttr(attr, output, session, stream, samplingRate, format, channelMask, flags, offloadInfo); } status_t AudioPolicyService::startOutput(audio_io_handle_t output, audio_stream_type_t stream, - int session) + audio_session_t session) { + if (uint32_t(stream) >= AUDIO_STREAM_CNT) { + return BAD_VALUE; + } if (mAudioPolicyManager == NULL) { return NO_INIT; } @@ -180,8 +189,11 @@ status_t AudioPolicyService::startOutput(audio_io_handle_t output, status_t AudioPolicyService::stopOutput(audio_io_handle_t output, audio_stream_type_t stream, - int session) + audio_session_t session) { + if (uint32_t(stream) >= AUDIO_STREAM_CNT) { + return BAD_VALUE; + } if (mAudioPolicyManager == NULL) { return NO_INIT; } @@ -192,7 +204,7 @@ status_t AudioPolicyService::stopOutput(audio_io_handle_t output, status_t AudioPolicyService::doStopOutput(audio_io_handle_t output, audio_stream_type_t stream, - int session) + audio_session_t session) { ALOGV("doStopOutput from tid %d", gettid()); sp<AudioPolicyEffects>audioPolicyEffects; @@ -211,61 +223,68 @@ status_t AudioPolicyService::doStopOutput(audio_io_handle_t output, return mAudioPolicyManager->stopOutput(output, stream, session); } -void AudioPolicyService::releaseOutput(audio_io_handle_t output) +void AudioPolicyService::releaseOutput(audio_io_handle_t output, + audio_stream_type_t stream, + audio_session_t session) { if (mAudioPolicyManager == NULL) { return; } ALOGV("releaseOutput()"); - mOutputCommandThread->releaseOutputCommand(output); + mOutputCommandThread->releaseOutputCommand(output, stream, session); } -void AudioPolicyService::doReleaseOutput(audio_io_handle_t output) +void AudioPolicyService::doReleaseOutput(audio_io_handle_t output, + audio_stream_type_t stream, + audio_session_t session) { ALOGV("doReleaseOutput from tid %d", gettid()); Mutex::Autolock _l(mLock); - mAudioPolicyManager->releaseOutput(output); + mAudioPolicyManager->releaseOutput(output, stream, session); } -audio_io_handle_t AudioPolicyService::getInput(audio_source_t inputSource, - uint32_t samplingRate, - audio_format_t format, - audio_channel_mask_t channelMask, - int audioSession, - audio_input_flags_t flags) +status_t AudioPolicyService::getInputForAttr(const audio_attributes_t *attr, + audio_io_handle_t *input, + audio_session_t session, + uint32_t samplingRate, + audio_format_t format, + audio_channel_mask_t channelMask, + audio_input_flags_t flags) { if (mAudioPolicyManager == NULL) { - return 0; + return NO_INIT; } // already checked by client, but double-check in case the client wrapper is bypassed - if (inputSource >= AUDIO_SOURCE_CNT && inputSource != AUDIO_SOURCE_HOTWORD) { - return 0; + if (attr->source >= AUDIO_SOURCE_CNT && attr->source != AUDIO_SOURCE_HOTWORD && + attr->source != AUDIO_SOURCE_FM_TUNER) { + return BAD_VALUE; } - if ((inputSource == AUDIO_SOURCE_HOTWORD) && !captureHotwordAllowed()) { - return 0; + if (((attr->source == AUDIO_SOURCE_HOTWORD) && !captureHotwordAllowed()) || + ((attr->source == AUDIO_SOURCE_FM_TUNER) && !captureFmTunerAllowed())) { + return BAD_VALUE; } - audio_io_handle_t input; sp<AudioPolicyEffects>audioPolicyEffects; + status_t status; { Mutex::Autolock _l(mLock); // the audio_in_acoustics_t parameter is ignored by get_input() - input = mAudioPolicyManager->getInput(inputSource, samplingRate, - format, channelMask, - (audio_session_t)audioSession, flags); + status = mAudioPolicyManager->getInputForAttr(attr, input, session, + samplingRate, format, channelMask, + flags); audioPolicyEffects = mAudioPolicyEffects; } - if (input == 0) { - return input; + if (status != NO_ERROR) { + return status; } if (audioPolicyEffects != 0) { // create audio pre processors according to input source - status_t status = audioPolicyEffects->addInputEffects(input, inputSource, audioSession); + status_t status = audioPolicyEffects->addInputEffects(*input, attr->source, session); if (status != NO_ERROR && status != ALREADY_EXISTS) { - ALOGW("Failed to add effects on input %d", input); + ALOGW("Failed to add effects on input %d", *input); } } - return input; + return NO_ERROR; } status_t AudioPolicyService::startInput(audio_io_handle_t input, @@ -321,7 +340,7 @@ status_t AudioPolicyService::initStreamVolume(audio_stream_type_t stream, if (!settingsAllowed()) { return PERMISSION_DENIED; } - if (uint32_t(stream) >= AUDIO_STREAM_CNT) { + if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) { return BAD_VALUE; } Mutex::Autolock _l(mLock); @@ -339,7 +358,7 @@ status_t AudioPolicyService::setStreamVolumeIndex(audio_stream_type_t stream, if (!settingsAllowed()) { return PERMISSION_DENIED; } - if (uint32_t(stream) >= AUDIO_STREAM_CNT) { + if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) { return BAD_VALUE; } Mutex::Autolock _l(mLock); @@ -355,7 +374,7 @@ status_t AudioPolicyService::getStreamVolumeIndex(audio_stream_type_t stream, if (mAudioPolicyManager == NULL) { return NO_INIT; } - if (uint32_t(stream) >= AUDIO_STREAM_CNT) { + if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) { return BAD_VALUE; } Mutex::Autolock _l(mLock); @@ -366,6 +385,9 @@ status_t AudioPolicyService::getStreamVolumeIndex(audio_stream_type_t stream, uint32_t AudioPolicyService::getStrategyForStream(audio_stream_type_t stream) { + if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) { + return 0; + } if (mAudioPolicyManager == NULL) { return 0; } @@ -376,8 +398,11 @@ uint32_t AudioPolicyService::getStrategyForStream(audio_stream_type_t stream) audio_devices_t AudioPolicyService::getDevicesForStream(audio_stream_type_t stream) { + if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) { + return AUDIO_DEVICE_NONE; + } if (mAudioPolicyManager == NULL) { - return (audio_devices_t)0; + return AUDIO_DEVICE_NONE; } return mAudioPolicyManager->getDevicesForStream(stream); } @@ -422,8 +447,11 @@ status_t AudioPolicyService::setEffectEnabled(int id, bool enabled) bool AudioPolicyService::isStreamActive(audio_stream_type_t stream, uint32_t inPastMs) const { + if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) { + return false; + } if (mAudioPolicyManager == NULL) { - return 0; + return false; } Mutex::Autolock _l(mLock); return mAudioPolicyManager->isStreamActive(stream, inPastMs); @@ -431,8 +459,11 @@ bool AudioPolicyService::isStreamActive(audio_stream_type_t stream, uint32_t inP bool AudioPolicyService::isStreamActiveRemotely(audio_stream_type_t stream, uint32_t inPastMs) const { + if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) { + return false; + } if (mAudioPolicyManager == NULL) { - return 0; + return false; } Mutex::Autolock _l(mLock); return mAudioPolicyManager->isStreamActiveRemotely(stream, inPastMs); diff --git a/services/audiopolicy/AudioPolicyInterfaceImplLegacy.cpp b/services/audiopolicy/AudioPolicyInterfaceImplLegacy.cpp index e1e81e1..4e42b25 100644 --- a/services/audiopolicy/AudioPolicyInterfaceImplLegacy.cpp +++ b/services/audiopolicy/AudioPolicyInterfaceImplLegacy.cpp @@ -134,8 +134,11 @@ audio_io_handle_t AudioPolicyService::getOutput(audio_stream_type_t stream, audio_output_flags_t flags, const audio_offload_info_t *offloadInfo) { + if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) { + return AUDIO_IO_HANDLE_NONE; + } if (mpAudioPolicy == NULL) { - return 0; + return AUDIO_IO_HANDLE_NONE; } ALOGV("getOutput()"); Mutex::Autolock _l(mLock); @@ -145,8 +148,11 @@ audio_io_handle_t AudioPolicyService::getOutput(audio_stream_type_t stream, status_t AudioPolicyService::startOutput(audio_io_handle_t output, audio_stream_type_t stream, - int session) + audio_session_t session) { + if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) { + return BAD_VALUE; + } if (mpAudioPolicy == NULL) { return NO_INIT; } @@ -170,8 +176,11 @@ status_t AudioPolicyService::startOutput(audio_io_handle_t output, status_t AudioPolicyService::stopOutput(audio_io_handle_t output, audio_stream_type_t stream, - int session) + audio_session_t session) { + if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) { + return BAD_VALUE; + } if (mpAudioPolicy == NULL) { return NO_INIT; } @@ -182,7 +191,7 @@ status_t AudioPolicyService::stopOutput(audio_io_handle_t output, status_t AudioPolicyService::doStopOutput(audio_io_handle_t output, audio_stream_type_t stream, - int session) + audio_session_t session) { ALOGV("doStopOutput from tid %d", gettid()); // release audio processors from the stream @@ -201,62 +210,68 @@ status_t AudioPolicyService::doStopOutput(audio_io_handle_t output, return mpAudioPolicy->stop_output(mpAudioPolicy, output, stream, session); } -void AudioPolicyService::releaseOutput(audio_io_handle_t output) +void AudioPolicyService::releaseOutput(audio_io_handle_t output, + audio_stream_type_t stream, + audio_session_t session) { if (mpAudioPolicy == NULL) { return; } ALOGV("releaseOutput()"); - mOutputCommandThread->releaseOutputCommand(output); + mOutputCommandThread->releaseOutputCommand(output, stream, session); } -void AudioPolicyService::doReleaseOutput(audio_io_handle_t output) +void AudioPolicyService::doReleaseOutput(audio_io_handle_t output, + audio_stream_type_t stream __unused, + audio_session_t session __unused) { ALOGV("doReleaseOutput from tid %d", gettid()); Mutex::Autolock _l(mLock); mpAudioPolicy->release_output(mpAudioPolicy, output); } -audio_io_handle_t AudioPolicyService::getInput(audio_source_t inputSource, - uint32_t samplingRate, - audio_format_t format, - audio_channel_mask_t channelMask, - int audioSession, - audio_input_flags_t flags __unused) +status_t AudioPolicyService::getInputForAttr(const audio_attributes_t *attr, + audio_io_handle_t *input, + audio_session_t session, + uint32_t samplingRate, + audio_format_t format, + audio_channel_mask_t channelMask, + audio_input_flags_t flags __unused) { if (mpAudioPolicy == NULL) { - return 0; + return NO_INIT; } // already checked by client, but double-check in case the client wrapper is bypassed - if (inputSource >= AUDIO_SOURCE_CNT && inputSource != AUDIO_SOURCE_HOTWORD) { - return 0; + if (attr->source >= AUDIO_SOURCE_CNT && attr->source != AUDIO_SOURCE_HOTWORD && + attr->source != AUDIO_SOURCE_FM_TUNER) { + return BAD_VALUE; } - if ((inputSource == AUDIO_SOURCE_HOTWORD) && !captureHotwordAllowed()) { - return 0; + if (((attr->source == AUDIO_SOURCE_HOTWORD) && !captureHotwordAllowed()) || + ((attr->source == AUDIO_SOURCE_FM_TUNER) && !captureFmTunerAllowed())) { + return BAD_VALUE; } - audio_io_handle_t input; sp<AudioPolicyEffects>audioPolicyEffects; { Mutex::Autolock _l(mLock); // the audio_in_acoustics_t parameter is ignored by get_input() - input = mpAudioPolicy->get_input(mpAudioPolicy, inputSource, samplingRate, + *input = mpAudioPolicy->get_input(mpAudioPolicy, attr->source, samplingRate, format, channelMask, (audio_in_acoustics_t) 0); audioPolicyEffects = mAudioPolicyEffects; } - if (input == 0) { - return input; + if (*input == AUDIO_IO_HANDLE_NONE) { + return INVALID_OPERATION; } if (audioPolicyEffects != 0) { // create audio pre processors according to input source - status_t status = audioPolicyEffects->addInputEffects(input, inputSource, audioSession); + status_t status = audioPolicyEffects->addInputEffects(*input, attr->source, session); if (status != NO_ERROR && status != ALREADY_EXISTS) { ALOGW("Failed to add effects on input %d", input); } } - return input; + return NO_ERROR; } status_t AudioPolicyService::startInput(audio_io_handle_t input, @@ -313,7 +328,7 @@ status_t AudioPolicyService::initStreamVolume(audio_stream_type_t stream, if (!settingsAllowed()) { return PERMISSION_DENIED; } - if (uint32_t(stream) >= AUDIO_STREAM_CNT) { + if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) { return BAD_VALUE; } Mutex::Autolock _l(mLock); @@ -331,7 +346,7 @@ status_t AudioPolicyService::setStreamVolumeIndex(audio_stream_type_t stream, if (!settingsAllowed()) { return PERMISSION_DENIED; } - if (uint32_t(stream) >= AUDIO_STREAM_CNT) { + if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) { return BAD_VALUE; } Mutex::Autolock _l(mLock); @@ -352,7 +367,7 @@ status_t AudioPolicyService::getStreamVolumeIndex(audio_stream_type_t stream, if (mpAudioPolicy == NULL) { return NO_INIT; } - if (uint32_t(stream) >= AUDIO_STREAM_CNT) { + if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) { return BAD_VALUE; } Mutex::Autolock _l(mLock); @@ -368,6 +383,9 @@ status_t AudioPolicyService::getStreamVolumeIndex(audio_stream_type_t stream, uint32_t AudioPolicyService::getStrategyForStream(audio_stream_type_t stream) { + if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) { + return 0; + } if (mpAudioPolicy == NULL) { return 0; } @@ -378,8 +396,11 @@ uint32_t AudioPolicyService::getStrategyForStream(audio_stream_type_t stream) audio_devices_t AudioPolicyService::getDevicesForStream(audio_stream_type_t stream) { + if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) { + return AUDIO_DEVICE_NONE; + } if (mpAudioPolicy == NULL) { - return (audio_devices_t)0; + return AUDIO_DEVICE_NONE; } return mpAudioPolicy->get_devices_for_stream(mpAudioPolicy, stream); } @@ -424,8 +445,11 @@ status_t AudioPolicyService::setEffectEnabled(int id, bool enabled) bool AudioPolicyService::isStreamActive(audio_stream_type_t stream, uint32_t inPastMs) const { + if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) { + return false; + } if (mpAudioPolicy == NULL) { - return 0; + return false; } Mutex::Autolock _l(mLock); return mpAudioPolicy->is_stream_active(mpAudioPolicy, stream, inPastMs); @@ -433,8 +457,11 @@ bool AudioPolicyService::isStreamActive(audio_stream_type_t stream, uint32_t inP bool AudioPolicyService::isStreamActiveRemotely(audio_stream_type_t stream, uint32_t inPastMs) const { + if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) { + return false; + } if (mpAudioPolicy == NULL) { - return 0; + return false; } Mutex::Autolock _l(mLock); return mpAudioPolicy->is_stream_active_remotely(mpAudioPolicy, stream, inPastMs); @@ -526,26 +553,39 @@ status_t AudioPolicyService::setAudioPortConfig(const struct audio_port_config * return INVALID_OPERATION; } -audio_io_handle_t AudioPolicyService::getOutputForAttr(const audio_attributes_t *attr, - uint32_t samplingRate, - audio_format_t format, - audio_channel_mask_t channelMask, - audio_output_flags_t flags, - const audio_offload_info_t *offloadInfo) +status_t AudioPolicyService::getOutputForAttr(const audio_attributes_t *attr, + audio_io_handle_t *output, + audio_session_t session, + audio_stream_type_t *stream, + uint32_t samplingRate, + audio_format_t format, + audio_channel_mask_t channelMask, + audio_output_flags_t flags, + const audio_offload_info_t *offloadInfo) { - audio_stream_type_t stream = audio_attributes_to_stream_type(attr); - - return getOutput(stream, samplingRate, format, channelMask, flags, offloadInfo); + if (attr != NULL) { + *stream = audio_attributes_to_stream_type(attr); + } else { + if (*stream == AUDIO_STREAM_DEFAULT) { + return BAD_VALUE; + } + } + *output = getOutput(*stream, samplingRate, format, channelMask, + flags, offloadInfo); + if (*output == AUDIO_IO_HANDLE_NONE) { + return INVALID_OPERATION; + } + return NO_ERROR; } -status_t AudioPolicyService::acquireSoundTriggerSession(audio_session_t *session, - audio_io_handle_t *ioHandle, - audio_devices_t *device) +status_t AudioPolicyService::acquireSoundTriggerSession(audio_session_t *session __unused, + audio_io_handle_t *ioHandle __unused, + audio_devices_t *device __unused) { return INVALID_OPERATION; } -status_t AudioPolicyService::releaseSoundTriggerSession(audio_session_t session) +status_t AudioPolicyService::releaseSoundTriggerSession(audio_session_t session __unused) { return INVALID_OPERATION; } diff --git a/services/audiopolicy/AudioPolicyManager.cpp b/services/audiopolicy/AudioPolicyManager.cpp index 536987a..8bb35f9 100644 --- a/services/audiopolicy/AudioPolicyManager.cpp +++ b/services/audiopolicy/AudioPolicyManager.cpp @@ -26,7 +26,7 @@ // A device mask for all audio input devices that are considered "virtual" when evaluating // active inputs in getActiveInput() -#define APM_AUDIO_IN_DEVICE_VIRTUAL_ALL AUDIO_DEVICE_IN_REMOTE_SUBMIX +#define APM_AUDIO_IN_DEVICE_VIRTUAL_ALL (AUDIO_DEVICE_IN_REMOTE_SUBMIX|AUDIO_DEVICE_IN_FM_TUNER) // A device mask for all audio output devices that are considered "remote" when evaluating // active output devices in isStreamActiveRemotely() #define APM_AUDIO_OUT_DEVICE_REMOTE_ALL AUDIO_DEVICE_OUT_REMOTE_SUBMIX @@ -43,6 +43,7 @@ #include <hardware/audio.h> #include <hardware/audio_effect.h> #include <media/AudioParameter.h> +#include <media/AudioPolicyHelper.h> #include <soundtrigger/SoundTrigger.h> #include "AudioPolicyManager.h" #include "audio_policy_conf.h" @@ -216,6 +217,10 @@ status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device, const char *device_address) { String8 address = (device_address == NULL) ? String8("") : String8(device_address); + // handle legacy remote submix case where the address was not always specified + if (deviceDistinguishesOnAddress(device) && (address.length() == 0)) { + address = String8("0"); + } ALOGV("setDeviceConnectionState() device: %x, state %d, address %s", device, state, address.string()); @@ -419,6 +424,10 @@ audio_policy_dev_state_t AudioPolicyManager::getDeviceConnectionState(audio_devi audio_policy_dev_state_t state = AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE; sp<DeviceDescriptor> devDesc = new DeviceDescriptor(String8(""), device); devDesc->mAddress = (device_address == NULL) ? String8("") : String8(device_address); + // handle legacy remote submix case where the address was not always specified + if (deviceDistinguishesOnAddress(device) && (devDesc->mAddress.length() == 0)) { + devDesc->mAddress = String8("0"); + } ssize_t index; DeviceVector *deviceVector; @@ -576,6 +585,9 @@ void AudioPolicyManager::setPhoneState(audio_mode_t state) if (isInCall()) { ALOGV("setPhoneState() in call state management: new state is %d", state); for (int stream = 0; stream < AUDIO_STREAM_CNT; stream++) { + if (stream == AUDIO_STREAM_PATCH) { + continue; + } handleIncallSonification((audio_stream_type_t)stream, false, true); } } @@ -673,6 +685,9 @@ void AudioPolicyManager::setPhoneState(audio_mode_t state) if (isStateInCall(state)) { ALOGV("setPhoneState() in call state management: new state is %d", state); for (int stream = 0; stream < AUDIO_STREAM_CNT; stream++) { + if (stream == AUDIO_STREAM_PATCH) { + continue; + } handleIncallSonification((audio_stream_type_t)stream, true, true); } } @@ -707,7 +722,7 @@ void AudioPolicyManager::setForceUse(audio_policy_force_use_t usage, config != AUDIO_POLICY_FORCE_WIRED_ACCESSORY && config != AUDIO_POLICY_FORCE_ANALOG_DOCK && config != AUDIO_POLICY_FORCE_DIGITAL_DOCK && config != AUDIO_POLICY_FORCE_NONE && - config != AUDIO_POLICY_FORCE_NO_BT_A2DP) { + config != AUDIO_POLICY_FORCE_NO_BT_A2DP && config != AUDIO_POLICY_FORCE_SPEAKER ) { ALOGW("setForceUse() invalid config %d for FOR_MEDIA", config); return; } @@ -822,48 +837,70 @@ audio_io_handle_t AudioPolicyManager::getOutput(audio_stream_type_t stream, audio_output_flags_t flags, const audio_offload_info_t *offloadInfo) { - routing_strategy strategy = getStrategy(stream); audio_devices_t device = getDeviceForStrategy(strategy, false /*fromCache*/); ALOGV("getOutput() device %d, stream %d, samplingRate %d, format %x, channelMask %x, flags %x", device, stream, samplingRate, format, channelMask, flags); - return getOutputForDevice(device, stream, samplingRate,format, channelMask, flags, - offloadInfo); -} - -audio_io_handle_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr, - uint32_t samplingRate, - audio_format_t format, - audio_channel_mask_t channelMask, - audio_output_flags_t flags, - const audio_offload_info_t *offloadInfo) -{ - if (attr == NULL) { - ALOGE("getOutputForAttr() called with NULL audio attributes"); - return 0; + return getOutputForDevice(device, AUDIO_SESSION_ALLOCATE, + stream, samplingRate,format, channelMask, + flags, offloadInfo); +} + +status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr, + audio_io_handle_t *output, + audio_session_t session, + audio_stream_type_t *stream, + uint32_t samplingRate, + audio_format_t format, + audio_channel_mask_t channelMask, + audio_output_flags_t flags, + const audio_offload_info_t *offloadInfo) +{ + audio_attributes_t attributes; + if (attr != NULL) { + if (!isValidAttributes(attr)) { + ALOGE("getOutputForAttr() invalid attributes: usage=%d content=%d flags=0x%x tags=[%s]", + attr->usage, attr->content_type, attr->flags, + attr->tags); + return BAD_VALUE; + } + attributes = *attr; + } else { + if (*stream < AUDIO_STREAM_MIN || *stream >= AUDIO_STREAM_PUBLIC_CNT) { + ALOGE("getOutputForAttr(): invalid stream type"); + return BAD_VALUE; + } + stream_type_to_audio_attributes(*stream, &attributes); } + ALOGV("getOutputForAttr() usage=%d, content=%d, tag=%s flags=%08x", - attr->usage, attr->content_type, attr->tags, attr->flags); + attributes.usage, attributes.content_type, attributes.tags, attributes.flags); // TODO this is where filtering for custom policies (rerouting, dynamic sources) will go - routing_strategy strategy = (routing_strategy) getStrategyForAttr(attr); + routing_strategy strategy = (routing_strategy) getStrategyForAttr(&attributes); audio_devices_t device = getDeviceForStrategy(strategy, false /*fromCache*/); - if ((attr->flags & AUDIO_FLAG_HW_AV_SYNC) != 0) { + if ((attributes.flags & AUDIO_FLAG_HW_AV_SYNC) != 0) { flags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_HW_AV_SYNC); } - ALOGV("getOutputForAttr() device %d, samplingRate %d, format %x, channelMask %x, flags %x", + ALOGV("getOutputForAttr() device 0x%x, samplingRate %d, format %x, channelMask %x, flags %x", device, samplingRate, format, channelMask, flags); - audio_stream_type_t stream = streamTypefromAttributesInt(attr); - return getOutputForDevice(device, stream, samplingRate, format, channelMask, flags, - offloadInfo); + *stream = streamTypefromAttributesInt(&attributes); + *output = getOutputForDevice(device, session, *stream, + samplingRate, format, channelMask, + flags, offloadInfo); + if (*output == AUDIO_IO_HANDLE_NONE) { + return INVALID_OPERATION; + } + return NO_ERROR; } audio_io_handle_t AudioPolicyManager::getOutputForDevice( audio_devices_t device, + audio_session_t session __unused, audio_stream_type_t stream, uint32_t samplingRate, audio_format_t format, @@ -926,6 +963,10 @@ audio_io_handle_t AudioPolicyManager::getOutputForDevice( if ((flags & AUDIO_OUTPUT_FLAG_HW_AV_SYNC) != 0) { flags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_DIRECT); } + // only allow deep buffering for music stream type + if (stream != AUDIO_STREAM_MUSIC) { + flags = (audio_output_flags_t)(flags &~AUDIO_OUTPUT_FLAG_DEEP_BUFFER); + } sp<IOProfile> profile; @@ -1110,7 +1151,7 @@ audio_io_handle_t AudioPolicyManager::selectOutput(const SortedVector<audio_io_h status_t AudioPolicyManager::startOutput(audio_io_handle_t output, audio_stream_type_t stream, - int session) + audio_session_t session) { ALOGV("startOutput() output %d, stream %d, session %d", output, stream, session); ssize_t index = mOutputs.indexOfKey(output); @@ -1119,6 +1160,20 @@ status_t AudioPolicyManager::startOutput(audio_io_handle_t output, return BAD_VALUE; } + // cannot start playback of STREAM_TTS if any other output is being used + uint32_t beaconMuteLatency = 0; + if (stream == AUDIO_STREAM_TTS) { + ALOGV("\t found BEACON stream"); + if (isAnyOutputActive(AUDIO_STREAM_TTS /*streamToIgnore*/)) { + return INVALID_OPERATION; + } else { + beaconMuteLatency = handleEventForBeacon(STARTING_BEACON); + } + } else { + // some playback other than beacon starts + beaconMuteLatency = handleEventForBeacon(STARTING_OUTPUT); + } + sp<AudioOutputDescriptor> outputDesc = mOutputs.valueAt(index); // increment usage count for this stream on the requested output: @@ -1130,8 +1185,9 @@ status_t AudioPolicyManager::startOutput(audio_io_handle_t output, audio_devices_t newDevice = getNewOutputDevice(output, false /*fromCache*/); routing_strategy strategy = getStrategy(stream); bool shouldWait = (strategy == STRATEGY_SONIFICATION) || - (strategy == STRATEGY_SONIFICATION_RESPECTFUL); - uint32_t waitMs = 0; + (strategy == STRATEGY_SONIFICATION_RESPECTFUL) || + (beaconMuteLatency > 0); + uint32_t waitMs = beaconMuteLatency; bool force = false; for (size_t i = 0; i < mOutputs.size(); i++) { sp<AudioOutputDescriptor> desc = mOutputs.valueAt(i); @@ -1145,7 +1201,8 @@ status_t AudioPolicyManager::startOutput(audio_io_handle_t output, force = true; } // wait for audio on other active outputs to be presented when starting - // a notification so that audio focus effect can propagate. + // a notification so that audio focus effect can propagate, or that a mute/unmute + // event occurred for beacon uint32_t latency = desc->latency(); if (shouldWait && desc->isActive(latency * 2) && (waitMs < latency)) { waitMs = latency; @@ -1178,7 +1235,7 @@ status_t AudioPolicyManager::startOutput(audio_io_handle_t output, status_t AudioPolicyManager::stopOutput(audio_io_handle_t output, audio_stream_type_t stream, - int session) + audio_session_t session) { ALOGV("stopOutput() output %d, stream %d, session %d", output, stream, session); ssize_t index = mOutputs.indexOfKey(output); @@ -1189,6 +1246,9 @@ status_t AudioPolicyManager::stopOutput(audio_io_handle_t output, sp<AudioOutputDescriptor> outputDesc = mOutputs.valueAt(index); + // always handle stream stop, check which stream type is stopping + handleEventForBeacon(stream == AUDIO_STREAM_TTS ? STOPPING_BEACON : STOPPING_OUTPUT); + // handle special case for sonification while in call if (isInCall()) { handleIncallSonification(stream, false, false); @@ -1233,7 +1293,9 @@ status_t AudioPolicyManager::stopOutput(audio_io_handle_t output, } } -void AudioPolicyManager::releaseOutput(audio_io_handle_t output) +void AudioPolicyManager::releaseOutput(audio_io_handle_t output, + audio_stream_type_t stream __unused, + audio_session_t session __unused) { ALOGV("releaseOutput() %d", output); ssize_t index = mOutputs.indexOfKey(output); @@ -1276,26 +1338,27 @@ void AudioPolicyManager::releaseOutput(audio_io_handle_t output) } -audio_io_handle_t AudioPolicyManager::getInput(audio_source_t inputSource, - uint32_t samplingRate, - audio_format_t format, - audio_channel_mask_t channelMask, - audio_session_t session, - audio_input_flags_t flags) +status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr, + audio_io_handle_t *input, + audio_session_t session, + uint32_t samplingRate, + audio_format_t format, + audio_channel_mask_t channelMask, + audio_input_flags_t flags) { - ALOGV("getInput() inputSource %d, samplingRate %d, format %d, channelMask %x, session %d, " - "flags %#x", - inputSource, samplingRate, format, channelMask, session, flags); + ALOGV("getInputForAttr() source %d, samplingRate %d, format %d, channelMask %x," + "session %d, flags %#x", + attr->source, samplingRate, format, channelMask, session, flags); - audio_devices_t device = getDeviceForInputSource(inputSource); + audio_devices_t device = getDeviceForInputSource(attr->source); if (device == AUDIO_DEVICE_NONE) { - ALOGW("getInput() could not find device for inputSource %d", inputSource); - return AUDIO_IO_HANDLE_NONE; + ALOGW("getInputForAttr() could not find device for source %d", attr->source); + return BAD_VALUE; } // adapt channel selection to input source - switch (inputSource) { + switch (attr->source) { case AUDIO_SOURCE_VOICE_UPLINK: channelMask = AUDIO_CHANNEL_IN_VOICE_UPLINK; break; @@ -1309,16 +1372,16 @@ audio_io_handle_t AudioPolicyManager::getInput(audio_source_t inputSource, break; } - audio_io_handle_t input = AUDIO_IO_HANDLE_NONE; + *input = AUDIO_IO_HANDLE_NONE; bool isSoundTrigger = false; - audio_source_t halInputSource = inputSource; - if (inputSource == AUDIO_SOURCE_HOTWORD) { + audio_source_t halInputSource = attr->source; + if (attr->source == AUDIO_SOURCE_HOTWORD) { ssize_t index = mSoundTriggerSessions.indexOfKey(session); if (index >= 0) { - input = mSoundTriggerSessions.valueFor(session); + *input = mSoundTriggerSessions.valueFor(session); isSoundTrigger = true; flags = (audio_input_flags_t)(flags | AUDIO_INPUT_FLAG_HW_HOTWORD); - ALOGV("SoundTrigger capture on session %d input %d", session, input); + ALOGV("SoundTrigger capture on session %d input %d", session, *input); } else { halInputSource = AUDIO_SOURCE_VOICE_RECOGNITION; } @@ -1339,16 +1402,16 @@ audio_io_handle_t AudioPolicyManager::getInput(audio_source_t inputSource, channelMask, flags); if (profile == 0) { - ALOGW("getInput() could not find profile for device 0x%X, samplingRate %u, format %#x, " - "channelMask 0x%X, flags %#x", + ALOGW("getInputForAttr() could not find profile for device 0x%X, samplingRate %u," + "format %#x, channelMask 0x%X, flags %#x", device, samplingRate, format, channelMask, log_flags); - return AUDIO_IO_HANDLE_NONE; + return BAD_VALUE; } } if (profile->mModule->mHandle == 0) { - ALOGE("getInput(): HW module %s not opened", profile->mModule->mName); - return AUDIO_IO_HANDLE_NONE; + ALOGE("getInputForAttr(): HW module %s not opened", profile->mModule->mName); + return NO_INIT; } audio_config_t config = AUDIO_CONFIG_INITIALIZER; @@ -1356,29 +1419,32 @@ audio_io_handle_t AudioPolicyManager::getInput(audio_source_t inputSource, config.channel_mask = channelMask; config.format = format; + // handle legacy remote submix case where the address was not always specified + String8 address = deviceDistinguishesOnAddress(device) ? String8("0") : String8(""); + status_t status = mpClientInterface->openInput(profile->mModule->mHandle, - &input, + input, &config, &device, - String8(""), + address, halInputSource, flags); // only accept input with the exact requested set of parameters - if (status != NO_ERROR || + if (status != NO_ERROR || *input == AUDIO_IO_HANDLE_NONE || (samplingRate != config.sample_rate) || (format != config.format) || (channelMask != config.channel_mask)) { - ALOGW("getInput() failed opening input: samplingRate %d, format %d, channelMask %x", + ALOGW("getInputForAttr() failed opening input: samplingRate %d, format %d, channelMask %x", samplingRate, format, channelMask); - if (input != AUDIO_IO_HANDLE_NONE) { - mpClientInterface->closeInput(input); + if (*input != AUDIO_IO_HANDLE_NONE) { + mpClientInterface->closeInput(*input); } - return AUDIO_IO_HANDLE_NONE; + return BAD_VALUE; } sp<AudioInputDescriptor> inputDesc = new AudioInputDescriptor(profile); - inputDesc->mInputSource = inputSource; + inputDesc->mInputSource = attr->source; inputDesc->mRefCount = 0; inputDesc->mOpenRefCount = 1; inputDesc->mSamplingRate = samplingRate; @@ -1388,9 +1454,9 @@ audio_io_handle_t AudioPolicyManager::getInput(audio_source_t inputSource, inputDesc->mSessions.add(session); inputDesc->mIsSoundTrigger = isSoundTrigger; - addInput(input, inputDesc); + addInput(*input, inputDesc); mpClientInterface->onAudioPortListUpdate(); - return input; + return NO_ERROR; } status_t AudioPolicyManager::startInput(audio_io_handle_t input, @@ -1557,6 +1623,11 @@ void AudioPolicyManager::initStreamVolume(audio_stream_type_t stream, } mStreams[stream].mIndexMin = indexMin; mStreams[stream].mIndexMax = indexMax; + //FIXME: AUDIO_STREAM_ACCESSIBILITY volume follows AUDIO_STREAM_MUSIC for now + if (stream == AUDIO_STREAM_MUSIC) { + mStreams[AUDIO_STREAM_ACCESSIBILITY].mIndexMin = indexMin; + mStreams[AUDIO_STREAM_ACCESSIBILITY].mIndexMax = indexMax; + } } status_t AudioPolicyManager::setStreamVolumeIndex(audio_stream_type_t stream, @@ -1584,17 +1655,35 @@ status_t AudioPolicyManager::setStreamVolumeIndex(audio_stream_type_t stream, } mStreams[stream].mIndexCur.add(device, index); - // compute and apply stream volume on all outputs according to connected device + // update volume on all outputs whose current device is also selected by the same + // strategy as the device specified by the caller + audio_devices_t strategyDevice = getDeviceForStrategy(getStrategy(stream), true /*fromCache*/); + + + //FIXME: AUDIO_STREAM_ACCESSIBILITY volume follows AUDIO_STREAM_MUSIC for now + audio_devices_t accessibilityDevice = AUDIO_DEVICE_NONE; + if (stream == AUDIO_STREAM_MUSIC) { + mStreams[AUDIO_STREAM_ACCESSIBILITY].mIndexCur.add(device, index); + accessibilityDevice = getDeviceForStrategy(STRATEGY_ACCESSIBILITY, true /*fromCache*/); + } + if ((device != AUDIO_DEVICE_OUT_DEFAULT) && + (device & (strategyDevice | accessibilityDevice)) == 0) { + return NO_ERROR; + } status_t status = NO_ERROR; for (size_t i = 0; i < mOutputs.size(); i++) { audio_devices_t curDevice = getDeviceForVolume(mOutputs.valueAt(i)->device()); - if ((device == AUDIO_DEVICE_OUT_DEFAULT) || (device == curDevice)) { + if ((device == AUDIO_DEVICE_OUT_DEFAULT) || ((curDevice & strategyDevice) != 0)) { status_t volStatus = checkAndSetVolume(stream, index, mOutputs.keyAt(i), curDevice); if (volStatus != NO_ERROR) { status = volStatus; } } + if ((device == AUDIO_DEVICE_OUT_DEFAULT) || ((curDevice & accessibilityDevice) != 0)) { + status_t volStatus = checkAndSetVolume(AUDIO_STREAM_ACCESSIBILITY, + index, mOutputs.keyAt(i), curDevice); + } } return status; } @@ -2561,13 +2650,10 @@ status_t AudioPolicyManager::setAudioPortConfig(const struct audio_port_config * void AudioPolicyManager::clearAudioPatches(uid_t uid) { - for (ssize_t i = 0; i < (ssize_t)mAudioPatches.size(); i++) { + for (ssize_t i = (ssize_t)mAudioPatches.size() - 1; i >= 0; i--) { sp<AudioPatch> patchDesc = mAudioPatches.valueAt(i); if (patchDesc->mUid == uid) { - // releaseAudioPatch() removes the patch from mAudioPatches - if (releaseAudioPatch(mAudioPatches.keyAt(i), uid) == NO_ERROR) { - i--; - } + releaseAudioPatch(mAudioPatches.keyAt(i), uid); } } } @@ -2653,7 +2739,10 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa mTotalEffectsCpuLoad(0), mTotalEffectsMemory(0), mA2dpSuspended(false), mSpeakerDrcEnabled(false), mNextUniqueId(1), - mAudioPortGeneration(1) + mAudioPortGeneration(1), + mBeaconMuteRefCount(0), + mBeaconPlayingRefCount(0), + mBeaconMuted(false) { mUidCached = getuid(); mpClientInterface = clientInterface; @@ -2787,6 +2876,14 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa inputDesc->mInputSource = AUDIO_SOURCE_MIC; inputDesc->mDevice = profileType; + // find the address + DeviceVector inputDevices = mAvailableInputDevices.getDevicesFromType(profileType); + // the inputs vector must be of size 1, but we don't want to crash here + String8 address = inputDevices.size() > 0 ? inputDevices.itemAt(0)->mAddress + : String8(""); + ALOGV(" for input device 0x%x using address %s", profileType, address.string()); + ALOGE_IF(inputDevices.size() == 0, "Input device list is empty!"); + audio_config_t config = AUDIO_CONFIG_INITIALIZER; config.sample_rate = inputDesc->mSamplingRate; config.channel_mask = inputDesc->mChannelMask; @@ -2796,7 +2893,7 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa &input, &config, &inputDesc->mDevice, - String8(""), + address, AUDIO_SOURCE_MIC, AUDIO_INPUT_FLAG_NONE); @@ -3517,7 +3614,8 @@ status_t AudioPolicyManager::checkInputsForDevice(audio_devices_t device, // check if one opened input is not needed any more after disconnecting one device for (size_t input_index = 0; input_index < mInputs.size(); input_index++) { desc = mInputs.valueAt(input_index); - if (!(desc->mProfile->mSupportedDevices.types() & mAvailableInputDevices.types())) { + if (!(desc->mProfile->mSupportedDevices.types() & mAvailableInputDevices.types() & + ~AUDIO_DEVICE_BIT_IN)) { ALOGV("checkInputsForDevice(): disconnecting adding input %d", mInputs.keyAt(input_index)); inputs.add(mInputs.keyAt(input_index)); @@ -3532,7 +3630,7 @@ status_t AudioPolicyManager::checkInputsForDevice(audio_devices_t device, profile_index < mHwModules[module_index]->mInputProfiles.size(); profile_index++) { sp<IOProfile> profile = mHwModules[module_index]->mInputProfiles[profile_index]; - if (profile->mSupportedDevices.types() & device) { + if (profile->mSupportedDevices.types() & device & ~AUDIO_DEVICE_BIT_IN) { ALOGV("checkInputsForDevice(): clearing direct input profile %zu on module %zu", profile_index, module_index); if (profile->mSamplingRates[0] == 0) { @@ -3708,6 +3806,9 @@ void AudioPolicyManager::checkOutputForStrategy(routing_strategy strategy) } // Move tracks associated to this strategy from previous output to new output for (int i = 0; i < AUDIO_STREAM_CNT; i++) { + if (i == AUDIO_STREAM_PATCH) { + continue; + } if (getStrategy((audio_stream_type_t)i) == strategy) { mpClientInterface->invalidateStream((audio_stream_type_t)i); } @@ -3724,8 +3825,10 @@ void AudioPolicyManager::checkOutputForAllStrategies() checkOutputForStrategy(STRATEGY_ENFORCED_AUDIBLE); checkOutputForStrategy(STRATEGY_SONIFICATION); checkOutputForStrategy(STRATEGY_SONIFICATION_RESPECTFUL); + checkOutputForStrategy(STRATEGY_ACCESSIBILITY); checkOutputForStrategy(STRATEGY_MEDIA); checkOutputForStrategy(STRATEGY_DTMF); + checkOutputForStrategy(STRATEGY_REROUTING); } audio_io_handle_t AudioPolicyManager::getA2dpOutput() @@ -3749,7 +3852,9 @@ void AudioPolicyManager::checkA2dpSuspend() } bool isScoConnected = - (mAvailableInputDevices.types() & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) != 0; + ((mAvailableInputDevices.types() & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET & + ~AUDIO_DEVICE_BIT_IN) != 0) || + ((mAvailableOutputDevices.types() & AUDIO_DEVICE_OUT_ALL_SCO) != 0); // suspend A2DP output if: // (NOT already suspended) && // ((SCO device is connected && @@ -3812,10 +3917,14 @@ audio_devices_t AudioPolicyManager::getNewOutputDevice(audio_io_handle_t output, // use device for strategy sonification // 5: the strategy "respectful" sonification is active on the output: // use device for strategy "respectful" sonification - // 6: the strategy media is active on the output: + // 6: the strategy accessibility is active on the output: + // use device for strategy accessibility + // 7: the strategy media is active on the output: // use device for strategy media - // 7: the strategy DTMF is active on the output: + // 8: the strategy DTMF is active on the output: // use device for strategy DTMF + // 9: the strategy for beacon, a.k.a. "transmitted through speaker" is active on the output: + // use device for strategy t-t-s if (outputDesc->isStrategyActive(STRATEGY_ENFORCED_AUDIBLE) && mForceUse[AUDIO_POLICY_FORCE_FOR_SYSTEM] == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED) { device = getDeviceForStrategy(STRATEGY_ENFORCED_AUDIBLE, fromCache); @@ -3828,10 +3937,16 @@ audio_devices_t AudioPolicyManager::getNewOutputDevice(audio_io_handle_t output, device = getDeviceForStrategy(STRATEGY_SONIFICATION, fromCache); } else if (outputDesc->isStrategyActive(STRATEGY_SONIFICATION_RESPECTFUL)) { device = getDeviceForStrategy(STRATEGY_SONIFICATION_RESPECTFUL, fromCache); + } else if (outputDesc->isStrategyActive(STRATEGY_ACCESSIBILITY)) { + device = getDeviceForStrategy(STRATEGY_ACCESSIBILITY, fromCache); } else if (outputDesc->isStrategyActive(STRATEGY_MEDIA)) { device = getDeviceForStrategy(STRATEGY_MEDIA, fromCache); } else if (outputDesc->isStrategyActive(STRATEGY_DTMF)) { device = getDeviceForStrategy(STRATEGY_DTMF, fromCache); + } else if (outputDesc->isStrategyActive(STRATEGY_TRANSMITTED_THROUGH_SPEAKER)) { + device = getDeviceForStrategy(STRATEGY_TRANSMITTED_THROUGH_SPEAKER, fromCache); + } else if (outputDesc->isStrategyActive(STRATEGY_REROUTING)) { + device = getDeviceForStrategy(STRATEGY_REROUTING, fromCache); } ALOGV("getNewOutputDevice() selected device %x", device); @@ -3866,7 +3981,7 @@ audio_devices_t AudioPolicyManager::getDevicesForStream(audio_stream_type_t stre // By checking the range of stream before calling getStrategy, we avoid // getStrategy's behavior for invalid streams. getStrategy would do a ALOGE // and then return STRATEGY_MEDIA, but we want to return the empty set. - if (stream < (audio_stream_type_t) 0 || stream >= AUDIO_STREAM_CNT) { + if (stream < (audio_stream_type_t) 0 || stream >= AUDIO_STREAM_PUBLIC_CNT) { return AUDIO_DEVICE_NONE; } audio_devices_t devices; @@ -3893,6 +4008,9 @@ audio_devices_t AudioPolicyManager::getDevicesForStream(audio_stream_type_t stre AudioPolicyManager::routing_strategy AudioPolicyManager::getStrategy( audio_stream_type_t stream) { + + ALOG_ASSERT(stream != AUDIO_STREAM_PATCH,"getStrategy() called for AUDIO_STREAM_PATCH"); + // stream to strategy mapping switch (stream) { case AUDIO_STREAM_VOICE_CALL: @@ -3906,29 +4024,45 @@ AudioPolicyManager::routing_strategy AudioPolicyManager::getStrategy( case AUDIO_STREAM_DTMF: return STRATEGY_DTMF; default: - ALOGE("unknown stream type"); + ALOGE("unknown stream type %d", stream); case AUDIO_STREAM_SYSTEM: // NOTE: SYSTEM stream uses MEDIA strategy because muting music and switching outputs // while key clicks are played produces a poor result - case AUDIO_STREAM_TTS: case AUDIO_STREAM_MUSIC: return STRATEGY_MEDIA; case AUDIO_STREAM_ENFORCED_AUDIBLE: return STRATEGY_ENFORCED_AUDIBLE; + case AUDIO_STREAM_TTS: + return STRATEGY_TRANSMITTED_THROUGH_SPEAKER; + case AUDIO_STREAM_ACCESSIBILITY: + return STRATEGY_ACCESSIBILITY; + case AUDIO_STREAM_REROUTING: + return STRATEGY_REROUTING; } } uint32_t AudioPolicyManager::getStrategyForAttr(const audio_attributes_t *attr) { // flags to strategy mapping + if ((attr->flags & AUDIO_FLAG_BEACON) == AUDIO_FLAG_BEACON) { + return (uint32_t) STRATEGY_TRANSMITTED_THROUGH_SPEAKER; + } if ((attr->flags & AUDIO_FLAG_AUDIBILITY_ENFORCED) == AUDIO_FLAG_AUDIBILITY_ENFORCED) { return (uint32_t) STRATEGY_ENFORCED_AUDIBLE; } // usage to strategy mapping switch (attr->usage) { + case AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY: + if (isStreamActive(AUDIO_STREAM_RING) || isStreamActive(AUDIO_STREAM_ALARM)) { + return (uint32_t) STRATEGY_SONIFICATION; + } + if (isInCall()) { + return (uint32_t) STRATEGY_PHONE; + } + return (uint32_t) STRATEGY_ACCESSIBILITY; + case AUDIO_USAGE_MEDIA: case AUDIO_USAGE_GAME: - case AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY: case AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE: case AUDIO_USAGE_ASSISTANCE_SONIFICATION: return (uint32_t) STRATEGY_MEDIA; @@ -3967,6 +4101,74 @@ void AudioPolicyManager::handleNotificationRoutingForStream(audio_stream_type_t } } +bool AudioPolicyManager::isAnyOutputActive(audio_stream_type_t streamToIgnore) { + for (size_t s = 0 ; s < AUDIO_STREAM_CNT ; s++) { + if (s == (size_t) streamToIgnore) { + continue; + } + for (size_t i = 0; i < mOutputs.size(); i++) { + const sp<AudioOutputDescriptor> outputDesc = mOutputs.valueAt(i); + if (outputDesc->mRefCount[s] != 0) { + return true; + } + } + } + return false; +} + +uint32_t AudioPolicyManager::handleEventForBeacon(int event) { + switch(event) { + case STARTING_OUTPUT: + mBeaconMuteRefCount++; + break; + case STOPPING_OUTPUT: + if (mBeaconMuteRefCount > 0) { + mBeaconMuteRefCount--; + } + break; + case STARTING_BEACON: + mBeaconPlayingRefCount++; + break; + case STOPPING_BEACON: + if (mBeaconPlayingRefCount > 0) { + mBeaconPlayingRefCount--; + } + break; + } + + if (mBeaconMuteRefCount > 0) { + // any playback causes beacon to be muted + return setBeaconMute(true); + } else { + // no other playback: unmute when beacon starts playing, mute when it stops + return setBeaconMute(mBeaconPlayingRefCount == 0); + } +} + +uint32_t AudioPolicyManager::setBeaconMute(bool mute) { + ALOGV("setBeaconMute(%d) mBeaconMuteRefCount=%d mBeaconPlayingRefCount=%d", + mute, mBeaconMuteRefCount, mBeaconPlayingRefCount); + // keep track of muted state to avoid repeating mute/unmute operations + if (mBeaconMuted != mute) { + // mute/unmute AUDIO_STREAM_TTS on all outputs + ALOGV("\t muting %d", mute); + uint32_t maxLatency = 0; + for (size_t i = 0; i < mOutputs.size(); i++) { + sp<AudioOutputDescriptor> desc = mOutputs.valueAt(i); + setStreamMute(AUDIO_STREAM_TTS, mute/*on*/, + desc->mIoHandle, + 0 /*delay*/, AUDIO_DEVICE_NONE); + const uint32_t latency = desc->latency() * 2; + if (latency > maxLatency) { + maxLatency = latency; + } + } + mBeaconMuted = mute; + return maxLatency; + } + return 0; +} + audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strategy, bool fromCache) { @@ -3980,6 +4182,14 @@ audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strate audio_devices_t availableOutputDeviceTypes = mAvailableOutputDevices.types(); switch (strategy) { + case STRATEGY_TRANSMITTED_THROUGH_SPEAKER: + device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_SPEAKER; + if (!device) { + ALOGE("getDeviceForStrategy() no device found for "\ + "STRATEGY_TRANSMITTED_THROUGH_SPEAKER"); + } + break; + case STRATEGY_SONIFICATION_RESPECTFUL: if (isInCall()) { device = getDeviceForStrategy(STRATEGY_SONIFICATION, false /*fromCache*/); @@ -4052,7 +4262,7 @@ audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strate // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to A2DP if (!isInCall() && (mForceUse[AUDIO_POLICY_FORCE_FOR_MEDIA] != AUDIO_POLICY_FORCE_NO_BT_A2DP) && - (getA2dpOutput() != 0) && !mA2dpSuspended) { + (getA2dpOutput() != 0)) { device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP; if (device) break; device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES; @@ -4087,7 +4297,7 @@ audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strate // A2DP speaker when forcing to speaker output if (!isInCall() && (mForceUse[AUDIO_POLICY_FORCE_FOR_MEDIA] != AUDIO_POLICY_FORCE_NO_BT_A2DP) && - (getA2dpOutput() != 0) && !mA2dpSuspended) { + (getA2dpOutput() != 0)) { device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER; if (device) break; } @@ -4141,6 +4351,24 @@ audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strate // The second device used for sonification is the same as the device used by media strategy // FALL THROUGH + // FIXME: STRATEGY_ACCESSIBILITY and STRATEGY_REROUTING follow STRATEGY_MEDIA for now + case STRATEGY_ACCESSIBILITY: + if (strategy == STRATEGY_ACCESSIBILITY) { + // do not route accessibility prompts to a digital output currently configured with a + // compressed format as they would likely not be mixed and dropped. + for (size_t i = 0; i < mOutputs.size(); i++) { + sp<AudioOutputDescriptor> desc = mOutputs.valueAt(i); + audio_devices_t devices = desc->device() & + (AUDIO_DEVICE_OUT_HDMI | AUDIO_DEVICE_OUT_SPDIF | AUDIO_DEVICE_OUT_HDMI_ARC); + if (desc->isActive() && !audio_is_linear_pcm(desc->mFormat) && + devices != AUDIO_DEVICE_NONE) { + availableOutputDeviceTypes = availableOutputDeviceTypes & ~devices; + } + } + } + // FALL THROUGH + + case STRATEGY_REROUTING: case STRATEGY_MEDIA: { uint32_t device2 = AUDIO_DEVICE_NONE; if (strategy != STRATEGY_SONIFICATION) { @@ -4149,7 +4377,7 @@ audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strate } if ((device2 == AUDIO_DEVICE_NONE) && (mForceUse[AUDIO_POLICY_FORCE_FOR_MEDIA] != AUDIO_POLICY_FORCE_NO_BT_A2DP) && - (getA2dpOutput() != 0) && !mA2dpSuspended) { + (getA2dpOutput() != 0)) { device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP; if (device2 == AUDIO_DEVICE_NONE) { device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES; @@ -4158,6 +4386,10 @@ audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strate device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER; } } + if ((device2 == AUDIO_DEVICE_NONE) && + (mForceUse[AUDIO_POLICY_FORCE_FOR_MEDIA] == AUDIO_POLICY_FORCE_SPEAKER)) { + device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_SPEAKER; + } if (device2 == AUDIO_DEVICE_NONE) { device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_WIRED_HEADPHONE; } @@ -4248,6 +4480,7 @@ uint32_t AudioPolicyManager::checkDeviceMuteStrategies(sp<AudioOutputDescriptor> for (size_t i = 0; i < NUM_STRATEGIES; i++) { audio_devices_t curDevice = getDeviceForStrategy((routing_strategy)i, false /*fromCache*/); + curDevice = curDevice & outputDesc->mProfile->mSupportedDevices.types(); bool mute = shouldMute && (curDevice & device) && (curDevice != device); bool doMute = false; @@ -4348,11 +4581,15 @@ uint32_t AudioPolicyManager::setOutputDevice(audio_io_handle_t output, muteWaitMs = checkDeviceMuteStrategies(outputDesc, prevDevice, delayMs); // Do not change the routing if: - // - the requested device is AUDIO_DEVICE_NONE - // - the requested device is the same as current device and force is not specified. + // the requested device is AUDIO_DEVICE_NONE + // OR the requested device is the same as current device + // AND force is not specified + // AND the output is connected by a valid audio patch. // Doing this check here allows the caller to call setOutputDevice() without conditions - if ((device == AUDIO_DEVICE_NONE || device == prevDevice) && !force) { - ALOGV("setOutputDevice() setting same device %04x or null device for output %d", device, output); + if ((device == AUDIO_DEVICE_NONE || device == prevDevice) && !force && + outputDesc->mPatchHandle != 0) { + ALOGV("setOutputDevice() setting same device %04x or null device for output %d", + device, output); return muteWaitMs; } @@ -4667,6 +4904,11 @@ audio_devices_t AudioPolicyManager::getDeviceForInputSource(audio_source_t input device = AUDIO_DEVICE_IN_REMOTE_SUBMIX; } break; + case AUDIO_SOURCE_FM_TUNER: + if (availableDeviceTypes & AUDIO_DEVICE_IN_FM_TUNER) { + device = AUDIO_DEVICE_IN_FM_TUNER; + } + break; default: ALOGW("getDeviceForInputSource() invalid input source %d", inputSource); break; @@ -4778,6 +5020,7 @@ AudioPolicyManager::device_category AudioPolicyManager::getDeviceCategory(audio_ } } +/* static */ float AudioPolicyManager::volIndexToAmpl(audio_devices_t device, const StreamDescriptor& streamDesc, int indexInUi) { @@ -4891,6 +5134,21 @@ const AudioPolicyManager::VolumeCurvePoint }; const AudioPolicyManager::VolumeCurvePoint + AudioPolicyManager::sLinearVolumeCurve[AudioPolicyManager::VOLCNT] = { + {0, -96.0f}, {33, -68.0f}, {66, -34.0f}, {100, 0.0f} +}; + +const AudioPolicyManager::VolumeCurvePoint + AudioPolicyManager::sSilentVolumeCurve[AudioPolicyManager::VOLCNT] = { + {0, -96.0f}, {1, -96.0f}, {2, -96.0f}, {100, -96.0f} +}; + +const AudioPolicyManager::VolumeCurvePoint + AudioPolicyManager::sFullScaleVolumeCurve[AudioPolicyManager::VOLCNT] = { + {0, 0.0f}, {1, 0.0f}, {2, 0.0f}, {100, 0.0f} +}; + +const AudioPolicyManager::VolumeCurvePoint *AudioPolicyManager::sVolumeProfiles[AUDIO_STREAM_CNT] [AudioPolicyManager::DEVICE_CATEGORY_CNT] = { { // AUDIO_STREAM_VOICE_CALL @@ -4948,11 +5206,30 @@ const AudioPolicyManager::VolumeCurvePoint sExtMediaSystemVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA }, { // AUDIO_STREAM_TTS + // "Transmitted Through Speaker": always silent except on DEVICE_CATEGORY_SPEAKER + sSilentVolumeCurve, // DEVICE_CATEGORY_HEADSET + sLinearVolumeCurve, // DEVICE_CATEGORY_SPEAKER + sSilentVolumeCurve, // DEVICE_CATEGORY_EARPIECE + sSilentVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA + }, + { // AUDIO_STREAM_ACCESSIBILITY sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_HEADSET sSpeakerMediaVolumeCurve, // DEVICE_CATEGORY_SPEAKER sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_EARPIECE sDefaultMediaVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA }, + { // AUDIO_STREAM_REROUTING + sFullScaleVolumeCurve, // DEVICE_CATEGORY_HEADSET + sFullScaleVolumeCurve, // DEVICE_CATEGORY_SPEAKER + sFullScaleVolumeCurve, // DEVICE_CATEGORY_EARPIECE + sFullScaleVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA + }, + { // AUDIO_STREAM_PATCH + sFullScaleVolumeCurve, // DEVICE_CATEGORY_HEADSET + sFullScaleVolumeCurve, // DEVICE_CATEGORY_SPEAKER + sFullScaleVolumeCurve, // DEVICE_CATEGORY_EARPIECE + sFullScaleVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA + }, }; void AudioPolicyManager::initializeVolumeCurves() @@ -4976,6 +5253,8 @@ void AudioPolicyManager::initializeVolumeCurves() sSpeakerSonificationVolumeCurveDrc; mStreams[AUDIO_STREAM_MUSIC].mVolumeCurve[DEVICE_CATEGORY_SPEAKER] = sSpeakerMediaVolumeCurveDrc; + mStreams[AUDIO_STREAM_ACCESSIBILITY].mVolumeCurve[DEVICE_CATEGORY_SPEAKER] = + sSpeakerMediaVolumeCurveDrc; } } @@ -5101,6 +5380,9 @@ void AudioPolicyManager::applyStreamVolumes(audio_io_handle_t output, ALOGVV("applyStreamVolumes() for output %d and device %x", output, device); for (int stream = 0; stream < AUDIO_STREAM_CNT; stream++) { + if (stream == AUDIO_STREAM_PATCH) { + continue; + } checkAndSetVolume((audio_stream_type_t)stream, mStreams[stream].getVolumeIndex(device), output, @@ -5118,6 +5400,9 @@ void AudioPolicyManager::setStrategyMute(routing_strategy strategy, { ALOGVV("setStrategyMute() strategy %d, mute %d, output %d", strategy, on, output); for (int stream = 0; stream < AUDIO_STREAM_CNT; stream++) { + if (stream == AUDIO_STREAM_PATCH) { + continue; + } if (getStrategy((audio_stream_type_t)stream) == strategy) { setStreamMute((audio_stream_type_t)stream, on, output, delayMs, device); } @@ -5329,6 +5614,9 @@ bool AudioPolicyManager::AudioOutputDescriptor::isStrategyActive(routing_strateg sysTime = systemTime(); } for (int i = 0; i < (int)AUDIO_STREAM_CNT; i++) { + if (i == AUDIO_STREAM_PATCH) { + continue; + } if (((getStrategy((audio_stream_type_t)i) == strategy) || (NUM_STRATEGIES == strategy)) && isStreamActive((audio_stream_type_t)i, inPastMs, sysTime)) { @@ -5843,12 +6131,28 @@ void AudioPolicyManager::AudioPort::importAudioPort(const sp<AudioPort> port) { } } } + for (size_t k = 0 ; k < port->mGains.size() ; k++) { + sp<AudioGain> gain = port->mGains.itemAt(k); + if (gain != 0) { + bool hasGain = false; + for (size_t l = 0 ; l < mGains.size() ; l++) { + if (gain == mGains.itemAt(l)) { + hasGain = true; + break; + } + } + if (!hasGain) { // never import a gain twice + mGains.add(gain); + } + } + } } void AudioPolicyManager::AudioPort::clearCapabilities() { mChannelMasks.clear(); mFormats.clear(); mSamplingRates.clear(); + mGains.clear(); } void AudioPolicyManager::AudioPort::loadSamplingRates(char *name) @@ -6018,6 +6322,10 @@ void AudioPolicyManager::AudioPort::loadGains(cnode *root) status_t AudioPolicyManager::AudioPort::checkExactSamplingRate(uint32_t samplingRate) const { + if (mSamplingRates.isEmpty()) { + return NO_ERROR; + } + for (size_t i = 0; i < mSamplingRates.size(); i ++) { if (mSamplingRates[i] == samplingRate) { return NO_ERROR; @@ -6029,6 +6337,10 @@ status_t AudioPolicyManager::AudioPort::checkExactSamplingRate(uint32_t sampling status_t AudioPolicyManager::AudioPort::checkCompatibleSamplingRate(uint32_t samplingRate, uint32_t *updatedSamplingRate) const { + if (mSamplingRates.isEmpty()) { + return NO_ERROR; + } + // Search for the closest supported sampling rate that is above (preferred) // or below (acceptable) the desired sampling rate, within a permitted ratio. // The sampling rates do not need to be sorted in ascending order. @@ -6087,6 +6399,10 @@ status_t AudioPolicyManager::AudioPort::checkCompatibleSamplingRate(uint32_t sam status_t AudioPolicyManager::AudioPort::checkExactChannelMask(audio_channel_mask_t channelMask) const { + if (mChannelMasks.isEmpty()) { + return NO_ERROR; + } + for (size_t i = 0; i < mChannelMasks.size(); i++) { if (mChannelMasks[i] == channelMask) { return NO_ERROR; @@ -6098,6 +6414,10 @@ status_t AudioPolicyManager::AudioPort::checkExactChannelMask(audio_channel_mask status_t AudioPolicyManager::AudioPort::checkCompatibleChannelMask(audio_channel_mask_t channelMask) const { + if (mChannelMasks.isEmpty()) { + return NO_ERROR; + } + const bool isRecordThread = mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SINK; for (size_t i = 0; i < mChannelMasks.size(); i ++) { // FIXME Does not handle multi-channel automatic conversions yet @@ -6121,6 +6441,10 @@ status_t AudioPolicyManager::AudioPort::checkCompatibleChannelMask(audio_channel status_t AudioPolicyManager::AudioPort::checkFormat(audio_format_t format) const { + if (mFormats.isEmpty()) { + return NO_ERROR; + } + for (size_t i = 0; i < mFormats.size(); i ++) { if (mFormats[i] == format) { return NO_ERROR; @@ -6791,7 +7115,11 @@ void AudioPolicyManager::DeviceVector::loadDevicesFromName(char *name, ARRAY_SIZE(sDeviceNameToEnumTable), devName); if (type != AUDIO_DEVICE_NONE) { - add(new DeviceDescriptor(String8(""), type)); + sp<DeviceDescriptor> dev = new DeviceDescriptor(String8(""), type); + if (type == AUDIO_DEVICE_IN_REMOTE_SUBMIX) { + dev->mAddress = String8("0"); + } + add(dev); } else { sp<DeviceDescriptor> deviceDesc = declaredDevices.getDeviceFromName(String8(devName)); @@ -7226,9 +7554,19 @@ audio_stream_type_t AudioPolicyManager::streamTypefromAttributesInt(const audio_ switch (attr->usage) { case AUDIO_USAGE_MEDIA: case AUDIO_USAGE_GAME: - case AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY: case AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE: return AUDIO_STREAM_MUSIC; + case AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY: + if (isStreamActive(AUDIO_STREAM_ALARM)) { + return AUDIO_STREAM_ALARM; + } + if (isStreamActive(AUDIO_STREAM_RING)) { + return AUDIO_STREAM_RING; + } + if (isInCall()) { + return AUDIO_STREAM_VOICE_CALL; + } + return AUDIO_STREAM_ACCESSIBILITY; case AUDIO_USAGE_ASSISTANCE_SONIFICATION: return AUDIO_STREAM_SYSTEM; case AUDIO_USAGE_VOICE_COMMUNICATION: @@ -7254,4 +7592,35 @@ audio_stream_type_t AudioPolicyManager::streamTypefromAttributesInt(const audio_ return AUDIO_STREAM_MUSIC; } } + +bool AudioPolicyManager::isValidAttributes(const audio_attributes_t *paa) { + // has flags that map to a strategy? + if ((paa->flags & (AUDIO_FLAG_AUDIBILITY_ENFORCED | AUDIO_FLAG_SCO | AUDIO_FLAG_BEACON)) != 0) { + return true; + } + + // has known usage? + switch (paa->usage) { + case AUDIO_USAGE_UNKNOWN: + case AUDIO_USAGE_MEDIA: + case AUDIO_USAGE_VOICE_COMMUNICATION: + case AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING: + case AUDIO_USAGE_ALARM: + case AUDIO_USAGE_NOTIFICATION: + case AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE: + case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST: + case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT: + case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED: + case AUDIO_USAGE_NOTIFICATION_EVENT: + case AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY: + case AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE: + case AUDIO_USAGE_ASSISTANCE_SONIFICATION: + case AUDIO_USAGE_GAME: + break; + default: + return false; + } + return true; +} + }; // namespace android diff --git a/services/audiopolicy/AudioPolicyManager.h b/services/audiopolicy/AudioPolicyManager.h index 0ea7b97..17348e9 100644 --- a/services/audiopolicy/AudioPolicyManager.h +++ b/services/audiopolicy/AudioPolicyManager.h @@ -87,25 +87,31 @@ public: audio_channel_mask_t channelMask, audio_output_flags_t flags, const audio_offload_info_t *offloadInfo); - virtual audio_io_handle_t getOutputForAttr(const audio_attributes_t *attr, - uint32_t samplingRate, - audio_format_t format, - audio_channel_mask_t channelMask, - audio_output_flags_t flags, - const audio_offload_info_t *offloadInfo); + virtual status_t getOutputForAttr(const audio_attributes_t *attr, + audio_io_handle_t *output, + audio_session_t session, + audio_stream_type_t *stream, + uint32_t samplingRate, + audio_format_t format, + audio_channel_mask_t channelMask, + audio_output_flags_t flags, + const audio_offload_info_t *offloadInfo); virtual status_t startOutput(audio_io_handle_t output, audio_stream_type_t stream, - int session = 0); + audio_session_t session); virtual status_t stopOutput(audio_io_handle_t output, audio_stream_type_t stream, - int session = 0); - virtual void releaseOutput(audio_io_handle_t output); - virtual audio_io_handle_t getInput(audio_source_t inputSource, - uint32_t samplingRate, - audio_format_t format, - audio_channel_mask_t channelMask, - audio_session_t session, - audio_input_flags_t flags); + audio_session_t session); + virtual void releaseOutput(audio_io_handle_t output, + audio_stream_type_t stream, + audio_session_t session); + virtual status_t getInputForAttr(const audio_attributes_t *attr, + audio_io_handle_t *input, + audio_session_t session, + uint32_t samplingRate, + audio_format_t format, + audio_channel_mask_t channelMask, + audio_input_flags_t flags); // indicates to the audio policy manager that the input starts being used. virtual status_t startInput(audio_io_handle_t input, @@ -187,6 +193,9 @@ protected: STRATEGY_SONIFICATION_RESPECTFUL, STRATEGY_DTMF, STRATEGY_ENFORCED_AUDIBLE, + STRATEGY_TRANSMITTED_THROUGH_SPEAKER, + STRATEGY_ACCESSIBILITY, + STRATEGY_REROUTING, NUM_STRATEGIES }; @@ -434,6 +443,9 @@ protected: static const VolumeCurvePoint sHeadsetSystemVolumeCurve[AudioPolicyManager::VOLCNT]; static const VolumeCurvePoint sDefaultVoiceVolumeCurve[AudioPolicyManager::VOLCNT]; static const VolumeCurvePoint sSpeakerVoiceVolumeCurve[AudioPolicyManager::VOLCNT]; + static const VolumeCurvePoint sLinearVolumeCurve[AudioPolicyManager::VOLCNT]; + static const VolumeCurvePoint sSilentVolumeCurve[AudioPolicyManager::VOLCNT]; + static const VolumeCurvePoint sFullScaleVolumeCurve[AudioPolicyManager::VOLCNT]; // default volume curves per stream and device category. See initializeVolumeCurves() static const VolumeCurvePoint *sVolumeProfiles[AUDIO_STREAM_CNT][DEVICE_CATEGORY_CNT]; @@ -600,8 +612,10 @@ protected: audio_io_handle_t output, audio_devices_t device); // check that volume change is permitted, compute and send new volume to audio hardware - status_t checkAndSetVolume(audio_stream_type_t stream, int index, audio_io_handle_t output, - audio_devices_t device, int delayMs = 0, bool force = false); + virtual status_t checkAndSetVolume(audio_stream_type_t stream, int index, + audio_io_handle_t output, + audio_devices_t device, + int delayMs = 0, bool force = false); // apply all stream volumes to the specified output and device void applyStreamVolumes(audio_io_handle_t output, audio_devices_t device, int delayMs = 0, bool force = false); @@ -708,7 +722,7 @@ protected: // if muting, wait for the audio in pcm buffer to be drained before proceeding // if unmuting, unmute only after the specified delay // Returns the number of ms waited - uint32_t checkDeviceMuteStrategies(sp<AudioOutputDescriptor> outputDesc, + virtual uint32_t checkDeviceMuteStrategies(sp<AudioOutputDescriptor> outputDesc, audio_devices_t prevDevice, uint32_t delayMs); @@ -806,6 +820,18 @@ protected: sp<AudioPatch> mCallTxPatch; sp<AudioPatch> mCallRxPatch; + // for supporting "beacon" streams, i.e. streams that only play on speaker, and never + // when something other than STREAM_TTS (a.k.a. "Transmitted Through Speaker") is playing + enum { + STARTING_OUTPUT, + STARTING_BEACON, + STOPPING_OUTPUT, + STOPPING_BEACON + }; + uint32_t mBeaconMuteRefCount; // ref count for stream that would mute beacon + uint32_t mBeaconPlayingRefCount;// ref count for the playing beacon streams + bool mBeaconMuted; // has STREAM_TTS been muted + #ifdef AUDIO_POLICY_TEST Mutex mLock; Condition mWaitWorkCV; @@ -820,10 +846,9 @@ protected: uint32_t mTestChannels; uint32_t mTestLatencyMs; #endif //AUDIO_POLICY_TEST - -private: static float volIndexToAmpl(audio_devices_t device, const StreamDescriptor& streamDesc, int indexInUi); +private: // updates device caching and output for streams that can influence the // routing of notifications void handleNotificationRoutingForStream(audio_stream_type_t stream); @@ -843,6 +868,7 @@ private: // internal method to return the output handle for the given device and format audio_io_handle_t getOutputForDevice( audio_devices_t device, + audio_session_t session, audio_stream_type_t stream, uint32_t samplingRate, audio_format_t format, @@ -851,6 +877,14 @@ private: const audio_offload_info_t *offloadInfo); // internal function to derive a stream type value from audio attributes audio_stream_type_t streamTypefromAttributesInt(const audio_attributes_t *attr); + // return true if any output is playing anything besides the stream to ignore + bool isAnyOutputActive(audio_stream_type_t streamToIgnore); + // event is one of STARTING_OUTPUT, STARTING_BEACON, STOPPING_OUTPUT, STOPPING_BEACON + // returns 0 if no mute/unmute event happened, the largest latency of the device where + // the mute/unmute happened + uint32_t handleEventForBeacon(int event); + uint32_t setBeaconMute(bool mute); + bool isValidAttributes(const audio_attributes_t *paa); }; }; diff --git a/services/audiopolicy/AudioPolicyService.cpp b/services/audiopolicy/AudioPolicyService.cpp index da2defe..b80380e 100644 --- a/services/audiopolicy/AudioPolicyService.cpp +++ b/services/audiopolicy/AudioPolicyService.cpp @@ -150,7 +150,7 @@ AudioPolicyService::~AudioPolicyService() void AudioPolicyService::registerClient(const sp<IAudioPolicyServiceClient>& client) { - Mutex::Autolock _l(mLock); + Mutex::Autolock _l(mNotificationClientsLock); uid_t uid = IPCThreadState::self()->getCallingUid(); if (mNotificationClients.indexOfKey(uid) < 0) { @@ -169,14 +169,17 @@ void AudioPolicyService::registerClient(const sp<IAudioPolicyServiceClient>& cli // removeNotificationClient() is called when the client process dies. void AudioPolicyService::removeNotificationClient(uid_t uid) { - Mutex::Autolock _l(mLock); - - mNotificationClients.removeItem(uid); - + { + Mutex::Autolock _l(mNotificationClientsLock); + mNotificationClients.removeItem(uid); + } #ifndef USE_LEGACY_AUDIO_POLICY + { + Mutex::Autolock _l(mLock); if (mAudioPolicyManager) { mAudioPolicyManager->clearAudioPatches(uid); } + } #endif } @@ -187,7 +190,7 @@ void AudioPolicyService::onAudioPortListUpdate() void AudioPolicyService::doOnAudioPortListUpdate() { - Mutex::Autolock _l(mLock); + Mutex::Autolock _l(mNotificationClientsLock); for (size_t i = 0; i < mNotificationClients.size(); i++) { mNotificationClients.valueAt(i)->onAudioPortListUpdate(); } @@ -213,7 +216,7 @@ status_t AudioPolicyService::clientReleaseAudioPatch(audio_patch_handle_t handle void AudioPolicyService::doOnAudioPatchListUpdate() { - Mutex::Autolock _l(mLock); + Mutex::Autolock _l(mNotificationClientsLock); for (size_t i = 0; i < mNotificationClients.size(); i++) { mNotificationClients.valueAt(i)->onAudioPatchListUpdate(); } @@ -455,7 +458,7 @@ bool AudioPolicyService::AudioCommandThread::threadLoop() break; } mLock.unlock(); - svc->doReleaseOutput(data->mIO); + svc->doReleaseOutput(data->mIO, data->mStream, data->mSession); mLock.lock(); }break; case CREATE_AUDIO_PATCH: { @@ -652,7 +655,7 @@ status_t AudioPolicyService::AudioCommandThread::voiceVolumeCommand(float volume void AudioPolicyService::AudioCommandThread::stopOutputCommand(audio_io_handle_t output, audio_stream_type_t stream, - int session) + audio_session_t session) { sp<AudioCommand> command = new AudioCommand(); command->mCommand = STOP_OUTPUT; @@ -665,12 +668,16 @@ void AudioPolicyService::AudioCommandThread::stopOutputCommand(audio_io_handle_t sendCommand(command); } -void AudioPolicyService::AudioCommandThread::releaseOutputCommand(audio_io_handle_t output) +void AudioPolicyService::AudioCommandThread::releaseOutputCommand(audio_io_handle_t output, + audio_stream_type_t stream, + audio_session_t session) { sp<AudioCommand> command = new AudioCommand(); command->mCommand = RELEASE_OUTPUT; sp<ReleaseOutputData> data = new ReleaseOutputData(); data->mIO = output; + data->mStream = stream; + data->mSession = session; command->mParam = data; ALOGV("AudioCommandThread() adding release output %d", output); sendCommand(command); diff --git a/services/audiopolicy/AudioPolicyService.h b/services/audiopolicy/AudioPolicyService.h index a09c084..74a59a8 100644 --- a/services/audiopolicy/AudioPolicyService.h +++ b/services/audiopolicy/AudioPolicyService.h @@ -74,25 +74,31 @@ public: audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE, const audio_offload_info_t *offloadInfo = NULL); - virtual audio_io_handle_t getOutputForAttr(const audio_attributes_t *attr, - uint32_t samplingRate = 0, - audio_format_t format = AUDIO_FORMAT_DEFAULT, - audio_channel_mask_t channelMask = 0, - audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE, - const audio_offload_info_t *offloadInfo = NULL); + virtual status_t getOutputForAttr(const audio_attributes_t *attr, + audio_io_handle_t *output, + audio_session_t session, + audio_stream_type_t *stream, + uint32_t samplingRate = 0, + audio_format_t format = AUDIO_FORMAT_DEFAULT, + audio_channel_mask_t channelMask = 0, + audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE, + const audio_offload_info_t *offloadInfo = NULL); virtual status_t startOutput(audio_io_handle_t output, audio_stream_type_t stream, - int session = 0); + audio_session_t session); virtual status_t stopOutput(audio_io_handle_t output, audio_stream_type_t stream, - int session = 0); - virtual void releaseOutput(audio_io_handle_t output); - virtual audio_io_handle_t getInput(audio_source_t inputSource, - uint32_t samplingRate, - audio_format_t format, - audio_channel_mask_t channelMask, - int audioSession, - audio_input_flags_t flags); + audio_session_t session); + virtual void releaseOutput(audio_io_handle_t output, + audio_stream_type_t stream, + audio_session_t session); + virtual status_t getInputForAttr(const audio_attributes_t *attr, + audio_io_handle_t *input, + audio_session_t session, + uint32_t samplingRate, + audio_format_t format, + audio_channel_mask_t channelMask, + audio_input_flags_t flags); virtual status_t startInput(audio_io_handle_t input, audio_session_t session); virtual status_t stopInput(audio_io_handle_t input, @@ -183,8 +189,10 @@ public: status_t doStopOutput(audio_io_handle_t output, audio_stream_type_t stream, - int session = 0); - void doReleaseOutput(audio_io_handle_t output); + audio_session_t session); + void doReleaseOutput(audio_io_handle_t output, + audio_stream_type_t stream, + audio_session_t session); status_t clientCreateAudioPatch(const struct audio_patch *patch, audio_patch_handle_t *handle, @@ -252,8 +260,10 @@ private: status_t voiceVolumeCommand(float volume, int delayMs = 0); void stopOutputCommand(audio_io_handle_t output, audio_stream_type_t stream, - int session); - void releaseOutputCommand(audio_io_handle_t output); + audio_session_t session); + void releaseOutputCommand(audio_io_handle_t output, + audio_stream_type_t stream, + audio_session_t session); status_t sendCommand(sp<AudioCommand>& command, int delayMs = 0); void insertCommand_l(sp<AudioCommand>& command, int delayMs = 0); status_t createAudioPatchCommand(const struct audio_patch *patch, @@ -323,12 +333,14 @@ private: public: audio_io_handle_t mIO; audio_stream_type_t mStream; - int mSession; + audio_session_t mSession; }; class ReleaseOutputData : public AudioCommandData { public: audio_io_handle_t mIO; + audio_stream_type_t mStream; + audio_session_t mSession; }; class CreateAudioPatchData : public AudioCommandData { @@ -497,7 +509,7 @@ private: AudioPolicyClient *mAudioPolicyClient; DefaultKeyedVector< uid_t, sp<NotificationClient> > mNotificationClients; - + Mutex mNotificationClientsLock; // protects mNotificationClients // Manage all effects configured in audio_effects.conf sp<AudioPolicyEffects> mAudioPolicyEffects; audio_mode_t mPhoneState; |