diff options
Diffstat (limited to 'services/audiopolicy')
-rw-r--r-- | services/audiopolicy/Android.mk | 6 | ||||
-rw-r--r-- | services/audiopolicy/AudioPolicyClientImplLegacy.cpp | 7 | ||||
-rw-r--r-- | services/audiopolicy/AudioPolicyEffects.cpp | 94 | ||||
-rw-r--r-- | services/audiopolicy/AudioPolicyEffects.h | 2 | ||||
-rw-r--r-- | services/audiopolicy/AudioPolicyInterface.h | 51 | ||||
-rw-r--r-- | services/audiopolicy/AudioPolicyInterfaceImpl.cpp | 163 | ||||
-rw-r--r-- | services/audiopolicy/AudioPolicyInterfaceImplLegacy.cpp | 137 | ||||
-rw-r--r-- | services/audiopolicy/AudioPolicyManager.cpp | 1270 | ||||
-rw-r--r-- | services/audiopolicy/AudioPolicyManager.h | 145 | ||||
-rw-r--r-- | services/audiopolicy/AudioPolicyService.cpp | 33 | ||||
-rw-r--r-- | services/audiopolicy/AudioPolicyService.h | 57 |
11 files changed, 1533 insertions, 432 deletions
diff --git a/services/audiopolicy/Android.mk b/services/audiopolicy/Android.mk index 6512c38..188fc89 100644 --- a/services/audiopolicy/Android.mk +++ b/services/audiopolicy/Android.mk @@ -30,7 +30,8 @@ LOCAL_SHARED_LIBRARIES := \ libbinder \ libmedia \ libhardware \ - libhardware_legacy + libhardware_legacy \ + libserviceutility ifneq ($(USE_LEGACY_AUDIO_POLICY), 1) LOCAL_SHARED_LIBRARIES += \ @@ -38,8 +39,7 @@ LOCAL_SHARED_LIBRARIES += \ endif LOCAL_STATIC_LIBRARIES := \ - libmedia_helper \ - libserviceutility + libmedia_helper LOCAL_MODULE:= libaudiopolicyservice diff --git a/services/audiopolicy/AudioPolicyClientImplLegacy.cpp b/services/audiopolicy/AudioPolicyClientImplLegacy.cpp index 97719da..a79f8ae 100644 --- a/services/audiopolicy/AudioPolicyClientImplLegacy.cpp +++ b/services/audiopolicy/AudioPolicyClientImplLegacy.cpp @@ -188,6 +188,13 @@ static audio_io_handle_t open_input(audio_module_handle_t module, if (pSamplingRate == NULL || pFormat == NULL || pChannelMask == NULL || pDevices == NULL) { return AUDIO_IO_HANDLE_NONE; } + + if (((*pDevices & AUDIO_DEVICE_IN_REMOTE_SUBMIX) == AUDIO_DEVICE_IN_REMOTE_SUBMIX) + && !captureAudioOutputAllowed()) { + ALOGE("open_input() permission denied: capture not allowed"); + return AUDIO_IO_HANDLE_NONE; + } + audio_config_t config = AUDIO_CONFIG_INITIALIZER;; config.sample_rate = *pSamplingRate; config.format = *pFormat; diff --git a/services/audiopolicy/AudioPolicyEffects.cpp b/services/audiopolicy/AudioPolicyEffects.cpp index 3c1c042..e6ace20 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; + inputDesc->mEffects.add(fx); } - 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); - 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; @@ -648,6 +658,10 @@ status_t AudioPolicyEffects::loadAudioEffectConfig(const char *path) loadInputEffectConfigurations(root, effects); loadStreamEffectConfigurations(root, effects); + for (size_t i = 0; i < effects.size(); i++) { + delete effects[i]; + } + config_free(root); free(root); free(data); 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..4508fa7 100644 --- a/services/audiopolicy/AudioPolicyInterface.h +++ b/services/audiopolicy/AudioPolicyInterface.h @@ -18,6 +18,7 @@ #define ANDROID_AUDIOPOLICY_INTERFACE_H #include <media/AudioSystem.h> +#include <media/AudioPolicy.h> #include <utils/String8.h> #include <hardware/audio_policy.h> @@ -56,6 +57,16 @@ class AudioPolicyInterface { public: + typedef enum { + API_INPUT_INVALID = -1, + API_INPUT_LEGACY = 0,// e.g. audio recording from a microphone + API_INPUT_MIX_CAPTURE,// used for "remote submix", capture of the media to play it remotely + API_INPUT_MIX_EXT_POLICY_REROUTE,// used for platform audio rerouting, where mixes are + // handled by external and dynamically installed + // policies which reroute audio mixes + } input_type_t; + +public: virtual ~AudioPolicyInterface() {} // // configuration functions @@ -90,30 +101,37 @@ 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, + input_type_t *inputType) = 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; @@ -195,6 +213,9 @@ public: audio_devices_t *device) = 0; virtual status_t releaseSoundTriggerSession(audio_session_t session) = 0; + + virtual status_t registerPolicyMixes(Vector<AudioMix> mixes) = 0; + virtual status_t unregisterPolicyMixes(Vector<AudioMix> mixes) = 0; }; diff --git a/services/audiopolicy/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/AudioPolicyInterfaceImpl.cpp index 6cd0ac8..a45dbb3 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,98 @@ 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; + AudioPolicyInterface::input_type_t inputType; { 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, &inputType); audioPolicyEffects = mAudioPolicyEffects; + + if (status == NO_ERROR) { + // enforce permission (if any) required for each type of input + switch (inputType) { + case AudioPolicyInterface::API_INPUT_LEGACY: + break; + case AudioPolicyInterface::API_INPUT_MIX_CAPTURE: + if (!captureAudioOutputAllowed()) { + ALOGE("getInputForAttr() permission denied: capture not allowed"); + status = PERMISSION_DENIED; + } + break; + case AudioPolicyInterface::API_INPUT_MIX_EXT_POLICY_REROUTE: + if (!modifyAudioRoutingAllowed()) { + ALOGE("getInputForAttr() permission denied: modify audio routing not allowed"); + status = PERMISSION_DENIED; + } + break; + case AudioPolicyInterface::API_INPUT_INVALID: + default: + LOG_ALWAYS_FATAL("getInputForAttr() encountered an invalid input type %d", + (int)inputType); + } + } + + if (status != NO_ERROR) { + if (status == PERMISSION_DENIED) { + mAudioPolicyManager->releaseInput(*input, session); + } + return status; + } } - if (input == 0) { - return input; - } + 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 +370,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 +388,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 +404,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 +415,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 +428,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 +477,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 +489,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); @@ -583,4 +644,20 @@ status_t AudioPolicyService::releaseSoundTriggerSession(audio_session_t session) return mAudioPolicyManager->releaseSoundTriggerSession(session); } +status_t AudioPolicyService::registerPolicyMixes(Vector<AudioMix> mixes, bool registration) +{ + Mutex::Autolock _l(mLock); + if(!modifyAudioRoutingAllowed()) { + return PERMISSION_DENIED; + } + if (mAudioPolicyManager == NULL) { + return NO_INIT; + } + if (registration) { + return mAudioPolicyManager->registerPolicyMixes(mixes); + } else { + return mAudioPolicyManager->unregisterPolicyMixes(mixes); + } +} + }; // namespace android diff --git a/services/audiopolicy/AudioPolicyInterfaceImplLegacy.cpp b/services/audiopolicy/AudioPolicyInterfaceImplLegacy.cpp index e1e81e1..b8846c6 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,75 @@ 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; } + + audio_source_t inputSource = attr->source; + // 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 (inputSource >= AUDIO_SOURCE_CNT && inputSource != AUDIO_SOURCE_HOTWORD && + inputSource != AUDIO_SOURCE_FM_TUNER) { + return BAD_VALUE; } - if ((inputSource == AUDIO_SOURCE_HOTWORD) && !captureHotwordAllowed()) { - return 0; + if (inputSource == AUDIO_SOURCE_DEFAULT) { + inputSource = AUDIO_SOURCE_MIC; + } + + if (((inputSource == AUDIO_SOURCE_HOTWORD) && !captureHotwordAllowed()) || + ((inputSource == 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, inputSource, 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, inputSource, 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 +335,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 +353,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 +374,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 +390,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 +403,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 +452,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 +464,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 +560,45 @@ 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 __unused, + 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); + 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; +} - return getOutput(stream, samplingRate, format, channelMask, flags, offloadInfo); +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::acquireSoundTriggerSession(audio_session_t *session, - audio_io_handle_t *ioHandle, - audio_devices_t *device) +status_t AudioPolicyService::releaseSoundTriggerSession(audio_session_t session __unused) { return INVALID_OPERATION; } -status_t AudioPolicyService::releaseSoundTriggerSession(audio_session_t session) +status_t AudioPolicyService::registerPolicyMixes(Vector<AudioMix> mixes __unused, + bool registration __unused) { return INVALID_OPERATION; } diff --git a/services/audiopolicy/AudioPolicyManager.cpp b/services/audiopolicy/AudioPolicyManager.cpp index 536987a..a58d60c 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" @@ -210,25 +211,29 @@ bool AudioPolicyManager::stringToBool(const char *value) // AudioPolicyInterface implementation // ---------------------------------------------------------------------------- - status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device, audio_policy_dev_state_t state, const char *device_address) { - String8 address = (device_address == NULL) ? String8("") : String8(device_address); + return setDeviceConnectionStateInt(device, state, device_address); +} +status_t AudioPolicyManager::setDeviceConnectionStateInt(audio_devices_t device, + audio_policy_dev_state_t state, + const char *device_address) +{ ALOGV("setDeviceConnectionState() device: %x, state %d, address %s", - device, state, address.string()); + device, state, device_address != NULL ? device_address : ""); // connect/disconnect only 1 device at a time if (!audio_is_output_device(device) && !audio_is_input_device(device)) return BAD_VALUE; + sp<DeviceDescriptor> devDesc = getDeviceDescriptor(device, device_address); + // handle output devices if (audio_is_output_device(device)) { SortedVector <audio_io_handle_t> outputs; - sp<DeviceDescriptor> devDesc = new DeviceDescriptor(String8(""), device); - devDesc->mAddress = address; ssize_t index = mAvailableOutputDevices.indexOf(devDesc); // save a copy of the opened output descriptors before any output is opened or closed @@ -260,7 +265,7 @@ status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device, return NO_MEMORY; } - if (checkOutputsForDevice(devDesc, state, outputs, address) != NO_ERROR) { + if (checkOutputsForDevice(devDesc, state, outputs, devDesc->mAddress) != NO_ERROR) { mAvailableOutputDevices.remove(devDesc); return INVALID_OPERATION; } @@ -280,14 +285,14 @@ status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device, ALOGV("setDeviceConnectionState() disconnecting output device %x", device); // Set Disconnect to HALs - AudioParameter param = AudioParameter(address); + AudioParameter param = AudioParameter(devDesc->mAddress); param.addInt(String8(AUDIO_PARAMETER_DEVICE_DISCONNECT), device); mpClientInterface->setParameters(AUDIO_IO_HANDLE_NONE, param.toString()); // remove device from available output devices mAvailableOutputDevices.remove(devDesc); - checkOutputsForDevice(devDesc, state, outputs, address); + checkOutputsForDevice(devDesc, state, outputs, devDesc->mAddress); } break; default: @@ -344,8 +349,6 @@ status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device, if (audio_is_input_device(device)) { SortedVector <audio_io_handle_t> inputs; - sp<DeviceDescriptor> devDesc = new DeviceDescriptor(String8(""), device); - devDesc->mAddress = address; ssize_t index = mAvailableInputDevices.indexOf(devDesc); switch (state) { @@ -361,7 +364,7 @@ status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device, device); return INVALID_OPERATION; } - if (checkInputsForDevice(device, state, inputs, address) != NO_ERROR) { + if (checkInputsForDevice(device, state, inputs, devDesc->mAddress) != NO_ERROR) { return INVALID_OPERATION; } @@ -384,11 +387,11 @@ status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device, ALOGV("setDeviceConnectionState() disconnecting input device %x", device); // Set Disconnect to HALs - AudioParameter param = AudioParameter(address); + AudioParameter param = AudioParameter(devDesc->mAddress); param.addInt(String8(AUDIO_PARAMETER_DEVICE_DISCONNECT), device); mpClientInterface->setParameters(AUDIO_IO_HANDLE_NONE, param.toString()); - checkInputsForDevice(device, state, inputs, address); + checkInputsForDevice(device, state, inputs, devDesc->mAddress); mAvailableInputDevices.remove(devDesc); } break; @@ -416,10 +419,7 @@ status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device, audio_policy_dev_state_t AudioPolicyManager::getDeviceConnectionState(audio_devices_t device, const char *device_address) { - 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); - ssize_t index; + sp<DeviceDescriptor> devDesc = getDeviceDescriptor(device, device_address); DeviceVector *deviceVector; if (audio_is_output_device(device)) { @@ -431,7 +431,7 @@ audio_policy_dev_state_t AudioPolicyManager::getDeviceConnectionState(audio_devi return AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE; } - index = deviceVector->indexOf(devDesc); + ssize_t index = deviceVector->indexOf(devDesc); if (index >= 0) { return AUDIO_POLICY_DEVICE_STATE_AVAILABLE; } else { @@ -439,6 +439,36 @@ audio_policy_dev_state_t AudioPolicyManager::getDeviceConnectionState(audio_devi } } +sp<AudioPolicyManager::DeviceDescriptor> AudioPolicyManager::getDeviceDescriptor( + const 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"); + } + + for (size_t i = 0; i < mHwModules.size(); i++) { + if (mHwModules[i]->mHandle == 0) { + continue; + } + DeviceVector deviceList = + mHwModules[i]->mDeclaredDevices.getDevicesFromTypeAddr(device, address); + if (!deviceList.isEmpty()) { + return deviceList.itemAt(0); + } + deviceList = mHwModules[i]->mDeclaredDevices.getDevicesFromType(device); + if (!deviceList.isEmpty()) { + return deviceList.itemAt(0); + } + } + + sp<DeviceDescriptor> devDesc = new DeviceDescriptor(String8(""), device); + devDesc->mAddress = address; + return devDesc; +} + void AudioPolicyManager::updateCallRouting(audio_devices_t rxDevice, int delayMs) { bool createTxPatch = false; @@ -449,7 +479,7 @@ void AudioPolicyManager::updateCallRouting(audio_devices_t rxDevice, int delayMs audio_patch_handle_t afPatchHandle; DeviceVector deviceList; - audio_devices_t txDevice = getDeviceForInputSource(AUDIO_SOURCE_VOICE_COMMUNICATION); + audio_devices_t txDevice = getDeviceAndMixForInputSource(AUDIO_SOURCE_VOICE_COMMUNICATION); ALOGV("updateCallRouting device rxDevice %08x txDevice %08x", rxDevice, txDevice); // release existing RX patch if any @@ -576,8 +606,14 @@ 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); } + + // force reevaluating accessibility routing when call starts + mpClientInterface->invalidateStream(AUDIO_STREAM_ACCESSIBILITY); } // store previous phone state for management of sonification strategy below @@ -673,6 +709,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 +746,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; } @@ -803,7 +842,7 @@ sp<AudioPolicyManager::IOProfile> AudioPolicyManager::getProfileForDirectOutput( } for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++) { sp<IOProfile> profile = mHwModules[i]->mOutputProfiles[j]; - bool found = profile->isCompatibleProfile(device, samplingRate, + bool found = profile->isCompatibleProfile(device, String8(""), samplingRate, NULL /*updatedSamplingRate*/, format, channelMask, flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD ? AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD : AUDIO_OUTPUT_FLAG_DIRECT); @@ -822,48 +861,113 @@ 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); -} + 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); + } -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; + for (size_t i = 0; i < mPolicyMixes.size(); i++) { + sp<AudioOutputDescriptor> desc; + if (mPolicyMixes[i]->mMix.mMixType == MIX_TYPE_PLAYERS) { + for (size_t j = 0; j < mPolicyMixes[i]->mMix.mCriteria.size(); j++) { + if ((RULE_MATCH_ATTRIBUTE_USAGE == mPolicyMixes[i]->mMix.mCriteria[j].mRule && + mPolicyMixes[i]->mMix.mCriteria[j].mAttr.mUsage == attributes.usage) || + (RULE_EXCLUDE_ATTRIBUTE_USAGE == mPolicyMixes[i]->mMix.mCriteria[j].mRule && + mPolicyMixes[i]->mMix.mCriteria[j].mAttr.mUsage != attributes.usage)) { + desc = mPolicyMixes[i]->mOutput; + break; + } + if (strncmp(attributes.tags, "addr=", strlen("addr=")) == 0 && + strncmp(attributes.tags + strlen("addr="), + mPolicyMixes[i]->mMix.mRegistrationId.string(), + AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - strlen("addr=") - 1) == 0) { + desc = mPolicyMixes[i]->mOutput; + break; + } + } + } else if (mPolicyMixes[i]->mMix.mMixType == MIX_TYPE_RECORDERS) { + if (attributes.usage == AUDIO_USAGE_VIRTUAL_SOURCE && + strncmp(attributes.tags, "addr=", strlen("addr=")) == 0 && + strncmp(attributes.tags + strlen("addr="), + mPolicyMixes[i]->mMix.mRegistrationId.string(), + AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - strlen("addr=") - 1) == 0) { + desc = mPolicyMixes[i]->mOutput; + } + } + if (desc != 0) { + if (!audio_is_linear_pcm(format)) { + return BAD_VALUE; + } + desc->mPolicyMix = &mPolicyMixes[i]->mMix; + *stream = streamTypefromAttributesInt(&attributes); + *output = desc->mIoHandle; + ALOGV("getOutputForAttr() returns output %d", *output); + return NO_ERROR; + } + } + if (attributes.usage == AUDIO_USAGE_VIRTUAL_SOURCE) { + ALOGW("getOutputForAttr() no policy mix found for usage AUDIO_USAGE_VIRTUAL_SOURCE"); + return BAD_VALUE; } + 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 +1030,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; @@ -1005,6 +1113,10 @@ audio_io_handle_t AudioPolicyManager::getOutputForDevice( if (output != AUDIO_IO_HANDLE_NONE) { mpClientInterface->closeOutput(output); } + // fall back to mixer output if possible when the direct output could not be open + if (audio_is_linear_pcm(format) && samplingRate <= MAX_MIXER_SAMPLING_RATE) { + goto non_direct_output; + } return AUDIO_IO_HANDLE_NONE; } outputDesc->mSamplingRate = config.sample_rate; @@ -1110,7 +1222,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 +1231,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: @@ -1127,11 +1253,18 @@ status_t AudioPolicyManager::startOutput(audio_io_handle_t output, outputDesc->changeRefCount(stream, 1); if (outputDesc->mRefCount[stream] == 1) { - audio_devices_t newDevice = getNewOutputDevice(output, false /*fromCache*/); + // starting an output being rerouted? + audio_devices_t newDevice; + if (outputDesc->mPolicyMix != NULL) { + newDevice = AUDIO_DEVICE_OUT_REMOTE_SUBMIX; + } else { + 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 +1278,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; @@ -1168,6 +1302,21 @@ status_t AudioPolicyManager::startOutput(audio_io_handle_t output, // update the outputs if starting an output with a stream that can affect notification // routing handleNotificationRoutingForStream(stream); + + // Automatically enable the remote submix input when output is started on a re routing mix + // of type MIX_TYPE_RECORDERS + if (audio_is_remote_submix_device(newDevice) && outputDesc->mPolicyMix != NULL && + outputDesc->mPolicyMix->mMixType == MIX_TYPE_RECORDERS) { + setDeviceConnectionStateInt(AUDIO_DEVICE_IN_REMOTE_SUBMIX, + AUDIO_POLICY_DEVICE_STATE_AVAILABLE, + outputDesc->mPolicyMix->mRegistrationId); + } + + // force reevaluating accessibility routing when ringtone or alarm starts + if (strategy == STRATEGY_SONIFICATION) { + mpClientInterface->invalidateStream(AUDIO_STREAM_ACCESSIBILITY); + } + if (waitMs > muteWaitMs) { usleep((waitMs - muteWaitMs) * 2 * 1000); } @@ -1178,7 +1327,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 +1338,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); @@ -1199,6 +1351,16 @@ status_t AudioPolicyManager::stopOutput(audio_io_handle_t output, outputDesc->changeRefCount(stream, -1); // store time at which the stream was stopped - see isStreamActive() if (outputDesc->mRefCount[stream] == 0) { + // Automatically disable the remote submix input when output is stopped on a + // re routing mix of type MIX_TYPE_RECORDERS + if (audio_is_remote_submix_device(outputDesc->mDevice) && + outputDesc->mPolicyMix != NULL && + outputDesc->mPolicyMix->mMixType == MIX_TYPE_RECORDERS) { + setDeviceConnectionStateInt(AUDIO_DEVICE_IN_REMOTE_SUBMIX, + AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, + outputDesc->mPolicyMix->mRegistrationId); + } + outputDesc->mStopTime[stream] = systemTime(); audio_devices_t newDevice = getNewOutputDevice(output, false /*fromCache*/); // delay the device switch by twice the latency because stopOutput() is executed when @@ -1233,7 +1395,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,79 +1440,121 @@ 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, + input_type_t *inputType) { - ALOGV("getInput() inputSource %d, samplingRate %d, format %d, channelMask %x, session %d, " - "flags %#x", - inputSource, samplingRate, format, channelMask, session, flags); - - audio_devices_t device = getDeviceForInputSource(inputSource); + ALOGV("getInputForAttr() source %d, samplingRate %d, format %d, channelMask %x," + "session %d, flags %#x", + attr->source, samplingRate, format, channelMask, session, flags); - if (device == AUDIO_DEVICE_NONE) { - ALOGW("getInput() could not find device for inputSource %d", inputSource); - return AUDIO_IO_HANDLE_NONE; - } + *input = AUDIO_IO_HANDLE_NONE; + *inputType = API_INPUT_INVALID; + audio_devices_t device; + // handle legacy remote submix case where the address was not always specified + String8 address = String8(""); + bool isSoundTrigger = false; + audio_source_t inputSource = attr->source; + audio_source_t halInputSource; + AudioMix *policyMix = NULL; - // adapt channel selection to input source - switch (inputSource) { - case AUDIO_SOURCE_VOICE_UPLINK: - channelMask = AUDIO_CHANNEL_IN_VOICE_UPLINK; - break; - case AUDIO_SOURCE_VOICE_DOWNLINK: - channelMask = AUDIO_CHANNEL_IN_VOICE_DNLINK; - break; - case AUDIO_SOURCE_VOICE_CALL: - channelMask = AUDIO_CHANNEL_IN_VOICE_UPLINK | AUDIO_CHANNEL_IN_VOICE_DNLINK; - break; - default: - break; + if (inputSource == AUDIO_SOURCE_DEFAULT) { + inputSource = AUDIO_SOURCE_MIC; } + halInputSource = inputSource; - audio_io_handle_t input = AUDIO_IO_HANDLE_NONE; - bool isSoundTrigger = false; - audio_source_t halInputSource = inputSource; - if (inputSource == AUDIO_SOURCE_HOTWORD) { - ssize_t index = mSoundTriggerSessions.indexOfKey(session); - if (index >= 0) { - 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); + if (inputSource == AUDIO_SOURCE_REMOTE_SUBMIX && + strncmp(attr->tags, "addr=", strlen("addr=")) == 0) { + device = AUDIO_DEVICE_IN_REMOTE_SUBMIX; + address = String8(attr->tags + strlen("addr=")); + ssize_t index = mPolicyMixes.indexOfKey(address); + if (index < 0) { + ALOGW("getInputForAttr() no policy for address %s", address.string()); + return BAD_VALUE; + } + if (mPolicyMixes[index]->mMix.mMixType != MIX_TYPE_PLAYERS) { + ALOGW("getInputForAttr() bad policy mix type for address %s", address.string()); + return BAD_VALUE; + } + policyMix = &mPolicyMixes[index]->mMix; + *inputType = API_INPUT_MIX_EXT_POLICY_REROUTE; + } else { + device = getDeviceAndMixForInputSource(inputSource, &policyMix); + if (device == AUDIO_DEVICE_NONE) { + ALOGW("getInputForAttr() could not find device for source %d", inputSource); + return BAD_VALUE; + } + if (policyMix != NULL) { + address = policyMix->mRegistrationId; + if (policyMix->mMixType == MIX_TYPE_RECORDERS) { + // there is an external policy, but this input is attached to a mix of recorders, + // meaning it receives audio injected into the framework, so the recorder doesn't + // know about it and is therefore considered "legacy" + *inputType = API_INPUT_LEGACY; + } else { + // recording a mix of players defined by an external policy, we're rerouting for + // an external policy + *inputType = API_INPUT_MIX_EXT_POLICY_REROUTE; + } + } else if (audio_is_remote_submix_device(device)) { + address = String8("0"); + *inputType = API_INPUT_MIX_CAPTURE; } else { - halInputSource = AUDIO_SOURCE_VOICE_RECOGNITION; + *inputType = API_INPUT_LEGACY; + } + // adapt channel selection to input source + switch (inputSource) { + case AUDIO_SOURCE_VOICE_UPLINK: + channelMask = AUDIO_CHANNEL_IN_VOICE_UPLINK; + break; + case AUDIO_SOURCE_VOICE_DOWNLINK: + channelMask = AUDIO_CHANNEL_IN_VOICE_DNLINK; + break; + case AUDIO_SOURCE_VOICE_CALL: + channelMask = AUDIO_CHANNEL_IN_VOICE_UPLINK | AUDIO_CHANNEL_IN_VOICE_DNLINK; + break; + default: + break; + } + if (inputSource == AUDIO_SOURCE_HOTWORD) { + ssize_t index = mSoundTriggerSessions.indexOfKey(session); + if (index >= 0) { + *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); + } else { + halInputSource = AUDIO_SOURCE_VOICE_RECOGNITION; + } } } - sp<IOProfile> profile = getInputProfile(device, - samplingRate, - format, - channelMask, - flags); + sp<IOProfile> profile = getInputProfile(device, address, + samplingRate, format, channelMask, + flags); if (profile == 0) { //retry without flags audio_input_flags_t log_flags = flags; flags = AUDIO_INPUT_FLAG_NONE; - profile = getInputProfile(device, - samplingRate, - format, - channelMask, - flags); + profile = getInputProfile(device, address, + samplingRate, format, 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; @@ -1357,24 +1563,24 @@ audio_io_handle_t AudioPolicyManager::getInput(audio_source_t inputSource, config.format = format; 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); @@ -1387,10 +1593,13 @@ audio_io_handle_t AudioPolicyManager::getInput(audio_source_t inputSource, inputDesc->mDevice = device; inputDesc->mSessions.add(session); inputDesc->mIsSoundTrigger = isSoundTrigger; + inputDesc->mPolicyMix = policyMix; - addInput(input, inputDesc); + ALOGV("getInputForAttr() returns input type = %d", inputType); + + addInput(*input, inputDesc); mpClientInterface->onAudioPortListUpdate(); - return input; + return NO_ERROR; } status_t AudioPolicyManager::startInput(audio_io_handle_t input, @@ -1437,11 +1646,21 @@ status_t AudioPolicyManager::startInput(audio_io_handle_t input, } setInputDevice(input, getNewInputDevice(input), true /* force */); - // Automatically enable the remote submix output when input is started. + // automatically enable the remote submix output when input is started if not + // used by a policy mix of type MIX_TYPE_RECORDERS // For remote submix (a virtual device), we open only one input per capture request. if (audio_is_remote_submix_device(inputDesc->mDevice)) { - setDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX, - AUDIO_POLICY_DEVICE_STATE_AVAILABLE, AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS); + String8 address = String8(""); + if (inputDesc->mPolicyMix == NULL) { + address = String8("0"); + } else if (inputDesc->mPolicyMix->mMixType == MIX_TYPE_PLAYERS) { + address = inputDesc->mPolicyMix->mRegistrationId; + } + if (address != "") { + setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_REMOTE_SUBMIX, + AUDIO_POLICY_DEVICE_STATE_AVAILABLE, + address); + } } } @@ -1476,10 +1695,20 @@ status_t AudioPolicyManager::stopInput(audio_io_handle_t input, inputDesc->mRefCount--; if (inputDesc->mRefCount == 0) { - // automatically disable the remote submix output when input is stopped + // automatically disable the remote submix output when input is stopped if not + // used by a policy mix of type MIX_TYPE_RECORDERS if (audio_is_remote_submix_device(inputDesc->mDevice)) { - setDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX, - AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS); + String8 address = String8(""); + if (inputDesc->mPolicyMix == NULL) { + address = String8("0"); + } else if (inputDesc->mPolicyMix->mMixType == MIX_TYPE_PLAYERS) { + address = inputDesc->mPolicyMix->mRegistrationId; + } + if (address != "") { + setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_REMOTE_SUBMIX, + AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, + address); + } } resetInputDevice(input); @@ -1557,6 +1786,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 +1818,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; } @@ -1814,7 +2066,11 @@ bool AudioPolicyManager::isStreamActiveRemotely(audio_stream_type_t stream, const sp<AudioOutputDescriptor> outputDesc = mOutputs.valueAt(i); if (((outputDesc->device() & APM_AUDIO_OUT_DEVICE_REMOTE_ALL) != 0) && outputDesc->isStreamActive(stream, inPastMs, sysTime)) { - return true; + // do not consider re routing (when the output is going to a dynamic policy) + // as "remote playback" + if (outputDesc->mPolicyMix == NULL) { + return true; + } } } return false; @@ -1824,16 +2080,148 @@ bool AudioPolicyManager::isSourceActive(audio_source_t source) const { for (size_t i = 0; i < mInputs.size(); i++) { const sp<AudioInputDescriptor> inputDescriptor = mInputs.valueAt(i); - if ((inputDescriptor->mInputSource == (int)source || - (source == AUDIO_SOURCE_VOICE_RECOGNITION && - inputDescriptor->mInputSource == AUDIO_SOURCE_HOTWORD)) - && (inputDescriptor->mRefCount > 0)) { + if (inputDescriptor->mRefCount == 0) { + continue; + } + if (inputDescriptor->mInputSource == (int)source) { return true; } + // AUDIO_SOURCE_HOTWORD is equivalent to AUDIO_SOURCE_VOICE_RECOGNITION only if it + // corresponds to an active capture triggered by a hardware hotword recognition + if ((source == AUDIO_SOURCE_VOICE_RECOGNITION) && + (inputDescriptor->mInputSource == AUDIO_SOURCE_HOTWORD)) { + // FIXME: we should not assume that the first session is the active one and keep + // activity count per session. Same in startInput(). + ssize_t index = mSoundTriggerSessions.indexOfKey(inputDescriptor->mSessions.itemAt(0)); + if (index >= 0) { + return true; + } + } } return false; } +// Register a list of custom mixes with their attributes and format. +// When a mix is registered, corresponding input and output profiles are +// added to the remote submix hw module. The profile contains only the +// parameters (sampling rate, format...) specified by the mix. +// The corresponding input remote submix device is also connected. +// +// When a remote submix device is connected, the address is checked to select the +// appropriate profile and the corresponding input or output stream is opened. +// +// When capture starts, getInputForAttr() will: +// - 1 look for a mix matching the address passed in attribtutes tags if any +// - 2 if none found, getDeviceForInputSource() will: +// - 2.1 look for a mix matching the attributes source +// - 2.2 if none found, default to device selection by policy rules +// At this time, the corresponding output remote submix device is also connected +// and active playback use cases can be transferred to this mix if needed when reconnecting +// after AudioTracks are invalidated +// +// When playback starts, getOutputForAttr() will: +// - 1 look for a mix matching the address passed in attribtutes tags if any +// - 2 if none found, look for a mix matching the attributes usage +// - 3 if none found, default to device and output selection by policy rules. + +status_t AudioPolicyManager::registerPolicyMixes(Vector<AudioMix> mixes) +{ + sp<HwModule> module; + for (size_t i = 0; i < mHwModules.size(); i++) { + if (strcmp(AUDIO_HARDWARE_MODULE_ID_REMOTE_SUBMIX, mHwModules[i]->mName) == 0 && + mHwModules[i]->mHandle != 0) { + module = mHwModules[i]; + break; + } + } + + if (module == 0) { + return INVALID_OPERATION; + } + + ALOGV("registerPolicyMixes() num mixes %d", mixes.size()); + + for (size_t i = 0; i < mixes.size(); i++) { + String8 address = mixes[i].mRegistrationId; + ssize_t index = mPolicyMixes.indexOfKey(address); + if (index >= 0) { + ALOGE("registerPolicyMixes(): mix for address %s already registered", address.string()); + continue; + } + audio_config_t outputConfig = mixes[i].mFormat; + audio_config_t inputConfig = mixes[i].mFormat; + // NOTE: audio flinger mixer does not support mono output: configure remote submix HAL in + // stereo and let audio flinger do the channel conversion if needed. + outputConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO; + inputConfig.channel_mask = AUDIO_CHANNEL_IN_STEREO; + module->addOutputProfile(address, &outputConfig, + AUDIO_DEVICE_OUT_REMOTE_SUBMIX, address); + module->addInputProfile(address, &inputConfig, + AUDIO_DEVICE_IN_REMOTE_SUBMIX, address); + sp<AudioPolicyMix> policyMix = new AudioPolicyMix(); + policyMix->mMix = mixes[i]; + mPolicyMixes.add(address, policyMix); + if (mixes[i].mMixType == MIX_TYPE_PLAYERS) { + setDeviceConnectionStateInt(AUDIO_DEVICE_IN_REMOTE_SUBMIX, + AUDIO_POLICY_DEVICE_STATE_AVAILABLE, + address.string()); + } else { + setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_REMOTE_SUBMIX, + AUDIO_POLICY_DEVICE_STATE_AVAILABLE, + address.string()); + } + } + return NO_ERROR; +} + +status_t AudioPolicyManager::unregisterPolicyMixes(Vector<AudioMix> mixes) +{ + sp<HwModule> module; + for (size_t i = 0; i < mHwModules.size(); i++) { + if (strcmp(AUDIO_HARDWARE_MODULE_ID_REMOTE_SUBMIX, mHwModules[i]->mName) == 0 && + mHwModules[i]->mHandle != 0) { + module = mHwModules[i]; + break; + } + } + + if (module == 0) { + return INVALID_OPERATION; + } + + ALOGV("unregisterPolicyMixes() num mixes %d", mixes.size()); + + for (size_t i = 0; i < mixes.size(); i++) { + String8 address = mixes[i].mRegistrationId; + ssize_t index = mPolicyMixes.indexOfKey(address); + if (index < 0) { + ALOGE("unregisterPolicyMixes(): mix for address %s not registered", address.string()); + continue; + } + + mPolicyMixes.removeItemsAt(index); + + if (getDeviceConnectionState(AUDIO_DEVICE_IN_REMOTE_SUBMIX, address.string()) == + AUDIO_POLICY_DEVICE_STATE_AVAILABLE) + { + setDeviceConnectionStateInt(AUDIO_DEVICE_IN_REMOTE_SUBMIX, + AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, + address.string()); + } + + if (getDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX, address.string()) == + AUDIO_POLICY_DEVICE_STATE_AVAILABLE) + { + setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_REMOTE_SUBMIX, + AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, + address.string()); + } + module->removeOutputProfile(address); + module->removeInputProfile(address); + } + return NO_ERROR; +} + status_t AudioPolicyManager::dump(int fd) { @@ -2234,6 +2622,7 @@ status_t AudioPolicyManager::createAudioPatch(const struct audio_patch *patch, } if (!outputDesc->mProfile->isCompatibleProfile(devDesc->mDeviceType, + devDesc->mAddress, patch->sources[0].sample_rate, NULL, // updatedSamplingRate patch->sources[0].format, @@ -2288,13 +2677,14 @@ status_t AudioPolicyManager::createAudioPatch(const struct audio_patch *patch, } if (!inputDesc->mProfile->isCompatibleProfile(devDesc->mDeviceType, - patch->sinks[0].sample_rate, - NULL, /*updatedSampleRate*/ - patch->sinks[0].format, - patch->sinks[0].channel_mask, - // FIXME for the parameter type, - // and the NONE - (audio_output_flags_t) + devDesc->mAddress, + patch->sinks[0].sample_rate, + NULL, /*updatedSampleRate*/ + patch->sinks[0].format, + patch->sinks[0].channel_mask, + // FIXME for the parameter type, + // and the NONE + (audio_output_flags_t) AUDIO_INPUT_FLAG_NONE)) { return INVALID_OPERATION; } @@ -2561,13 +2951,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); } } } @@ -2578,7 +2965,7 @@ status_t AudioPolicyManager::acquireSoundTriggerSession(audio_session_t *session { *session = (audio_session_t)mpClientInterface->newAudioUniqueId(); *ioHandle = (audio_io_handle_t)mpClientInterface->newAudioUniqueId(); - *device = getDeviceForInputSource(AUDIO_SOURCE_HOTWORD); + *device = getDeviceAndMixForInputSource(AUDIO_SOURCE_HOTWORD); mSoundTriggerSessions.add(*session, *ioHandle); @@ -2653,7 +3040,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 +3177,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 +3194,7 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa &input, &config, &inputDesc->mDevice, - String8(""), + address, AUDIO_SOURCE_MIC, AUDIO_INPUT_FLAG_NONE); @@ -3069,29 +3467,15 @@ void AudioPolicyManager::addInput(audio_io_handle_t input, sp<AudioInputDescript } void AudioPolicyManager::findIoHandlesByAddress(sp<AudioOutputDescriptor> desc /*in*/, + const audio_devices_t device /*in*/, const String8 address /*in*/, SortedVector<audio_io_handle_t>& outputs /*out*/) { - // look for a match on the given address on the addresses of the outputs: - // find the address by finding the patch that maps to this output - ssize_t patchIdx = mAudioPatches.indexOfKey(desc->mPatchHandle); - //ALOGV(" inspecting output %d (patch %d) for supported device=0x%x", - // outputIdx, patchIdx, desc->mProfile->mSupportedDevices.types()); - if (patchIdx >= 0) { - const sp<AudioPatch> patchDesc = mAudioPatches.valueAt(patchIdx); - const int numSinks = patchDesc->mPatch.num_sinks; - for (ssize_t j=0; j < numSinks; j++) { - if (patchDesc->mPatch.sinks[j].type == AUDIO_PORT_TYPE_DEVICE) { - const char* patchAddr = - patchDesc->mPatch.sinks[j].ext.device.address; - if (strncmp(patchAddr, - address.string(), AUDIO_DEVICE_MAX_ADDRESS_LEN) == 0) { - ALOGV("findIoHandlesByAddress(): adding opened output %d on same address %s", - desc->mIoHandle, patchDesc->mPatch.sinks[j].ext.device.address); - outputs.add(desc->mIoHandle); - break; - } - } - } + sp<DeviceDescriptor> devDesc = + desc->mProfile->mSupportedDevices.getDevice(device, address); + if (devDesc != 0) { + ALOGV("findIoHandlesByAddress(): adding opened output %d on same address %s", + desc->mIoHandle, address.string()); + outputs.add(desc->mIoHandle); } } @@ -3115,7 +3499,7 @@ status_t AudioPolicyManager::checkOutputsForDevice(const sp<DeviceDescriptor> de outputs.add(mOutputs.keyAt(i)); } else { ALOGV(" checking address match due to device 0x%x", device); - findIoHandlesByAddress(desc, address, outputs); + findIoHandlesByAddress(desc, device, address, outputs); } } } @@ -3128,9 +3512,13 @@ status_t AudioPolicyManager::checkOutputsForDevice(const sp<DeviceDescriptor> de } for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++) { - if (mHwModules[i]->mOutputProfiles[j]->mSupportedDevices.types() & device) { - ALOGV("checkOutputsForDevice(): adding profile %zu from module %zu", j, i); - profiles.add(mHwModules[i]->mOutputProfiles[j]); + sp<IOProfile> profile = mHwModules[i]->mOutputProfiles[j]; + if (profile->mSupportedDevices.types() & device) { + if (!deviceDistinguishesOnAddress(device) || + address == profile->mSupportedDevices[0]->mAddress) { + profiles.add(profile); + ALOGV("checkOutputsForDevice(): adding profile %zu from module %zu", j, i); + } } } } @@ -3262,7 +3650,18 @@ status_t AudioPolicyManager::checkOutputsForDevice(const sp<DeviceDescriptor> de if (output != AUDIO_IO_HANDLE_NONE) { addOutput(output, desc); - if ((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0) { + if (deviceDistinguishesOnAddress(device) && address != "0") { + ssize_t index = mPolicyMixes.indexOfKey(address); + if (index >= 0) { + mPolicyMixes[index]->mOutput = desc; + desc->mPolicyMix = &mPolicyMixes[index]->mMix; + } else { + ALOGE("checkOutputsForDevice() cannot find policy for address %s", + address.string()); + } + } else if ((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0) { + // no duplicated output for direct outputs and + // outputs used by dynamic policy mixes audio_io_handle_t duplicatedOutput = AUDIO_IO_HANDLE_NONE; // set initial stream volume for device @@ -3325,15 +3724,15 @@ status_t AudioPolicyManager::checkOutputsForDevice(const sp<DeviceDescriptor> de for (size_t i = 0; i < mOutputs.size(); i++) { desc = mOutputs.valueAt(i); if (!desc->isDuplicated()) { - if (!(desc->mProfile->mSupportedDevices.types() + // exact match on device + if (deviceDistinguishesOnAddress(device) && + (desc->mProfile->mSupportedDevices.types() == device)) { + findIoHandlesByAddress(desc, device, address, outputs); + } else if (!(desc->mProfile->mSupportedDevices.types() & mAvailableOutputDevices.types())) { ALOGV("checkOutputsForDevice(): disconnecting adding output %d", mOutputs.keyAt(i)); outputs.add(mOutputs.keyAt(i)); - } else if (deviceDistinguishesOnAddress(device) && - // exact match on device - (desc->mProfile->mSupportedDevices.types() == device)) { - findIoHandlesByAddress(desc, address, outputs); } } } @@ -3395,11 +3794,15 @@ status_t AudioPolicyManager::checkInputsForDevice(audio_devices_t device, profile_index < mHwModules[module_idx]->mInputProfiles.size(); profile_index++) { - if (mHwModules[module_idx]->mInputProfiles[profile_index]->mSupportedDevices.types() - & (device & ~AUDIO_DEVICE_BIT_IN)) { - ALOGV("checkInputsForDevice(): adding profile %zu from module %zu", - profile_index, module_idx); - profiles.add(mHwModules[module_idx]->mInputProfiles[profile_index]); + sp<IOProfile> profile = mHwModules[module_idx]->mInputProfiles[profile_index]; + + if (profile->mSupportedDevices.types() & (device & ~AUDIO_DEVICE_BIT_IN)) { + if (!deviceDistinguishesOnAddress(device) || + address == profile->mSupportedDevices[0]->mAddress) { + profiles.add(profile); + ALOGV("checkInputsForDevice(): adding profile %zu from module %zu", + profile_index, module_idx); + } } } } @@ -3517,7 +3920,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 +3936,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) { @@ -3566,6 +3970,12 @@ void AudioPolicyManager::closeOutput(audio_io_handle_t output) return; } + for (size_t i = 0; i < mPolicyMixes.size(); i++) { + if (mPolicyMixes[i]->mOutput == outputDesc) { + mPolicyMixes[i]->mOutput.clear(); + } + } + // look for duplicated outputs connected to the output being removed. for (size_t i = 0; i < mOutputs.size(); i++) { sp<AudioOutputDescriptor> dupOutputDesc = mOutputs.valueAt(i); @@ -3675,6 +4085,24 @@ void AudioPolicyManager::checkOutputForStrategy(routing_strategy strategy) SortedVector<audio_io_handle_t> srcOutputs = getOutputsForDevice(oldDevice, mPreviousOutputs); SortedVector<audio_io_handle_t> dstOutputs = getOutputsForDevice(newDevice, mOutputs); + // also take into account external policy-related changes: add all outputs which are + // associated with policies in the "before" and "after" output vectors + ALOGVV("checkOutputForStrategy(): policy related outputs"); + for (size_t i = 0 ; i < mPreviousOutputs.size() ; i++) { + const sp<AudioOutputDescriptor> desc = mPreviousOutputs.valueAt(i); + if (desc != 0 && desc->mPolicyMix != NULL) { + srcOutputs.add(desc->mIoHandle); + ALOGVV(" previous outputs: adding %d", desc->mIoHandle); + } + } + for (size_t i = 0 ; i < mOutputs.size() ; i++) { + const sp<AudioOutputDescriptor> desc = mOutputs.valueAt(i); + if (desc != 0 && desc->mPolicyMix != NULL) { + dstOutputs.add(desc->mIoHandle); + ALOGVV(" new outputs: adding %d", desc->mIoHandle); + } + } + if (!vectorsEqual(srcOutputs,dstOutputs)) { ALOGV("checkOutputForStrategy() strategy %d, moving from output %d to output %d", strategy, srcOutputs[0], dstOutputs[0]); @@ -3708,6 +4136,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 +4155,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 +4182,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 +4247,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 +4267,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); @@ -3852,7 +4297,7 @@ audio_devices_t AudioPolicyManager::getNewInputDevice(audio_io_handle_t input) } } - audio_devices_t device = getDeviceForInputSource(inputDesc->mInputSource); + audio_devices_t device = getDeviceAndMixForInputSource(inputDesc->mInputSource); ALOGV("getNewInputDevice() selected device %x", device); return device; @@ -3866,7 +4311,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 +4338,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 +4354,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 +4431,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 +4512,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*/); @@ -4023,7 +4563,8 @@ audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strate // - cannot route from voice call RX OR // - audio HAL version is < 3.0 and TX device is on the primary HW module if (mPhoneState == AUDIO_MODE_IN_CALL) { - audio_devices_t txDevice = getDeviceForInputSource(AUDIO_SOURCE_VOICE_COMMUNICATION); + audio_devices_t txDevice = + getDeviceAndMixForInputSource(AUDIO_SOURCE_VOICE_COMMUNICATION); sp<AudioOutputDescriptor> hwOutputDesc = mOutputs.valueFor(mPrimaryOutput); if (((mAvailableInputDevices.types() & AUDIO_DEVICE_IN_TELEPHONY_RX & ~AUDIO_DEVICE_BIT_IN) == 0) || @@ -4052,7 +4593,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,11 +4628,11 @@ 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; } - if (mPhoneState != AUDIO_MODE_IN_CALL) { + if (!isInCall()) { device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_USB_ACCESSORY; if (device) break; device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_USB_DEVICE; @@ -4141,15 +4682,35 @@ 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) { // no sonification on remote submix (e.g. WFD) - device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_REMOTE_SUBMIX; + if (mAvailableOutputDevices.getDevice(AUDIO_DEVICE_OUT_REMOTE_SUBMIX, String8("0")) != 0) { + device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_REMOTE_SUBMIX; + } } 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 +4719,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 +4813,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 +4914,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; } @@ -4546,6 +5116,7 @@ status_t AudioPolicyManager::resetInputDevice(audio_io_handle_t input, } sp<AudioPolicyManager::IOProfile> AudioPolicyManager::getInputProfile(audio_devices_t device, + String8 address, uint32_t& samplingRate, audio_format_t format, audio_channel_mask_t channelMask, @@ -4563,9 +5134,10 @@ sp<AudioPolicyManager::IOProfile> AudioPolicyManager::getInputProfile(audio_devi { sp<IOProfile> profile = mHwModules[i]->mInputProfiles[j]; // profile->log(); - if (profile->isCompatibleProfile(device, samplingRate, + if (profile->isCompatibleProfile(device, address, samplingRate, &samplingRate /*updatedSamplingRate*/, format, channelMask, (audio_output_flags_t) flags)) { + return profile; } } @@ -4573,11 +5145,42 @@ sp<AudioPolicyManager::IOProfile> AudioPolicyManager::getInputProfile(audio_devi return NULL; } + +audio_devices_t AudioPolicyManager::getDeviceAndMixForInputSource(audio_source_t inputSource, + AudioMix **policyMix) +{ + audio_devices_t availableDeviceTypes = mAvailableInputDevices.types() & + ~AUDIO_DEVICE_BIT_IN; + + for (size_t i = 0; i < mPolicyMixes.size(); i++) { + if (mPolicyMixes[i]->mMix.mMixType != MIX_TYPE_RECORDERS) { + continue; + } + for (size_t j = 0; j < mPolicyMixes[i]->mMix.mCriteria.size(); j++) { + if ((RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET == mPolicyMixes[i]->mMix.mCriteria[j].mRule && + mPolicyMixes[i]->mMix.mCriteria[j].mAttr.mSource == inputSource) || + (RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET == mPolicyMixes[i]->mMix.mCriteria[j].mRule && + mPolicyMixes[i]->mMix.mCriteria[j].mAttr.mSource != inputSource)) { + if (availableDeviceTypes & AUDIO_DEVICE_IN_REMOTE_SUBMIX) { + if (policyMix != NULL) { + *policyMix = &mPolicyMixes[i]->mMix; + } + return AUDIO_DEVICE_IN_REMOTE_SUBMIX; + } + break; + } + } + } + + return getDeviceForInputSource(inputSource); +} + audio_devices_t AudioPolicyManager::getDeviceForInputSource(audio_source_t inputSource) { uint32_t device = AUDIO_DEVICE_NONE; audio_devices_t availableDeviceTypes = mAvailableInputDevices.types() & ~AUDIO_DEVICE_BIT_IN; + switch (inputSource) { case AUDIO_SOURCE_VOICE_UPLINK: if (availableDeviceTypes & AUDIO_DEVICE_IN_VOICE_CALL) { @@ -4590,6 +5193,9 @@ audio_devices_t AudioPolicyManager::getDeviceForInputSource(audio_source_t input case AUDIO_SOURCE_MIC: if (availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_A2DP) { device = AUDIO_DEVICE_IN_BLUETOOTH_A2DP; + } else if ((mForceUse[AUDIO_POLICY_FORCE_FOR_RECORD] == AUDIO_POLICY_FORCE_BT_SCO) && + (availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET)) { + device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET; } else if (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) { device = AUDIO_DEVICE_IN_WIRED_HEADSET; } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) { @@ -4667,6 +5273,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; @@ -4686,7 +5297,7 @@ bool AudioPolicyManager::isVirtualInputDevice(audio_devices_t device) } bool AudioPolicyManager::deviceDistinguishesOnAddress(audio_devices_t device) { - return ((device & APM_AUDIO_DEVICE_MATCH_ADDRESS_ALL) != 0); + return ((device & APM_AUDIO_DEVICE_MATCH_ADDRESS_ALL & ~AUDIO_DEVICE_BIT_IN) != 0); } audio_io_handle_t AudioPolicyManager::getActiveInput(bool ignoreVirtualInputs) @@ -4707,7 +5318,7 @@ uint32_t AudioPolicyManager::activeInputsCount() const for (size_t i = 0; i < mInputs.size(); i++) { const sp<AudioInputDescriptor> desc = mInputs.valueAt(i); if (desc->mRefCount > 0) { - return count++; + count++; } } return count; @@ -4778,6 +5389,7 @@ AudioPolicyManager::device_category AudioPolicyManager::getDeviceCategory(audio_ } } +/* static */ float AudioPolicyManager::volIndexToAmpl(audio_devices_t device, const StreamDescriptor& streamDesc, int indexInUi) { @@ -4891,6 +5503,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 +5575,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 +5622,8 @@ void AudioPolicyManager::initializeVolumeCurves() sSpeakerSonificationVolumeCurveDrc; mStreams[AUDIO_STREAM_MUSIC].mVolumeCurve[DEVICE_CATEGORY_SPEAKER] = sSpeakerMediaVolumeCurveDrc; + mStreams[AUDIO_STREAM_ACCESSIBILITY].mVolumeCurve[DEVICE_CATEGORY_SPEAKER] = + sSpeakerMediaVolumeCurveDrc; } } @@ -5059,6 +5707,18 @@ status_t AudioPolicyManager::checkAndSetVolume(audio_stream_type_t stream, } float volume = computeVolume(stream, index, output, device); + // unit gain if rerouting to external policy + if (device == AUDIO_DEVICE_OUT_REMOTE_SUBMIX) { + ssize_t index = mOutputs.indexOfKey(output); + if (index >= 0) { + sp<AudioOutputDescriptor> outputDesc = mOutputs.valueAt(index); + if (outputDesc->mPolicyMix != NULL) { + ALOGV("max gain when rerouting for output=%d", output); + volume = 1.0f; + } + } + + } // We actually change the volume if: // - the float value returned by computeVolume() changed // - the force flag is set @@ -5101,6 +5761,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 +5781,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); } @@ -5235,7 +5901,8 @@ uint32_t AudioPolicyManager::getMaxEffectsMemory() AudioPolicyManager::AudioOutputDescriptor::AudioOutputDescriptor( const sp<IOProfile>& profile) : mId(0), mIoHandle(0), mLatency(0), - mFlags((audio_output_flags_t)0), mDevice(AUDIO_DEVICE_NONE), mPatchHandle(0), + mFlags((audio_output_flags_t)0), mDevice(AUDIO_DEVICE_NONE), mPolicyMix(NULL), + mPatchHandle(0), mOutput1(0), mOutput2(0), mProfile(profile), mDirectOpenCount(0) { // clear usage count for all stream types @@ -5329,6 +5996,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)) { @@ -5427,7 +6097,7 @@ status_t AudioPolicyManager::AudioOutputDescriptor::dump(int fd) AudioPolicyManager::AudioInputDescriptor::AudioInputDescriptor(const sp<IOProfile>& profile) : mId(0), mIoHandle(0), - mDevice(AUDIO_DEVICE_NONE), mPatchHandle(0), mRefCount(0), + mDevice(AUDIO_DEVICE_NONE), mPolicyMix(NULL), mPatchHandle(0), mRefCount(0), mInputSource(AUDIO_SOURCE_DEFAULT), mProfile(profile), mIsSoundTrigger(false) { if (profile != NULL) { @@ -5717,6 +6387,69 @@ status_t AudioPolicyManager::HwModule::loadDevice(cnode *root) return NO_ERROR; } +status_t AudioPolicyManager::HwModule::addOutputProfile(String8 name, const audio_config_t *config, + audio_devices_t device, String8 address) +{ + sp<IOProfile> profile = new IOProfile(name, AUDIO_PORT_ROLE_SOURCE, this); + + profile->mSamplingRates.add(config->sample_rate); + profile->mChannelMasks.add(config->channel_mask); + profile->mFormats.add(config->format); + + sp<DeviceDescriptor> devDesc = new DeviceDescriptor(String8(""), device); + devDesc->mAddress = address; + profile->mSupportedDevices.add(devDesc); + + mOutputProfiles.add(profile); + + return NO_ERROR; +} + +status_t AudioPolicyManager::HwModule::removeOutputProfile(String8 name) +{ + for (size_t i = 0; i < mOutputProfiles.size(); i++) { + if (mOutputProfiles[i]->mName == name) { + mOutputProfiles.removeAt(i); + break; + } + } + + return NO_ERROR; +} + +status_t AudioPolicyManager::HwModule::addInputProfile(String8 name, const audio_config_t *config, + audio_devices_t device, String8 address) +{ + sp<IOProfile> profile = new IOProfile(name, AUDIO_PORT_ROLE_SINK, this); + + profile->mSamplingRates.add(config->sample_rate); + profile->mChannelMasks.add(config->channel_mask); + profile->mFormats.add(config->format); + + sp<DeviceDescriptor> devDesc = new DeviceDescriptor(String8(""), device); + devDesc->mAddress = address; + profile->mSupportedDevices.add(devDesc); + + ALOGV("addInputProfile() name %s rate %d mask 0x08", name.string(), config->sample_rate, config->channel_mask); + + mInputProfiles.add(profile); + + return NO_ERROR; +} + +status_t AudioPolicyManager::HwModule::removeInputProfile(String8 name) +{ + for (size_t i = 0; i < mInputProfiles.size(); i++) { + if (mInputProfiles[i]->mName == name) { + mInputProfiles.removeAt(i); + break; + } + } + + return NO_ERROR; +} + + void AudioPolicyManager::HwModule::dump(int fd) { const size_t SIZE = 256; @@ -5843,12 +6576,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 +6767,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 +6782,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 +6844,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 +6859,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 +6886,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; @@ -6587,17 +7356,18 @@ AudioPolicyManager::IOProfile::~IOProfile() // Sampling rate, format and channel mask must be specified in order to // get a valid a match bool AudioPolicyManager::IOProfile::isCompatibleProfile(audio_devices_t device, - uint32_t samplingRate, - uint32_t *updatedSamplingRate, - audio_format_t format, - audio_channel_mask_t channelMask, - uint32_t flags) const + String8 address, + uint32_t samplingRate, + uint32_t *updatedSamplingRate, + audio_format_t format, + audio_channel_mask_t channelMask, + uint32_t flags) const { const bool isPlaybackThread = mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SOURCE; const bool isRecordThread = mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SINK; ALOG_ASSERT(isPlaybackThread != isRecordThread); - if ((mSupportedDevices.types() & device) != device) { + if (device != AUDIO_DEVICE_NONE && mSupportedDevices.getDevice(device, address) == 0) { return false; } @@ -6698,9 +7468,6 @@ AudioPolicyManager::DeviceDescriptor::DeviceDescriptor(const String8& name, audi NULL), mDeviceType(type), mAddress(""), mId(0) { - if (mGains.size() > 0) { - mGains[0]->getDefaultConfig(&mGain); - } } bool AudioPolicyManager::DeviceDescriptor::equals(const sp<DeviceDescriptor>& other) const @@ -6715,6 +7482,15 @@ bool AudioPolicyManager::DeviceDescriptor::equals(const sp<DeviceDescriptor>& ot mChannelMask == other->mChannelMask); } +void AudioPolicyManager::DeviceDescriptor::loadGains(cnode *root) +{ + AudioPort::loadGains(root); + if (mGains.size() > 0) { + mGains[0]->getDefaultConfig(&mGain); + } +} + + void AudioPolicyManager::DeviceVector::refreshTypes() { mDeviceTypes = AUDIO_DEVICE_NONE; @@ -6791,7 +7567,12 @@ 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 || + type == AUDIO_DEVICE_OUT_REMOTE_SUBMIX ) { + dev->mAddress = String8("0"); + } + add(dev); } else { sp<DeviceDescriptor> deviceDesc = declaredDevices.getDeviceFromName(String8(devName)); @@ -6800,7 +7581,7 @@ void AudioPolicyManager::DeviceVector::loadDevicesFromName(char *name, } } } - devName = strtok(NULL, "|"); + devName = strtok(NULL, "|"); } } @@ -6810,13 +7591,15 @@ sp<AudioPolicyManager::DeviceDescriptor> AudioPolicyManager::DeviceVector::getDe sp<DeviceDescriptor> device; for (size_t i = 0; i < size(); i++) { if (itemAt(i)->mDeviceType == type) { - device = itemAt(i); - if (itemAt(i)->mAddress = address) { - break; + if (address == "" || itemAt(i)->mAddress == address) { + device = itemAt(i); + if (itemAt(i)->mAddress == address) { + break; + } } } } - ALOGV("DeviceVector::getDevice() for type %d address %s found %p", + ALOGV("DeviceVector::getDevice() for type %08x address %s found %p", type, address.string(), device.get()); return device; } @@ -6854,13 +7637,9 @@ AudioPolicyManager::DeviceVector AudioPolicyManager::DeviceVector::getDevicesFro audio_devices_t type, String8 address) const { DeviceVector devices; - //ALOGV(" looking for device=%x, addr=%s", type, address.string()); for (size_t i = 0; i < size(); i++) { - //ALOGV(" at i=%d: device=%x, addr=%s", - // i, itemAt(i)->mDeviceType, itemAt(i)->mAddress.string()); if (itemAt(i)->mDeviceType == type) { if (itemAt(i)->mAddress == address) { - //ALOGV(" found matching address %s", address.string()); devices.add(itemAt(i)); } } @@ -7221,14 +8000,27 @@ audio_stream_type_t AudioPolicyManager::streamTypefromAttributesInt(const audio_ if ((attr->flags & AUDIO_FLAG_SCO) == AUDIO_FLAG_SCO) { return AUDIO_STREAM_BLUETOOTH_SCO; } + if ((attr->flags & AUDIO_FLAG_BEACON) == AUDIO_FLAG_BEACON) { + return AUDIO_STREAM_TTS; + } // usage to stream type mapping 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 +8046,36 @@ 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: + case AUDIO_USAGE_VIRTUAL_SOURCE: + break; + default: + return false; + } + return true; +} + }; // namespace android diff --git a/services/audiopolicy/AudioPolicyManager.h b/services/audiopolicy/AudioPolicyManager.h index 0ea7b97..cbdafa6 100644 --- a/services/audiopolicy/AudioPolicyManager.h +++ b/services/audiopolicy/AudioPolicyManager.h @@ -23,6 +23,7 @@ #include <utils/Errors.h> #include <utils/KeyedVector.h> #include <utils/SortedVector.h> +#include <media/AudioPolicy.h> #include "AudioPolicyInterface.h" @@ -87,25 +88,32 @@ 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, + input_type_t *inputType); // indicates to the audio policy manager that the input starts being used. virtual status_t startInput(audio_io_handle_t input, @@ -148,6 +156,8 @@ public: // return whether a stream is playing remotely, override to change the definition of // local/remote playback, used for instance by notification manager to not make // media players lose audio focus when not playing locally + // For the base implementation, "remotely" means playing during screen mirroring which + // uses an output for playback with a non-empty, non "0" address. virtual bool isStreamActiveRemotely(audio_stream_type_t stream, uint32_t inPastMs = 0) const; virtual bool isSourceActive(audio_source_t source) const; @@ -178,6 +188,9 @@ public: virtual status_t releaseSoundTriggerSession(audio_session_t session); + virtual status_t registerPolicyMixes(Vector<AudioMix> mixes); + virtual status_t unregisterPolicyMixes(Vector<AudioMix> mixes); + protected: enum routing_strategy { @@ -187,6 +200,9 @@ protected: STRATEGY_SONIFICATION_RESPECTFUL, STRATEGY_DTMF, STRATEGY_ENFORCED_AUDIBLE, + STRATEGY_TRANSMITTED_THROUGH_SPEAKER, + STRATEGY_ACCESSIBILITY, + STRATEGY_REROUTING, NUM_STRATEGIES }; @@ -248,7 +264,7 @@ protected: audio_gain_mode_t loadGainMode(char *name); void loadGain(cnode *root, int index); - void loadGains(cnode *root); + virtual void loadGains(cnode *root); // searches for an exact match status_t checkExactSamplingRate(uint32_t samplingRate) const; @@ -328,10 +344,14 @@ protected: virtual ~DeviceDescriptor() {} bool equals(const sp<DeviceDescriptor>& other) const; + + // AudioPortConfig + virtual sp<AudioPort> getAudioPort() const { return (AudioPort*) this; } virtual void toAudioPortConfig(struct audio_port_config *dstConfig, const struct audio_port_config *srcConfig = NULL) const; - virtual sp<AudioPort> getAudioPort() const { return (AudioPort*) this; } + // AudioPort + virtual void loadGains(cnode *root); virtual void toAudioPort(struct audio_port *port) const; status_t dump(int fd, int spaces, int index) const; @@ -383,6 +403,7 @@ protected: // For input, flags is interpreted as audio_input_flags_t. // TODO: merge audio_output_flags_t and audio_input_flags_t. bool isCompatibleProfile(audio_devices_t device, + String8 address, uint32_t samplingRate, uint32_t *updatedSamplingRate, audio_format_t format, @@ -406,6 +427,13 @@ protected: status_t loadInput(cnode *root); status_t loadDevice(cnode *root); + status_t addOutputProfile(String8 name, const audio_config_t *config, + audio_devices_t device, String8 address); + status_t removeOutputProfile(String8 name); + status_t addInputProfile(String8 name, const audio_config_t *config, + audio_devices_t device, String8 address); + status_t removeInputProfile(String8 name); + void dump(int fd); const char *const mName; // base name of the audio HW module (primary, a2dp ...) @@ -434,6 +462,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]; @@ -471,6 +502,7 @@ protected: uint32_t mLatency; // audio_output_flags_t mFlags; // audio_devices_t mDevice; // current device this output is routed to + AudioMix *mPolicyMix; // non NULL when used by a dynamic policy audio_patch_handle_t mPatchHandle; uint32_t mRefCount[AUDIO_STREAM_CNT]; // number of streams of each type using this output nsecs_t mStopTime[AUDIO_STREAM_CNT]; @@ -496,6 +528,7 @@ protected: audio_port_handle_t mId; audio_io_handle_t mIoHandle; // input handle audio_devices_t mDevice; // current device this input is routed to + AudioMix *mPolicyMix; // non NULL when used by a dynamic policy audio_patch_handle_t mPatchHandle; uint32_t mRefCount; // number of AudioRecord clients using // this input @@ -565,7 +598,7 @@ protected: // change the route of the specified output. Returns the number of ms we have slept to // allow new routing to take effect in certain cases. - uint32_t setOutputDevice(audio_io_handle_t output, + virtual uint32_t setOutputDevice(audio_io_handle_t output, audio_devices_t device, bool force = false, int delayMs = 0, @@ -600,8 +633,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 +743,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); @@ -717,10 +752,11 @@ protected: audio_format_t format); // samplingRate parameter is an in/out and so may be modified sp<IOProfile> getInputProfile(audio_devices_t device, - uint32_t& samplingRate, - audio_format_t format, - audio_channel_mask_t channelMask, - audio_input_flags_t flags); + String8 address, + uint32_t& samplingRate, + audio_format_t format, + audio_channel_mask_t channelMask, + audio_input_flags_t flags); sp<IOProfile> getProfileForDirectOutput(audio_devices_t device, uint32_t samplingRate, audio_format_t format, @@ -731,9 +767,9 @@ protected: bool isNonOffloadableEffectEnabled(); - status_t addAudioPatch(audio_patch_handle_t handle, + virtual status_t addAudioPatch(audio_patch_handle_t handle, const sp<AudioPatch>& patch); - status_t removeAudioPatch(audio_patch_handle_t handle); + virtual status_t removeAudioPatch(audio_patch_handle_t handle); sp<AudioOutputDescriptor> getOutputFromId(audio_port_handle_t id) const; sp<AudioInputDescriptor> getInputFromId(audio_port_handle_t id) const; @@ -806,6 +842,29 @@ 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 + + // custom mix entry in mPolicyMixes + class AudioPolicyMix : public RefBase { + public: + AudioPolicyMix() {} + + AudioMix mMix; // Audio policy mix descriptor + sp<AudioOutputDescriptor> mOutput; // Corresponding output stream + }; + DefaultKeyedVector<String8, sp<AudioPolicyMix> > mPolicyMixes; // list of registered mixes + + #ifdef AUDIO_POLICY_TEST Mutex mLock; Condition mWaitWorkCV; @@ -820,14 +879,15 @@ protected: uint32_t mTestChannels; uint32_t mTestLatencyMs; #endif //AUDIO_POLICY_TEST - -private: static float volIndexToAmpl(audio_devices_t device, const StreamDescriptor& streamDesc, int indexInUi); + static bool isVirtualInputDevice(audio_devices_t device); + uint32_t nextUniqueId(); + uint32_t nextAudioPortGeneration(); +private: // updates device caching and output for streams that can influence the // routing of notifications void handleNotificationRoutingForStream(audio_stream_type_t stream); - static bool isVirtualInputDevice(audio_devices_t device); static bool deviceDistinguishesOnAddress(audio_devices_t device); // find the outputs on a given output descriptor that have the given address. // to be called on an AudioOutputDescriptor whose supported devices (as defined @@ -835,14 +895,14 @@ private: // see deviceDistinguishesOnAddress(audio_devices_t) for whether the device type is one // where addresses are used to distinguish between one connected device and another. void findIoHandlesByAddress(sp<AudioOutputDescriptor> desc /*in*/, + const audio_devices_t device /*in*/, const String8 address /*in*/, SortedVector<audio_io_handle_t>& outputs /*out*/); - uint32_t nextUniqueId(); - uint32_t nextAudioPortGeneration(); uint32_t curAudioPortGeneration() const { return mAudioPortGeneration; } // 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 +911,27 @@ 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); + + // select input device corresponding to requested audio source and return associated policy + // mix if any. Calls getDeviceForInputSource(). + audio_devices_t getDeviceAndMixForInputSource(audio_source_t inputSource, + AudioMix **policyMix = NULL); + + // Called by setDeviceConnectionState(). + status_t setDeviceConnectionStateInt(audio_devices_t device, + audio_policy_dev_state_t state, + const char *device_address); + sp<DeviceDescriptor> getDeviceDescriptor(const audio_devices_t device, + const char *device_address); + }; }; diff --git a/services/audiopolicy/AudioPolicyService.cpp b/services/audiopolicy/AudioPolicyService.cpp index da2defe..eb9116d 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); @@ -901,8 +908,10 @@ void AudioPolicyService::AudioCommandThread::insertCommand_l(sp<AudioCommand>& c } removedCommands.clear(); - // Disable wait for status if delay is not 0 - if (delayMs != 0) { + // Disable wait for status if delay is not 0. + // Except for create audio patch command because the returned patch handle + // is needed by audio policy manager + if (delayMs != 0 && command->mCommand != CREATE_AUDIO_PATCH) { command->mWaitStatus = false; } diff --git a/services/audiopolicy/AudioPolicyService.h b/services/audiopolicy/AudioPolicyService.h index a09c084..80284a4 100644 --- a/services/audiopolicy/AudioPolicyService.h +++ b/services/audiopolicy/AudioPolicyService.h @@ -30,6 +30,7 @@ #include <media/IAudioPolicyService.h> #include <media/ToneGenerator.h> #include <media/AudioEffect.h> +#include <media/AudioPolicy.h> #ifdef USE_LEGACY_AUDIO_POLICY #include <hardware_legacy/AudioPolicyInterface.h> #endif @@ -74,25 +75,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, @@ -181,10 +188,14 @@ public: virtual audio_mode_t getPhoneState(); + virtual status_t registerPolicyMixes(Vector<AudioMix> mixes, bool registration); + 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 +263,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 +336,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 +512,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; |