diff options
Diffstat (limited to 'services/audiopolicy')
-rw-r--r-- | services/audiopolicy/AudioPolicyEffects.cpp | 77 | ||||
-rw-r--r-- | services/audiopolicy/AudioPolicyInterfaceImpl.cpp | 35 | ||||
-rw-r--r-- | services/audiopolicy/AudioPolicyInterfaceImplLegacy.cpp | 35 | ||||
-rw-r--r-- | services/audiopolicy/AudioPolicyManager.cpp | 217 | ||||
-rw-r--r-- | services/audiopolicy/AudioPolicyManager.h | 31 |
5 files changed, 322 insertions, 73 deletions
diff --git a/services/audiopolicy/AudioPolicyEffects.cpp b/services/audiopolicy/AudioPolicyEffects.cpp index 3c1c042..e7e1b36 100644 --- a/services/audiopolicy/AudioPolicyEffects.cpp +++ b/services/audiopolicy/AudioPolicyEffects.cpp @@ -105,26 +105,28 @@ status_t AudioPolicyEffects::addInputEffects(audio_io_handle_t input, inputDesc->mRefCount++; ALOGV("addInputEffects(): input: %d, refCount: %d", input, inputDesc->mRefCount); - - Vector <EffectDesc *> effects = mInputSources.valueAt(index)->mEffects; - for (size_t i = 0; i < effects.size(); i++) { - EffectDesc *effect = effects[i]; - sp<AudioEffect> fx = new AudioEffect(NULL, &effect->mUuid, -1, 0, 0, audioSession, input); - status_t status = fx->initCheck(); - if (status != NO_ERROR && status != ALREADY_EXISTS) { - ALOGW("addInputEffects(): failed to create Fx %s on source %d", + if (inputDesc->mRefCount == 1) { + Vector <EffectDesc *> effects = mInputSources.valueAt(index)->mEffects; + for (size_t i = 0; i < effects.size(); i++) { + EffectDesc *effect = effects[i]; + sp<AudioEffect> fx = new AudioEffect(NULL, &effect->mUuid, -1, 0, 0, + audioSession, input); + status_t status = fx->initCheck(); + if (status != NO_ERROR && status != ALREADY_EXISTS) { + ALOGW("addInputEffects(): failed to create Fx %s on source %d", + effect->mName, (int32_t)aliasSource); + // fx goes out of scope and strong ref on AudioEffect is released + continue; + } + for (size_t j = 0; j < effect->mParams.size(); j++) { + fx->setParameter(effect->mParams[j]); + } + ALOGV("addInputEffects(): added Fx %s on source: %d", effect->mName, (int32_t)aliasSource); - // fx goes out of scope and strong ref on AudioEffect is released - continue; - } - for (size_t j = 0; j < effect->mParams.size(); j++) { - fx->setParameter(effect->mParams[j]); + inputDesc->mEffects.add(fx); } - ALOGV("addInputEffects(): added Fx %s on source: %d", effect->mName, (int32_t)aliasSource); - inputDesc->mEffects.add(fx); + inputDesc->setProcessorEnabled(true); } - inputDesc->setProcessorEnabled(true); - return status; } @@ -241,26 +243,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 +285,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(); diff --git a/services/audiopolicy/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/AudioPolicyInterfaceImpl.cpp index 6cd0ac8..c06ca72 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_CNT) { + return AUDIO_IO_HANDLE_NONE; + } if (mAudioPolicyManager == NULL) { - return 0; + return AUDIO_IO_HANDLE_NONE; } ALOGV("getOutput()"); Mutex::Autolock _l(mLock); @@ -158,6 +161,9 @@ status_t AudioPolicyService::startOutput(audio_io_handle_t output, audio_stream_type_t stream, int session) { + if (uint32_t(stream) >= AUDIO_STREAM_CNT) { + return BAD_VALUE; + } if (mAudioPolicyManager == NULL) { return NO_INIT; } @@ -182,6 +188,9 @@ status_t AudioPolicyService::stopOutput(audio_io_handle_t output, audio_stream_type_t stream, int session) { + if (uint32_t(stream) >= AUDIO_STREAM_CNT) { + return BAD_VALUE; + } if (mAudioPolicyManager == NULL) { return NO_INIT; } @@ -238,11 +247,13 @@ audio_io_handle_t AudioPolicyService::getInput(audio_source_t inputSource, return 0; } // already checked by client, but double-check in case the client wrapper is bypassed - if (inputSource >= AUDIO_SOURCE_CNT && inputSource != AUDIO_SOURCE_HOTWORD) { + if (inputSource >= AUDIO_SOURCE_CNT && inputSource != AUDIO_SOURCE_HOTWORD && + inputSource != AUDIO_SOURCE_FM_TUNER) { return 0; } - if ((inputSource == AUDIO_SOURCE_HOTWORD) && !captureHotwordAllowed()) { + if (((inputSource == AUDIO_SOURCE_HOTWORD) && !captureHotwordAllowed()) || + ((inputSource == AUDIO_SOURCE_FM_TUNER) && !captureFmTunerAllowed())) { return 0; } audio_io_handle_t input; @@ -366,6 +377,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_CNT) { + return 0; + } if (mAudioPolicyManager == NULL) { return 0; } @@ -376,8 +390,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_CNT) { + return AUDIO_DEVICE_NONE; + } if (mAudioPolicyManager == NULL) { - return (audio_devices_t)0; + return AUDIO_DEVICE_NONE; } return mAudioPolicyManager->getDevicesForStream(stream); } @@ -422,8 +439,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_CNT) { + return false; + } if (mAudioPolicyManager == NULL) { - return 0; + return false; } Mutex::Autolock _l(mLock); return mAudioPolicyManager->isStreamActive(stream, inPastMs); @@ -431,8 +451,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_CNT) { + return false; + } if (mAudioPolicyManager == NULL) { - return 0; + return false; } Mutex::Autolock _l(mLock); return mAudioPolicyManager->isStreamActiveRemotely(stream, inPastMs); diff --git a/services/audiopolicy/AudioPolicyInterfaceImplLegacy.cpp b/services/audiopolicy/AudioPolicyInterfaceImplLegacy.cpp index e1e81e1..09476c1 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_CNT) { + return AUDIO_IO_HANDLE_NONE; + } if (mpAudioPolicy == NULL) { - return 0; + return AUDIO_IO_HANDLE_NONE; } ALOGV("getOutput()"); Mutex::Autolock _l(mLock); @@ -147,6 +150,9 @@ status_t AudioPolicyService::startOutput(audio_io_handle_t output, audio_stream_type_t stream, int session) { + if (uint32_t(stream) >= AUDIO_STREAM_CNT) { + return BAD_VALUE; + } if (mpAudioPolicy == NULL) { return NO_INIT; } @@ -172,6 +178,9 @@ status_t AudioPolicyService::stopOutput(audio_io_handle_t output, audio_stream_type_t stream, int session) { + if (uint32_t(stream) >= AUDIO_STREAM_CNT) { + return BAD_VALUE; + } if (mpAudioPolicy == NULL) { return NO_INIT; } @@ -228,11 +237,13 @@ audio_io_handle_t AudioPolicyService::getInput(audio_source_t inputSource, return 0; } // already checked by client, but double-check in case the client wrapper is bypassed - if (inputSource >= AUDIO_SOURCE_CNT && inputSource != AUDIO_SOURCE_HOTWORD) { + if (inputSource >= AUDIO_SOURCE_CNT && inputSource != AUDIO_SOURCE_HOTWORD && + inputSource != AUDIO_SOURCE_FM_TUNER) { return 0; } - if ((inputSource == AUDIO_SOURCE_HOTWORD) && !captureHotwordAllowed()) { + if (((inputSource == AUDIO_SOURCE_HOTWORD) && !captureHotwordAllowed()) || + ((inputSource == AUDIO_SOURCE_FM_TUNER) && !captureFmTunerAllowed())) { return 0; } @@ -368,6 +379,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_CNT) { + return 0; + } if (mpAudioPolicy == NULL) { return 0; } @@ -378,8 +392,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_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 +441,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_CNT) { + return false; + } if (mpAudioPolicy == NULL) { - return 0; + return false; } Mutex::Autolock _l(mLock); return mpAudioPolicy->is_stream_active(mpAudioPolicy, stream, inPastMs); @@ -433,8 +453,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_CNT) { + return false; + } if (mpAudioPolicy == NULL) { - return 0; + return false; } Mutex::Autolock _l(mLock); return mpAudioPolicy->is_stream_active_remotely(mpAudioPolicy, stream, inPastMs); diff --git a/services/audiopolicy/AudioPolicyManager.cpp b/services/audiopolicy/AudioPolicyManager.cpp index 536987a..584e170 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 @@ -216,6 +216,10 @@ status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device, const char *device_address) { String8 address = (device_address == NULL) ? String8("") : String8(device_address); + // handle legacy remote submix case where the address was not always specified + if (deviceDistinguishesOnAddress(device) && (address.length() == 0)) { + address = String8("0"); + } ALOGV("setDeviceConnectionState() device: %x, state %d, address %s", device, state, address.string()); @@ -419,6 +423,10 @@ audio_policy_dev_state_t AudioPolicyManager::getDeviceConnectionState(audio_devi audio_policy_dev_state_t state = AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE; sp<DeviceDescriptor> devDesc = new DeviceDescriptor(String8(""), device); devDesc->mAddress = (device_address == NULL) ? String8("") : String8(device_address); + // handle legacy remote submix case where the address was not always specified + if (deviceDistinguishesOnAddress(device) && (devDesc->mAddress.length() == 0)) { + devDesc->mAddress = String8("0"); + } ssize_t index; DeviceVector *deviceVector; @@ -707,7 +715,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; } @@ -854,7 +862,7 @@ audio_io_handle_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t 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); @@ -1119,6 +1127,20 @@ status_t AudioPolicyManager::startOutput(audio_io_handle_t output, return BAD_VALUE; } + // cannot start playback of STREAM_TTS if any other output is being used + uint32_t beaconMuteLatency = 0; + if (stream == AUDIO_STREAM_TTS) { + ALOGV("\t found BEACON stream"); + if (isAnyOutputActive(AUDIO_STREAM_TTS /*streamToIgnore*/)) { + return INVALID_OPERATION; + } else { + beaconMuteLatency = handleEventForBeacon(STARTING_BEACON); + } + } else { + // some playback other than beacon starts + beaconMuteLatency = handleEventForBeacon(STARTING_OUTPUT); + } + sp<AudioOutputDescriptor> outputDesc = mOutputs.valueAt(index); // increment usage count for this stream on the requested output: @@ -1130,8 +1152,9 @@ status_t AudioPolicyManager::startOutput(audio_io_handle_t output, audio_devices_t newDevice = getNewOutputDevice(output, false /*fromCache*/); routing_strategy strategy = getStrategy(stream); bool shouldWait = (strategy == STRATEGY_SONIFICATION) || - (strategy == STRATEGY_SONIFICATION_RESPECTFUL); - uint32_t waitMs = 0; + (strategy == STRATEGY_SONIFICATION_RESPECTFUL) || + (beaconMuteLatency > 0); + uint32_t waitMs = beaconMuteLatency; bool force = false; for (size_t i = 0; i < mOutputs.size(); i++) { sp<AudioOutputDescriptor> desc = mOutputs.valueAt(i); @@ -1145,7 +1168,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; @@ -1189,6 +1213,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); @@ -1356,11 +1383,14 @@ audio_io_handle_t AudioPolicyManager::getInput(audio_source_t inputSource, config.channel_mask = channelMask; config.format = format; + // handle legacy remote submix case where the address was not always specified + String8 address = deviceDistinguishesOnAddress(device) ? String8("0") : String8(""); + status_t status = mpClientInterface->openInput(profile->mModule->mHandle, &input, &config, &device, - String8(""), + address, halInputSource, flags); @@ -1584,12 +1614,17 @@ 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*/); + if ((device != AUDIO_DEVICE_OUT_DEFAULT) && (device & strategyDevice) == 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; @@ -2653,7 +2688,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 +2825,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 +2842,7 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa &input, &config, &inputDesc->mDevice, - String8(""), + address, AUDIO_SOURCE_MIC, AUDIO_INPUT_FLAG_NONE); @@ -3816,6 +3862,8 @@ audio_devices_t AudioPolicyManager::getNewOutputDevice(audio_io_handle_t output, // use device for strategy media // 7: the strategy DTMF is active on the output: // use device for strategy DTMF + // 8: 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); @@ -3832,6 +3880,8 @@ audio_devices_t AudioPolicyManager::getNewOutputDevice(audio_io_handle_t output, 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); } ALOGV("getNewOutputDevice() selected device %x", device); @@ -3910,16 +3960,20 @@ AudioPolicyManager::routing_strategy AudioPolicyManager::getStrategy( 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; } } 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; } @@ -3967,6 +4021,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 +4102,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*/); @@ -4158,6 +4288,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 +4382,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 +4483,15 @@ uint32_t AudioPolicyManager::setOutputDevice(audio_io_handle_t output, muteWaitMs = checkDeviceMuteStrategies(outputDesc, prevDevice, delayMs); // Do not change the routing if: - // - the requested device is AUDIO_DEVICE_NONE - // - the requested device is the same as current device and force is not specified. + // the requested device is AUDIO_DEVICE_NONE + // OR the requested device is the same as current device + // AND force is not specified + // AND the output is connected by a valid audio patch. // Doing this check here allows the caller to call setOutputDevice() without conditions - if ((device == AUDIO_DEVICE_NONE || device == prevDevice) && !force) { - ALOGV("setOutputDevice() setting same device %04x or null device for output %d", device, output); + if ((device == AUDIO_DEVICE_NONE || device == prevDevice) && !force && + outputDesc->mPatchHandle != 0) { + ALOGV("setOutputDevice() setting same device %04x or null device for output %d", + device, output); return muteWaitMs; } @@ -4667,6 +4806,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; @@ -4891,6 +5035,16 @@ 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::sVolumeProfiles[AUDIO_STREAM_CNT] [AudioPolicyManager::DEVICE_CATEGORY_CNT] = { { // AUDIO_STREAM_VOICE_CALL @@ -4948,10 +5102,11 @@ const AudioPolicyManager::VolumeCurvePoint sExtMediaSystemVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA }, { // AUDIO_STREAM_TTS - sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_HEADSET - sSpeakerMediaVolumeCurve, // DEVICE_CATEGORY_SPEAKER - sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_EARPIECE - sDefaultMediaVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA + // "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 }, }; @@ -5843,12 +5998,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) @@ -6791,7 +6962,11 @@ void AudioPolicyManager::DeviceVector::loadDevicesFromName(char *name, ARRAY_SIZE(sDeviceNameToEnumTable), devName); if (type != AUDIO_DEVICE_NONE) { - add(new DeviceDescriptor(String8(""), type)); + sp<DeviceDescriptor> dev = new DeviceDescriptor(String8(""), type); + if (type == AUDIO_DEVICE_IN_REMOTE_SUBMIX) { + dev->mAddress = String8("0"); + } + add(dev); } else { sp<DeviceDescriptor> deviceDesc = declaredDevices.getDeviceFromName(String8(devName)); diff --git a/services/audiopolicy/AudioPolicyManager.h b/services/audiopolicy/AudioPolicyManager.h index 0ea7b97..50d7831 100644 --- a/services/audiopolicy/AudioPolicyManager.h +++ b/services/audiopolicy/AudioPolicyManager.h @@ -187,6 +187,7 @@ protected: STRATEGY_SONIFICATION_RESPECTFUL, STRATEGY_DTMF, STRATEGY_ENFORCED_AUDIBLE, + STRATEGY_TRANSMITTED_THROUGH_SPEAKER, NUM_STRATEGIES }; @@ -434,6 +435,8 @@ 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]; // default volume curves per stream and device category. See initializeVolumeCurves() static const VolumeCurvePoint *sVolumeProfiles[AUDIO_STREAM_CNT][DEVICE_CATEGORY_CNT]; @@ -600,8 +603,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); @@ -806,6 +811,18 @@ protected: sp<AudioPatch> mCallTxPatch; sp<AudioPatch> mCallRxPatch; + // for supporting "beacon" streams, i.e. streams that only play on speaker, and never + // when something other than STREAM_TTS (a.k.a. "Transmitted Through Speaker") is playing + enum { + STARTING_OUTPUT, + STARTING_BEACON, + STOPPING_OUTPUT, + STOPPING_BEACON + }; + uint32_t mBeaconMuteRefCount; // ref count for stream that would mute beacon + uint32_t mBeaconPlayingRefCount;// ref count for the playing beacon streams + bool mBeaconMuted; // has STREAM_TTS been muted + #ifdef AUDIO_POLICY_TEST Mutex mLock; Condition mWaitWorkCV; @@ -820,10 +837,9 @@ protected: uint32_t mTestChannels; uint32_t mTestLatencyMs; #endif //AUDIO_POLICY_TEST - -private: static float volIndexToAmpl(audio_devices_t device, const StreamDescriptor& streamDesc, int indexInUi); +private: // updates device caching and output for streams that can influence the // routing of notifications void handleNotificationRoutingForStream(audio_stream_type_t stream); @@ -851,6 +867,13 @@ 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); }; }; |