From aaac0fd20d26e6a3a1c2d4bf0638f6a183ecec4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Gaffie?= Date: Thu, 22 Nov 2018 17:56:39 +0100 Subject: [PATCH] audiopolicy: switch to VolumeGroup for Output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Volume used to be managed per stream type. VolumeGroup is a configurable way to manage volume affinity. This CL allows to switch to VolumeGroup as new volume affinity management. Bug: 124767636 Test: audio smoke tests Change-Id: I71fc214f6db3158f0f05920cc3d700b29db1a4bc Signed-off-by: François Gaffie --- services/audiopolicy/common/include/Volume.h | 9 +- .../include/AudioOutputDescriptor.h | 25 +- .../src/AudioOutputDescriptor.cpp | 49 +- .../engine/common/include/EngineBase.h | 6 +- .../engine/common/include/ProductStrategy.h | 2 + .../engine/common/src/EngineBase.cpp | 17 +- .../engine/common/src/ProductStrategy.cpp | 12 +- .../interface/AudioPolicyManagerInterface.h | 4 - .../parameter-framework/plugin/Android.mk | 4 +- .../managerdefault/AudioPolicyManager.cpp | 496 +++++++++--------- .../managerdefault/AudioPolicyManager.h | 55 +- 11 files changed, 373 insertions(+), 306 deletions(-) diff --git a/services/audiopolicy/common/include/Volume.h b/services/audiopolicy/common/include/Volume.h index 48b5271932..561f100092 100644 --- a/services/audiopolicy/common/include/Volume.h +++ b/services/audiopolicy/common/include/Volume.h @@ -16,19 +16,22 @@ #pragma once +#include #include #include #include namespace android { + /** * VolumeSource is the discriminent for volume management on an output. * It used to be the stream type by legacy, it may be host volume group or a volume curves if - * we allow to have more than one curve per volume group. + * we allow to have more than one curve per volume group (mandatory to get rid of AudioServer + * stream aliases. */ -enum VolumeSource : std::underlying_type::type; -static const VolumeSource VOLUME_SOURCE_NONE = static_cast(AUDIO_STREAM_DEFAULT); +enum VolumeSource : std::underlying_type::type; +static const VolumeSource VOLUME_SOURCE_NONE = static_cast(VOLUME_GROUP_NONE); static inline VolumeSource streamToVolumeSource(audio_stream_type_t stream) { return static_cast(stream); diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h index 704f404d9a..04fc3d086b 100644 --- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h +++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h @@ -107,7 +107,7 @@ private: }; /** * Note: volume activities shall be indexed by CurvesId if we want to allow multiple - * curves per volume group, inferring a mute management or volume balancing between HW and SW is + * curves per volume source, inferring a mute management or volume balancing between HW and SW is * done */ using VolumeActivities = std::map; @@ -157,7 +157,7 @@ public: virtual uint32_t latency() { return 0; } virtual bool isFixedVolume(audio_devices_t device); virtual bool setVolume(float volumeDb, - audio_stream_type_t stream, + VolumeSource volumeSource, const StreamTypeVector &streams, audio_devices_t device, uint32_t delayMs, bool force); @@ -221,7 +221,7 @@ public: } void setCurVolume(VolumeSource vs, float volumeDb) { - // Even if not activity for this group registered, need to create anyway + // Even if not activity for this source registered, need to create anyway mVolumeActivities[vs].setVolume(volumeDb); } float getCurVolume(VolumeSource vs) const @@ -280,6 +280,11 @@ public: return mActiveClients; } + bool useHwGain() const + { + return !devices().isEmpty() ? devices().itemAt(0)->hasGainController() : false; + } + DeviceVector mDevices; /**< current devices this output is routed to */ AudioMix *mPolicyMix = nullptr; // non NULL when used by a dynamic policy @@ -328,7 +333,7 @@ public: } } virtual bool setVolume(float volumeDb, - audio_stream_type_t stream, + VolumeSource volumeSource, const StreamTypeVector &streams, audio_devices_t device, uint32_t delayMs, bool force); @@ -402,7 +407,7 @@ public: void dump(String8 *dst) const override; virtual bool setVolume(float volumeDb, - audio_stream_type_t stream, + VolumeSource volumeSource, const StreamTypeVector &streams, audio_devices_t device, uint32_t delayMs, bool force); @@ -422,7 +427,7 @@ public: bool isActive(VolumeSource volumeSource, uint32_t inPastMs = 0) const; /** - * return whether any source contributing to VolumeSource is playing remotely, override + * return whether any source contributing to VolumeSource 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 @@ -488,8 +493,8 @@ public: /** * @brief isAnyOutputActive checks if any output is active (aka playing) except the one(s) that * hold the volume source to be ignored - * @param volumeSourceToIgnore source not considered in the activity detection - * @return true if any output is active for any source except the one to be ignored + * @param volumeSourceToIgnore source not to be considered in the activity detection + * @return true if any output is active for any volume source except the one to be ignored */ bool isAnyOutputActive(VolumeSource volumeSourceToIgnore) const { @@ -518,8 +523,8 @@ public: /** * @brief isAnyOutputActive checks if any output is active (aka playing) except the one(s) that * hold the volume source to be ignored - * @param volumeSourceToIgnore source not considered in the activity detection - * @return true if any output is active for any source except the one to be ignored + * @param volumeSourceToIgnore source not to be considered in the activity detection + * @return true if any output is active for any volume source except the one to be ignored */ bool isAnyOutputActive(VolumeSource volumeSourceToIgnore) const { diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp index fd33649ff1..4d325593c5 100644 --- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp +++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp @@ -23,6 +23,7 @@ #include "AudioGain.h" #include "Volume.h" #include "HwModule.h" +#include "TypeConverter.h" #include #include @@ -150,17 +151,18 @@ bool AudioOutputDescriptor::isFixedVolume(audio_devices_t device __unused) } bool AudioOutputDescriptor::setVolume(float volumeDb, - audio_stream_type_t stream, - audio_devices_t device __unused, + VolumeSource volumeSource, + const StreamTypeVector &/*streams*/, + audio_devices_t /*device*/, uint32_t delayMs, bool force) { // We actually change the volume if: // - the float value returned by computeVolume() changed // - the force flag is set - if (volumeDb != getCurVolume(static_cast(stream)) || force) { - ALOGV("setVolume() for stream %d, volume %f, delay %d", stream, volumeDb, delayMs); - setCurVolume(static_cast(stream), volumeDb); + if (volumeDb != getCurVolume(volumeSource) || force) { + ALOGV("%s for volumeSrc %d, volume %f, delay %d", __func__, volumeSource, volumeDb, delayMs); + setCurVolume(volumeSource, volumeDb); return true; } return false; @@ -389,23 +391,33 @@ void SwAudioOutputDescriptor::toAudioPort( } bool SwAudioOutputDescriptor::setVolume(float volumeDb, - audio_stream_type_t stream, + VolumeSource vs, const StreamTypeVector &streamTypes, audio_devices_t device, uint32_t delayMs, bool force) { - if (!AudioOutputDescriptor::setVolume(volumeDb, stream, device, delayMs, force)) { + StreamTypeVector streams = streamTypes; + if (!AudioOutputDescriptor::setVolume(volumeDb, vs, streamTypes, device, delayMs, force)) { return false; } + if (streams.empty()) { + streams.push_back(AUDIO_STREAM_MUSIC); + } if (!devices().isEmpty()) { // Assume first device to check upon Gain Crontroller availability + // APM loops on all group, so filter on active group to set the port gain, + // let the other groups set the stream volume as per legacy const auto &devicePort = devices().itemAt(0); - ALOGV("%s: device %s hasGC %d", __FUNCTION__, - devicePort->toString().c_str(), devices().itemAt(0)->hasGainController(true)); - if (devicePort->hasGainController(true)) { + if (devicePort->hasGainController(true) && isActive(vs)) { + ALOGV("%s: device %s has gain controller", __func__, devicePort->toString().c_str()); + // @todo: here we might be in trouble if the SwOutput has several active clients with + // different Volume Source (or if we allow several curves within same volume group) + // // @todo: default stream volume to max (0) when using HW Port gain? float volumeAmpl = Volume::DbToAmpl(0); - mClientInterface->setStreamVolume(stream, volumeAmpl, mIoHandle, delayMs); + for (const auto &stream : streams) { + mClientInterface->setStreamVolume(stream, volumeAmpl, mIoHandle, delayMs); + } AudioGains gains = devicePort->getGains(); int gainMinValueInMb = gains[0]->getMinValueInMb(); @@ -422,11 +434,15 @@ bool SwAudioOutputDescriptor::setVolume(float volumeDb, } } // Force VOICE_CALL to track BLUETOOTH_SCO stream volume when bluetooth audio is enabled - float volumeAmpl = Volume::DbToAmpl(getCurVolume(static_cast(stream))); - if (stream == AUDIO_STREAM_BLUETOOTH_SCO) { + float volumeAmpl = Volume::DbToAmpl(getCurVolume(vs)); + if (hasStream(streams, AUDIO_STREAM_BLUETOOTH_SCO)) { mClientInterface->setStreamVolume(AUDIO_STREAM_VOICE_CALL, volumeAmpl, mIoHandle, delayMs); } - mClientInterface->setStreamVolume(stream, volumeAmpl, mIoHandle, delayMs); + for (const auto &stream : streams) { + ALOGV("%s output %d for volumeSource %d, volume %f, delay %d stream=%s", __func__, + mIoHandle, vs, volumeDb, delayMs, toString(stream).c_str()); + mClientInterface->setStreamVolume(stream, volumeAmpl, mIoHandle, delayMs); + } return true; } @@ -616,12 +632,13 @@ void HwAudioOutputDescriptor::toAudioPort( bool HwAudioOutputDescriptor::setVolume(float volumeDb, - audio_stream_type_t stream, + VolumeSource volumeSource, const StreamTypeVector &streams, audio_devices_t device, uint32_t delayMs, bool force) { - bool changed = AudioOutputDescriptor::setVolume(volumeDb, stream, device, delayMs, force); + bool changed = + AudioOutputDescriptor::setVolume(volumeDb, volumeSource, streams, device, delayMs, force); if (changed) { // TODO: use gain controller on source device if any to adjust volume diff --git a/services/audiopolicy/engine/common/include/EngineBase.h b/services/audiopolicy/engine/common/include/EngineBase.h index 6ff8512408..cedc78f8b5 100644 --- a/services/audiopolicy/engine/common/include/EngineBase.h +++ b/services/audiopolicy/engine/common/include/EngineBase.h @@ -84,10 +84,6 @@ public: volume_group_t getVolumeGroupForStreamType(audio_stream_type_t stream) const override; - StreamTypeVector getStreamTypesForVolumeGroup(volume_group_t volumeGroup) const override; - - AttributesVector getAllAttributesForVolumeGroup(volume_group_t volumeGroup) const override; - status_t listAudioVolumeGroups(AudioVolumeGroupVector &groups) const override; void dump(String8 *dst) const override; @@ -112,7 +108,7 @@ public: VolumeSource toVolumeSource(audio_stream_type_t stream) const { - return static_cast(stream); + return static_cast(getVolumeGroupForStreamType(stream)); } status_t switchVolumeCurve(audio_stream_type_t streamSrc, audio_stream_type_t streamDst); diff --git a/services/audiopolicy/engine/common/include/ProductStrategy.h b/services/audiopolicy/engine/common/include/ProductStrategy.h index 767a8ed583..1a2a198ccd 100644 --- a/services/audiopolicy/engine/common/include/ProductStrategy.h +++ b/services/audiopolicy/engine/common/include/ProductStrategy.h @@ -152,6 +152,8 @@ public: volume_group_t getVolumeGroupForStreamType(audio_stream_type_t stream) const; + volume_group_t getDefaultVolumeGroup() const; + product_strategy_t getDefault() const; void dump(String8 *dst, int spaces = 0) const; diff --git a/services/audiopolicy/engine/common/src/EngineBase.cpp b/services/audiopolicy/engine/common/src/EngineBase.cpp index 4fe7b42414..07a7e65124 100644 --- a/services/audiopolicy/engine/common/src/EngineBase.cpp +++ b/services/audiopolicy/engine/common/src/EngineBase.cpp @@ -218,6 +218,9 @@ VolumeCurves *EngineBase::getVolumeCurvesForAttributes(const audio_attributes_t VolumeCurves *EngineBase::getVolumeCurvesForStreamType(audio_stream_type_t stream) const { volume_group_t volGr = mProductStrategies.getVolumeGroupForStreamType(stream); + if (volGr == VOLUME_GROUP_NONE) { + volGr = mProductStrategies.getDefaultVolumeGroup(); + } const auto &iter = mVolumeGroups.find(volGr); LOG_ALWAYS_FATAL_IF(iter == std::end(mVolumeGroups), "No volume groups for %s", toString(stream).c_str()); @@ -260,20 +263,6 @@ volume_group_t EngineBase::getVolumeGroupForStreamType(audio_stream_type_t strea return mProductStrategies.getVolumeGroupForStreamType(stream); } -StreamTypeVector EngineBase::getStreamTypesForVolumeGroup(volume_group_t volumeGroup) const -{ - // @TODO default music stream to control volume if no group? - return (mVolumeGroups.find(volumeGroup) != end(mVolumeGroups)) ? - mVolumeGroups.at(volumeGroup)->getStreamTypes() : - StreamTypeVector(AUDIO_STREAM_MUSIC); -} - -AttributesVector EngineBase::getAllAttributesForVolumeGroup(volume_group_t volumeGroup) const -{ - return (mVolumeGroups.find(volumeGroup) != end(mVolumeGroups)) ? - mVolumeGroups.at(volumeGroup)->getSupportedAttributes() : AttributesVector(); -} - status_t EngineBase::listAudioVolumeGroups(AudioVolumeGroupVector &groups) const { for (const auto &iter : mVolumeGroups) { diff --git a/services/audiopolicy/engine/common/src/ProductStrategy.cpp b/services/audiopolicy/engine/common/src/ProductStrategy.cpp index 16e6690a58..f74f190d0d 100644 --- a/services/audiopolicy/engine/common/src/ProductStrategy.cpp +++ b/services/audiopolicy/engine/common/src/ProductStrategy.cpp @@ -270,11 +270,7 @@ volume_group_t ProductStrategyMap::getVolumeGroupForAttributes(const audio_attri return group; } } - product_strategy_t defaultStrategy = getDefault(); - if (defaultStrategy == PRODUCT_STRATEGY_NONE) { - return VOLUME_GROUP_NONE; - } - return at(defaultStrategy)->getDefaultVolumeGroup(); + return getDefaultVolumeGroup(); } volume_group_t ProductStrategyMap::getVolumeGroupForStreamType(audio_stream_type_t stream) const @@ -285,6 +281,12 @@ volume_group_t ProductStrategyMap::getVolumeGroupForStreamType(audio_stream_type return group; } } + ALOGW("%s: no volume group for %s, using default", __func__, toString(stream).c_str()); + return getDefaultVolumeGroup(); +} + +volume_group_t ProductStrategyMap::getDefaultVolumeGroup() const +{ product_strategy_t defaultStrategy = getDefault(); if (defaultStrategy == PRODUCT_STRATEGY_NONE) { return VOLUME_GROUP_NONE; diff --git a/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h b/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h index 38f3401c2b..4cf72c8c09 100644 --- a/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h +++ b/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h @@ -283,10 +283,6 @@ public: */ virtual volume_group_t getVolumeGroupForStreamType(audio_stream_type_t stream) const = 0; - virtual StreamTypeVector getStreamTypesForVolumeGroup(volume_group_t volumeGroup) const = 0; - - virtual AttributesVector getAllAttributesForVolumeGroup(volume_group_t volumeGroup) const = 0; - /** * @brief listAudioVolumeGroups introspection API to get the Audio Volume Groups, aka * former stream aliases in Audio Service, defining volume curves attached to one or more diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.mk b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.mk index 65dc9afff0..4706d7d61e 100644 --- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.mk +++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.mk @@ -36,7 +36,9 @@ LOCAL_HEADER_LIBRARIES := \ LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB) -LOCAL_STATIC_LIBRARIES := libpfw_utility +LOCAL_STATIC_LIBRARIES := \ + libpfw_utility \ + libaudiopolicycomponents LOCAL_MODULE_TAGS := optional LOCAL_MODULE := libpolicy-subsystem diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp index ea98253adc..494a68ca4d 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp @@ -1084,7 +1084,7 @@ status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr, new TrackClientDescriptor(*portId, uid, session, resultAttr, clientConfig, sanitizedRequestedPortId, *stream, mEngine->getProductStrategyForAttributes(resultAttr), - streamToVolumeSource(*stream), + toVolumeSource(resultAttr), *flags, isRequestedDeviceForExclusiveUse, std::move(weakSecondaryOutputDescs)); sp outputDesc = mOutputs.valueFor(*output); @@ -1694,8 +1694,9 @@ status_t AudioPolicyManager::startSource(const sp& outp setOutputDevices(outputDesc, devices, force, 0, NULL, requiresMuteCheck); // apply volume rules for current stream and device if necessary - checkAndSetVolume(stream, - getVolumeCurves(stream).getVolumeIndex(outputDesc->devices().types()), + auto &curves = getVolumeCurves(client->attributes()); + checkAndSetVolume(curves, client->volumeSource(), + curves.getVolumeIndex(outputDesc->devices().types()), outputDesc, outputDesc->devices().types()); @@ -2384,107 +2385,27 @@ status_t AudioPolicyManager::setStreamVolumeIndex(audio_stream_type_t stream, int index, audio_devices_t device) { - auto &curves = getVolumeCurves(stream); - // VOICE_CALL and BLUETOOTH_SCO stream have minVolumeIndex > 0 but - // can be muted directly by an app that has MODIFY_PHONE_STATE permission. - if (((index < curves.getVolumeIndexMin()) && - !((stream == AUDIO_STREAM_VOICE_CALL || stream == AUDIO_STREAM_BLUETOOTH_SCO) && - index == 0)) || - (index > curves.getVolumeIndexMax())) { - return BAD_VALUE; - } - if (!audio_is_output_device(device)) { + auto attributes = mEngine->getAttributesForStreamType(stream); + auto volumeGroup = mEngine->getVolumeGroupForStreamType(stream); + if (volumeGroup == VOLUME_GROUP_NONE) { + ALOGE("%s: no group matching with stream %s", __FUNCTION__, toString(stream).c_str()); return BAD_VALUE; } - - // Force max volume if stream cannot be muted - if (!curves.canBeMuted()) index = curves.getVolumeIndexMax(); - - ALOGV("setStreamVolumeIndex() stream %d, device %08x, index %d", - stream, device, index); - - // update other private stream volumes which follow this one - for (int curStream = 0; curStream < AUDIO_STREAM_FOR_POLICY_CNT; curStream++) { - if (!streamsMatchForvolume(stream, (audio_stream_type_t)curStream)) { - continue; - } - auto &curCurves = getVolumeCurves(static_cast(curStream)); - curCurves.addCurrentVolumeIndex(device, index); - } - - // update volume on all outputs and streams matching the following: - // - The requested stream (or a stream matching for volume control) is active on the output - // - The device (or devices) selected by the engine for this stream includes - // the requested device - // - For non default requested device, currently selected device on the output is either the - // requested device or one of the devices selected by the engine for this stream - // - For default requested device (AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME), apply volume only if - // no specific device volume value exists for currently selected device. - status_t status = NO_ERROR; - for (size_t i = 0; i < mOutputs.size(); i++) { - sp desc = mOutputs.valueAt(i); - audio_devices_t curDevice = desc->devices().types(); - for (int curStream = 0; curStream < AUDIO_STREAM_FOR_POLICY_CNT; curStream++) { - if (!(streamsMatchForvolume(stream, (audio_stream_type_t)curStream))) { - continue; - } - if (!(desc->isActive(streamToVolumeSource((audio_stream_type_t)curStream)) || isInCall())) { - continue; - } - audio_devices_t curStreamDevice = Volume::getDeviceForVolume( - mEngine->getOutputDevicesForStream((audio_stream_type_t)curStream, - false /*fromCache*/).types()); - if ((device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) && - ((curStreamDevice & device) == 0)) { - continue; - } - bool applyVolume; - if (device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) { - curStreamDevice |= device; - applyVolume = (Volume::getDeviceForVolume(curDevice) & curStreamDevice) != 0; - } else { - applyVolume = !curves.hasVolumeIndexForDevice(curStreamDevice); - } - // rescale index before applying to curStream as ranges may be different for - // stream and curStream - int idx = rescaleVolumeIndex(index, stream, (audio_stream_type_t)curStream); - if (applyVolume) { - //FIXME: workaround for truncated touch sounds - // delayed volume change for system stream to be removed when the problem is - // handled by system UI - status_t volStatus = checkAndSetVolume( - (audio_stream_type_t)curStream, idx, desc, curDevice, - (stream == AUDIO_STREAM_SYSTEM) ? - TOUCH_SOUND_FIXED_DELAY_MS : 0); - if (volStatus != NO_ERROR) { - status = volStatus; - } - } - } - } - return status; + ALOGV("%s: stream %s attributes=%s", __func__, + toString(stream).c_str(), toString(attributes).c_str()); + return setVolumeGroupIndex(getVolumeCurves(stream), volumeGroup, index, device, attributes); } status_t AudioPolicyManager::getStreamVolumeIndex(audio_stream_type_t stream, - int *index, - audio_devices_t device) + int *index, + audio_devices_t device) { - if (index == NULL) { - return BAD_VALUE; - } - if (!audio_is_output_device(device)) { - return BAD_VALUE; - } // if device is AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME, return volume for device selected for this // stream by the engine. if (device == AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) { device = mEngine->getOutputDevicesForStream(stream, true /*fromCache*/).types(); } - device = Volume::getDeviceForVolume(device); - - *index = getVolumeCurves(stream).getVolumeIndex(device); - ALOGV("getStreamVolumeIndex() stream %d device %08x index %d", stream, device, *index); - return NO_ERROR; + return getVolumeIndex(getVolumeCurves(stream), *index, device); } status_t AudioPolicyManager::setVolumeIndexForAttributes(const audio_attributes_t &attr, @@ -2497,18 +2418,25 @@ status_t AudioPolicyManager::setVolumeIndexForAttributes(const audio_attributes_ ALOGD("%s: could not find group matching with %s", __FUNCTION__, toString(attr).c_str()); return BAD_VALUE; } - ALOGD("%s: FOUND group %d matching with %s", __FUNCTION__, volumeGroup, toString(attr).c_str()); + ALOGV("%s: group %d matching with %s", __FUNCTION__, volumeGroup, toString(attr).c_str()); return setVolumeGroupIndex(getVolumeCurves(attr), volumeGroup, index, device, attr); } status_t AudioPolicyManager::setVolumeGroupIndex(IVolumeCurves &curves, volume_group_t group, int index, audio_devices_t device, - const audio_attributes_t /*attributes*/) + const audio_attributes_t attributes) { ALOGVV("%s: group=%d", __func__, group); status_t status = NO_ERROR; - setVolumeCurveIndex(group, index, device, curves); + VolumeSource vs = toVolumeSource(group); + product_strategy_t strategy = mEngine->getProductStrategyForAttributes(attributes); + + status = setVolumeCurveIndex(index, device, curves); + if (status != NO_ERROR) { + ALOGE("%s failed to set curve index for group %d device 0x%X", __func__, group, device); + return status; + } // update volume on all outputs and streams matching the following: // - The requested stream (or a stream matching for volume control) is active on the output // - The device (or devices) selected by the engine for this stream includes @@ -2517,21 +2445,116 @@ status_t AudioPolicyManager::setVolumeGroupIndex(IVolumeCurves &curves, volume_g // requested device or one of the devices selected by the engine for this stream // - For default requested device (AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME), apply volume only if // no specific device volume value exists for currently selected device. - // @TODO + for (size_t i = 0; i < mOutputs.size(); i++) { + sp desc = mOutputs.valueAt(i); + audio_devices_t curDevice = Volume::getDeviceForVolume(desc->devices().types()); + + // Inter / intra volume group priority management: Loop on strategies arranged by priority + // If a higher priority strategy is active, and the output is routed to a device with a + // HW Gain management, do not change the volume + bool applyVolume = false; + if (desc->useHwGain()) { + if (!(desc->isActive(group) || isInCall())) { + continue; + } + for (const auto &productStrategy : mEngine->getOrderedProductStrategies()) { + auto activeClients = desc->clientsList(true /*activeOnly*/, productStrategy, + false /*preferredDevice*/); + if (activeClients.empty()) { + continue; + } + bool isPreempted = false; + bool isHigherPriority = productStrategy < strategy; + for (const auto &client : activeClients) { + if (isHigherPriority && (client->volumeSource() != vs)) { + ALOGV("%s: Strategy=%d (\nrequester:\n" + " group %d, volumeGroup=%d attributes=%s)\n" + " higher priority source active:\n" + " volumeGroup=%d attributes=%s) \n" + " on output %zu, bailing out", __func__, productStrategy, + group, group, toString(attributes).c_str(), + client->volumeSource(), toString(client->attributes()).c_str(), i); + applyVolume = false; + isPreempted = true; + break; + } + // However, continue for loop to ensure no higher prio clients running on output + if (client->volumeSource() == vs) { + applyVolume = true; + } + } + if (isPreempted || applyVolume) { + break; + } + } + if (!applyVolume) { + continue; // next output + } + status_t volStatus = checkAndSetVolume(curves, vs, index, desc, curDevice, + (vs == toVolumeSource(AUDIO_STREAM_SYSTEM)? + TOUCH_SOUND_FIXED_DELAY_MS : 0)); + if (volStatus != NO_ERROR) { + status = volStatus; + } + continue; + } + for (auto curVolGroup : getVolumeGroups()) { + VolumeSource curVolSrc = toVolumeSource(curVolGroup); + if (!(curVolSrc == vs || isInCall())) { + continue; + } + if (!(desc->isActive(vs) || isInCall())) { + continue; + } + audio_devices_t curSrcDevice; + auto &curCurves = getVolumeCurves(curVolSrc); + auto curCurvAttrs = curCurves.getAttributes(); + if (!curCurvAttrs.empty() && curCurvAttrs.front() != defaultAttr) { + auto attr = curCurvAttrs.front(); + curSrcDevice = mEngine->getOutputDevicesForAttributes(attr, nullptr, false).types(); + } else if (!curCurves.getStreamTypes().empty()) { + auto stream = curCurves.getStreamTypes().front(); + curSrcDevice = mEngine->getOutputDevicesForStream(stream, false).types(); + } else { + ALOGE("%s: Invalid src %d: no valid attributes nor stream",__func__, curVolSrc); + continue; + } + curSrcDevice = Volume::getDeviceForVolume(curSrcDevice); + if ((device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) && ((curDevice & device) == 0)) { + continue; + } + if (device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) { + curSrcDevice |= device; + applyVolume = (curDevice & curSrcDevice) != 0; + } else { + applyVolume = !curves.hasVolumeIndexForDevice(curSrcDevice); + } + if (applyVolume) { + //FIXME: workaround for truncated touch sounds + // delayed volume change for system stream to be removed when the problem is + // handled by system UI + status_t volStatus = checkAndSetVolume( + curCurves, curVolSrc, index, desc, curDevice, + ((vs == toVolumeSource(AUDIO_STREAM_SYSTEM))? + TOUCH_SOUND_FIXED_DELAY_MS : 0)); + if (volStatus != NO_ERROR) { + status = volStatus; + } + } + } + } mpClientInterface->onAudioVolumeGroupChanged(group, 0 /*flags*/); return status; } -status_t AudioPolicyManager::setVolumeCurveIndex(volume_group_t volumeGroup, - int index, +status_t AudioPolicyManager::setVolumeCurveIndex(int index, audio_devices_t device, IVolumeCurves &volumeCurves) { // VOICE_CALL stream has minVolumeIndex > 0 but can be muted directly by an // app that has MODIFY_PHONE_STATE permission. - // If voice is member of the volume group, it will contaminate all the member of this group - auto streams = mEngine->getStreamTypesForVolumeGroup(volumeGroup); - if (((index < volumeCurves.getVolumeIndexMin()) && !(hasVoiceStream(streams) && index == 0)) || + bool hasVoice = hasVoiceStream(volumeCurves.getStreamTypes()); + if (((index < volumeCurves.getVolumeIndexMin()) && !(hasVoice && index == 0)) || (index > volumeCurves.getVolumeIndexMax())) { ALOGD("%s: wrong index %d min=%d max=%d", __FUNCTION__, index, volumeCurves.getVolumeIndexMin(), volumeCurves.getVolumeIndexMax()); @@ -2544,7 +2567,7 @@ status_t AudioPolicyManager::setVolumeCurveIndex(volume_group_t volumeGroup, // Force max volume if stream cannot be muted if (!volumeCurves.canBeMuted()) index = volumeCurves.getVolumeIndexMax(); - ALOGD("%s device %08x, index %d", __FUNCTION__ , device, index); + ALOGV("%s device %08x, index %d", __FUNCTION__ , device, index); volumeCurves.addCurrentVolumeIndex(device, index); return NO_ERROR; } @@ -2706,19 +2729,12 @@ status_t AudioPolicyManager::setEffectEnabled(int id, bool enabled) bool AudioPolicyManager::isStreamActive(audio_stream_type_t stream, uint32_t inPastMs) const { - bool active = false; - for (int curStream = 0; curStream < AUDIO_STREAM_FOR_POLICY_CNT && !active; curStream++) { - if (!streamsMatchForvolume(stream, (audio_stream_type_t)curStream)) { - continue; - } - active = mOutputs.isActive(streamToVolumeSource((audio_stream_type_t)curStream), inPastMs); - } - return active; + return mOutputs.isActive(toVolumeSource(stream), inPastMs); } bool AudioPolicyManager::isStreamActiveRemotely(audio_stream_type_t stream, uint32_t inPastMs) const { - return mOutputs.isActiveRemotely(streamToVolumeSource((audio_stream_type_t)stream), inPastMs); + return mOutputs.isActiveRemotely(toVolumeSource(stream), inPastMs); } bool AudioPolicyManager::isSourceActive(audio_source_t source) const @@ -3747,11 +3763,11 @@ status_t AudioPolicyManager::startAudioSource(const struct audio_port_config *so struct audio_patch dummyPatch = {}; sp patchDesc = new AudioPatch(&dummyPatch, uid); - sp sourceDesc = new SourceClientDescriptor( - *portId, uid, *attributes, patchDesc, srcDevice, - mEngine->getStreamTypeForAttributes(*attributes), - mEngine->getProductStrategyForAttributes(*attributes), - streamToVolumeSource(mEngine->getStreamTypeForAttributes(*attributes))); + sp sourceDesc = + new SourceClientDescriptor(*portId, uid, *attributes, patchDesc, srcDevice, + mEngine->getStreamTypeForAttributes(*attributes), + mEngine->getProductStrategyForAttributes(*attributes), + toVolumeSource(*attributes)); status_t status = connectAudioSource(sourceDesc); if (status == NO_ERROR) { @@ -3916,7 +3932,7 @@ status_t AudioPolicyManager::getMasterMono(bool *mono) float AudioPolicyManager::getStreamVolumeDB( audio_stream_type_t stream, int index, audio_devices_t device) { - return computeVolume(stream, index, device); + return computeVolume(getVolumeCurves(stream), toVolumeSource(stream), index, device); } status_t AudioPolicyManager::getSurroundFormats(unsigned int *numSurroundFormats, @@ -5292,11 +5308,10 @@ uint32_t AudioPolicyManager::setBeaconMute(bool mute) { // mute/unmute AUDIO_STREAM_TTS on all outputs ALOGV("\t muting %d", mute); uint32_t maxLatency = 0; + auto ttsVolumeSource = toVolumeSource(AUDIO_STREAM_TTS); for (size_t i = 0; i < mOutputs.size(); i++) { sp desc = mOutputs.valueAt(i); - setStreamMute(AUDIO_STREAM_TTS, mute/*on*/, - desc, - 0 /*delay*/, AUDIO_DEVICE_NONE); + setVolumeSourceMute(ttsVolumeSource, mute/*on*/, desc, 0 /*delay*/, AUDIO_DEVICE_NONE); const uint32_t latency = desc->latency() * 2; if (latency > maxLatency) { maxLatency = latency; @@ -5380,15 +5395,12 @@ uint32_t AudioPolicyManager::checkDeviceMuteStrategies(const spisStrategyActive(productStrategy)) { - // make sure that we do not start the temporary mute period too early in case of - // delayed device change - setStrategyMute(productStrategy, true, outputDesc, delayMs); - setStrategyMute(productStrategy, false, outputDesc, delayMs + tempMuteDurationMs, + for (const auto &activeVs : outputDesc->getActiveVolumeSources()) { + // make sure that we do not start the temporary mute period too early in case of + // delayed device change + setVolumeSourceMute(activeVs, true, outputDesc, delayMs); + setVolumeSourceMute(activeVs, false, outputDesc, delayMs + tempMuteDurationMs, devices.types()); - } } } @@ -5612,51 +5624,51 @@ sp AudioPolicyManager::getInputProfile(const sp &de return NULL; } -float AudioPolicyManager::computeVolume(audio_stream_type_t stream, +float AudioPolicyManager::computeVolume(IVolumeCurves &curves, + VolumeSource volumeSource, int index, audio_devices_t device) { - auto &curves = getVolumeCurves(stream); float volumeDb = curves.volIndexToDb(Volume::getDeviceCategory(device), index); // handle the case of accessibility active while a ringtone is playing: if the ringtone is much // louder than the accessibility prompt, the prompt cannot be heard, thus masking the touch // exploration of the dialer UI. In this situation, bring the accessibility volume closer to // the ringtone volume - if ((stream == AUDIO_STREAM_ACCESSIBILITY) - && (AUDIO_MODE_RINGTONE == mEngine->getPhoneState()) - && isStreamActive(AUDIO_STREAM_RING, 0)) { - const float ringVolumeDB = computeVolume(AUDIO_STREAM_RING, index, device); - return ringVolumeDB - 4 > volumeDb ? ringVolumeDB - 4 : volumeDb; + const auto callVolumeSrc = toVolumeSource(AUDIO_STREAM_VOICE_CALL); + const auto ringVolumeSrc = toVolumeSource(AUDIO_STREAM_RING); + const auto musicVolumeSrc = toVolumeSource(AUDIO_STREAM_MUSIC); + const auto alarmVolumeSrc = toVolumeSource(AUDIO_STREAM_ALARM); + + if (volumeSource == toVolumeSource(AUDIO_STREAM_ACCESSIBILITY) + && (AUDIO_MODE_RINGTONE == mEngine->getPhoneState()) && + mOutputs.isActive(ringVolumeSrc, 0)) { + auto &ringCurves = getVolumeCurves(AUDIO_STREAM_RING); + const float ringVolumeDb = computeVolume(ringCurves, ringVolumeSrc, index, device); + return ringVolumeDb - 4 > volumeDb ? ringVolumeDb - 4 : volumeDb; } // in-call: always cap volume by voice volume + some low headroom - if ((stream != AUDIO_STREAM_VOICE_CALL) && - (isInCall() || mOutputs.isActiveLocally(streamToVolumeSource(AUDIO_STREAM_VOICE_CALL)))) { - switch (stream) { - case AUDIO_STREAM_SYSTEM: - case AUDIO_STREAM_RING: - case AUDIO_STREAM_MUSIC: - case AUDIO_STREAM_ALARM: - case AUDIO_STREAM_NOTIFICATION: - case AUDIO_STREAM_ENFORCED_AUDIBLE: - case AUDIO_STREAM_DTMF: - case AUDIO_STREAM_ACCESSIBILITY: { - int voiceVolumeIndex = getVolumeCurves(AUDIO_STREAM_VOICE_CALL).getVolumeIndex(device); - const float maxVoiceVolDb = - computeVolume(AUDIO_STREAM_VOICE_CALL, voiceVolumeIndex, device) + if ((volumeSource != callVolumeSrc && (isInCall() || + mOutputs.isActiveLocally(callVolumeSrc))) && + (volumeSource == toVolumeSource(AUDIO_STREAM_SYSTEM) || + volumeSource == ringVolumeSrc || volumeSource == musicVolumeSrc || + volumeSource == alarmVolumeSrc || + volumeSource == toVolumeSource(AUDIO_STREAM_NOTIFICATION) || + volumeSource == toVolumeSource(AUDIO_STREAM_ENFORCED_AUDIBLE) || + volumeSource == toVolumeSource(AUDIO_STREAM_DTMF) || + volumeSource == toVolumeSource(AUDIO_STREAM_ACCESSIBILITY))) { + auto &voiceCurves = getVolumeCurves(callVolumeSrc); + int voiceVolumeIndex = voiceCurves.getVolumeIndex(device); + const float maxVoiceVolDb = + computeVolume(voiceCurves, callVolumeSrc, voiceVolumeIndex, device) + IN_CALL_EARPIECE_HEADROOM_DB; - if (volumeDb > maxVoiceVolDb) { - ALOGV("computeVolume() stream %d at vol=%f overriden by stream %d at vol=%f", - stream, volumeDb, AUDIO_STREAM_VOICE_CALL, maxVoiceVolDb); - volumeDb = maxVoiceVolDb; - } - } break; - default: - break; + if (volumeDb > maxVoiceVolDb) { + ALOGV("%s volume source %d at vol=%f overriden by volume group %d at vol=%f", __func__, + volumeSource, volumeDb, callVolumeSrc, maxVoiceVolDb); + volumeDb = maxVoiceVolDb; } } - // if a headset is connected, apply the following rules to ring tones and notifications // to avoid sound level bursts in user's ears: // - always attenuate notifications volume by 6dB @@ -5664,19 +5676,17 @@ float AudioPolicyManager::computeVolume(audio_stream_type_t stream, // speaker is part of the select devices // - if music is playing, always limit the volume to current music volume, // with a minimum threshold at -36dB so that notification is always perceived. - if ((device & (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP | - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES | - AUDIO_DEVICE_OUT_WIRED_HEADSET | - AUDIO_DEVICE_OUT_WIRED_HEADPHONE | - AUDIO_DEVICE_OUT_USB_HEADSET | - AUDIO_DEVICE_OUT_HEARING_AID)) && - ((stream == AUDIO_STREAM_ALARM || stream == AUDIO_STREAM_RING) - || (stream == AUDIO_STREAM_NOTIFICATION) - || (stream == AUDIO_STREAM_SYSTEM) - || ((stream == AUDIO_STREAM_ENFORCED_AUDIBLE) && - (mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == - AUDIO_POLICY_FORCE_NONE))) && - getVolumeCurves(stream).canBeMuted()) { + if ((device & (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP | AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES | + AUDIO_DEVICE_OUT_WIRED_HEADSET | AUDIO_DEVICE_OUT_WIRED_HEADPHONE | + AUDIO_DEVICE_OUT_USB_HEADSET | AUDIO_DEVICE_OUT_HEARING_AID)) && + ((volumeSource == alarmVolumeSrc || + volumeSource == ringVolumeSrc) || + (volumeSource == toVolumeSource(AUDIO_STREAM_NOTIFICATION)) || + (volumeSource == toVolumeSource(AUDIO_STREAM_SYSTEM)) || + ((volumeSource == toVolumeSource(AUDIO_STREAM_ENFORCED_AUDIBLE)) && + (mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_NONE))) && + curves.canBeMuted()) { + // when the phone is ringing we must consider that music could have been paused just before // by the music application and behave as if music was active if the last music track was // just stopped @@ -5686,29 +5696,29 @@ float AudioPolicyManager::computeVolume(audio_stream_type_t stream, audio_devices_t musicDevice = mEngine->getOutputDevicesForAttributes(attributes_initializer(AUDIO_USAGE_MEDIA), nullptr, true /*fromCache*/).types(); - float musicVolDB = computeVolume(AUDIO_STREAM_MUSIC, - getVolumeCurves(AUDIO_STREAM_MUSIC).getVolumeIndex(musicDevice), - musicDevice); - float minVolDB = (musicVolDB > SONIFICATION_HEADSET_VOLUME_MIN_DB) ? - musicVolDB : SONIFICATION_HEADSET_VOLUME_MIN_DB; - if (volumeDb > minVolDB) { - volumeDb = minVolDB; - ALOGV("computeVolume limiting volume to %f musicVol %f", minVolDB, musicVolDB); + auto &musicCurves = getVolumeCurves(AUDIO_STREAM_MUSIC); + float musicVolDb = computeVolume(musicCurves, musicVolumeSrc, + musicCurves.getVolumeIndex(musicDevice), musicDevice); + float minVolDb = (musicVolDb > SONIFICATION_HEADSET_VOLUME_MIN_DB) ? + musicVolDb : SONIFICATION_HEADSET_VOLUME_MIN_DB; + if (volumeDb > minVolDb) { + volumeDb = minVolDb; + ALOGV("computeVolume limiting volume to %f musicVol %f", minVolDb, musicVolDb); } if (device & (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP | - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES)) { + AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES)) { // on A2DP, also ensure notification volume is not too low compared to media when // intended to be played if ((volumeDb > -96.0f) && - (musicVolDB - SONIFICATION_A2DP_MAX_MEDIA_DIFF_DB > volumeDb)) { - ALOGV("computeVolume increasing volume for stream=%d device=0x%X from %f to %f", - stream, device, - volumeDb, musicVolDB - SONIFICATION_A2DP_MAX_MEDIA_DIFF_DB); - volumeDb = musicVolDB - SONIFICATION_A2DP_MAX_MEDIA_DIFF_DB; + (musicVolDb - SONIFICATION_A2DP_MAX_MEDIA_DIFF_DB > volumeDb)) { + ALOGV("%s increasing volume for volume source=%d device=0x%X from %f to %f", + __func__, volumeSource, device, volumeDb, + musicVolDb - SONIFICATION_A2DP_MAX_MEDIA_DIFF_DB); + volumeDb = musicVolDb - SONIFICATION_A2DP_MAX_MEDIA_DIFF_DB; } } } else if ((Volume::getDeviceForVolume(device) != AUDIO_DEVICE_OUT_SPEAKER) || - (stream != AUDIO_STREAM_ALARM && stream != AUDIO_STREAM_RING)) { + (!(volumeSource == alarmVolumeSrc || volumeSource == ringVolumeSrc))) { volumeDb += SONIFICATION_HEADSET_VOLUME_FACTOR_DB; } } @@ -5742,58 +5752,61 @@ int AudioPolicyManager::rescaleVolumeIndex(int srcIndex, return (int)(minDst + ((srcIndex - minSrc) * (maxDst - minDst)) / (maxSrc - minSrc)); } -status_t AudioPolicyManager::checkAndSetVolume(audio_stream_type_t stream, +status_t AudioPolicyManager::checkAndSetVolume(IVolumeCurves &curves, + VolumeSource volumeSource, int index, const sp& outputDesc, audio_devices_t device, int delayMs, bool force) { - // do not change actual stream volume if the stream is muted - if (outputDesc->isMuted(streamToVolumeSource(stream))) { - ALOGVV("%s() stream %d muted count %d", __func__, stream, outputDesc->getMuteCount(stream)); + // do not change actual attributes volume if the attributes is muted + if (outputDesc->isMuted(volumeSource)) { + ALOGVV("%s: volume source %d muted count %d active=%d", __func__, volumeSource, + outputDesc->getMuteCount(volumeSource), outputDesc->isActive(volumeSource)); return NO_ERROR; } + VolumeSource callVolSrc = toVolumeSource(AUDIO_STREAM_VOICE_CALL); + VolumeSource btScoVolSrc = toVolumeSource(AUDIO_STREAM_BLUETOOTH_SCO); + bool isVoiceVolSrc = callVolSrc == volumeSource; + bool isBtScoVolSrc = btScoVolSrc == volumeSource; + audio_policy_forced_cfg_t forceUseForComm = mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION); // do not change in call volume if bluetooth is connected and vice versa - if ((stream == AUDIO_STREAM_VOICE_CALL && forceUseForComm == AUDIO_POLICY_FORCE_BT_SCO) || - (stream == AUDIO_STREAM_BLUETOOTH_SCO && forceUseForComm != AUDIO_POLICY_FORCE_BT_SCO)) { - ALOGV("checkAndSetVolume() cannot set stream %d volume with force use = %d for comm", - stream, forceUseForComm); + // if sco and call follow same curves, bypass forceUseForComm + if ((callVolSrc != btScoVolSrc) && + ((isVoiceVolSrc && forceUseForComm == AUDIO_POLICY_FORCE_BT_SCO) || + (isBtScoVolSrc && forceUseForComm != AUDIO_POLICY_FORCE_BT_SCO))) { + ALOGV("%s cannot set volume group %d volume with force use = %d for comm", __func__, + volumeSource, forceUseForComm); return INVALID_OPERATION; } - if (device == AUDIO_DEVICE_NONE) { device = outputDesc->devices().types(); } - float volumeDb = computeVolume(stream, index, device); + float volumeDb = computeVolume(curves, volumeSource, index, device); if (outputDesc->isFixedVolume(device) || // Force VoIP volume to max for bluetooth SCO - ((stream == AUDIO_STREAM_VOICE_CALL || stream == AUDIO_STREAM_BLUETOOTH_SCO) && - (device & AUDIO_DEVICE_OUT_ALL_SCO) != 0)) { + ((isVoiceVolSrc || isBtScoVolSrc) && (device & AUDIO_DEVICE_OUT_ALL_SCO) != 0)) { volumeDb = 0.0f; } + outputDesc->setVolume(volumeDb, volumeSource, curves.getStreamTypes(), device, delayMs, force); - outputDesc->setVolume(volumeDb, stream, device, delayMs, force); - - if (stream == AUDIO_STREAM_VOICE_CALL || - stream == AUDIO_STREAM_BLUETOOTH_SCO) { + if (isVoiceVolSrc || isBtScoVolSrc) { float voiceVolume; // Force voice volume to max for bluetooth SCO as volume is managed by the headset - if (stream == AUDIO_STREAM_VOICE_CALL) { - voiceVolume = (float)index/(float)getVolumeCurves(stream).getVolumeIndexMax(); + if (isVoiceVolSrc) { + voiceVolume = (float)index/(float)curves.getVolumeIndexMax(); } else { voiceVolume = 1.0; } - if (voiceVolume != mLastVoiceVolume) { mpClientInterface->setVoiceVolume(voiceVolume, delayMs); mLastVoiceVolume = voiceVolume; } } - return NO_ERROR; } @@ -5803,14 +5816,10 @@ void AudioPolicyManager::applyStreamVolumes(const sp& out bool force) { ALOGVV("applyStreamVolumes() for device %08x", device); - - for (int stream = 0; stream < AUDIO_STREAM_FOR_POLICY_CNT; stream++) { - checkAndSetVolume((audio_stream_type_t)stream, - getVolumeCurves((audio_stream_type_t)stream).getVolumeIndex(device), - outputDesc, - device, - delayMs, - force); + for (const auto &volumeGroup : mEngine->getVolumeGroups()) { + auto &curves = getVolumeCurves(toVolumeSource(volumeGroup)); + checkAndSetVolume(curves, toVolumeSource(volumeGroup), + curves.getVolumeIndex(device), outputDesc, device, delayMs, force); } } @@ -5820,43 +5829,54 @@ void AudioPolicyManager::setStrategyMute(product_strategy_t strategy, int delayMs, audio_devices_t device) { - for (auto stream: mEngine->getStreamTypesForProductStrategy(strategy)) { - ALOGVV("%s() stream %d, mute %d, output ID %d", __FUNCTION__, stream, on, - outputDesc->getId()); - setStreamMute(stream, on, outputDesc, delayMs, device); + std::vector sourcesToMute; + for (auto attributes: mEngine->getAllAttributesForProductStrategy(strategy)) { + ALOGVV("%s() attributes %s, mute %d, output ID %d", __func__, + toString(attributes).c_str(), on, outputDesc->getId()); + VolumeSource source = toVolumeSource(attributes); + if (std::find(begin(sourcesToMute), end(sourcesToMute), source) == end(sourcesToMute)) { + sourcesToMute.push_back(source); + } } + for (auto source : sourcesToMute) { + setVolumeSourceMute(source, on, outputDesc, delayMs, device); + } + } -void AudioPolicyManager::setStreamMute(audio_stream_type_t stream, - bool on, - const sp& outputDesc, - int delayMs, - audio_devices_t device) +void AudioPolicyManager::setVolumeSourceMute(VolumeSource volumeSource, + bool on, + const sp& outputDesc, + int delayMs, + audio_devices_t device, + bool activeOnly) { + if (activeOnly && !outputDesc->isActive(volumeSource)) { + return; + } if (device == AUDIO_DEVICE_NONE) { device = outputDesc->devices().types(); } - - ALOGVV("setStreamMute() stream %d, mute %d, mMuteCount %d device %04x", - stream, on, outputDesc->getMuteCount(stream), device); - auto &curves = getVolumeCurves(stream); + auto &curves = getVolumeCurves(volumeSource); if (on) { - if (!outputDesc->isMuted(streamToVolumeSource(stream))) { + if (!outputDesc->isMuted(volumeSource)) { if (curves.canBeMuted() && - ((stream != AUDIO_STREAM_ENFORCED_AUDIBLE) || - (mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_NONE))) { - checkAndSetVolume(stream, 0, outputDesc, device, delayMs); + (volumeSource != toVolumeSource(AUDIO_STREAM_ENFORCED_AUDIBLE) || + (mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == + AUDIO_POLICY_FORCE_NONE))) { + checkAndSetVolume(curves, volumeSource, 0, outputDesc, device, delayMs); } } - // increment mMuteCount after calling checkAndSetVolume() so that volume change is not ignored - outputDesc->incMuteCount(streamToVolumeSource(stream)); + // increment mMuteCount after calling checkAndSetVolume() so that volume change is not + // ignored + outputDesc->incMuteCount(volumeSource); } else { - if (!outputDesc->isMuted(streamToVolumeSource(stream))) { - ALOGV("setStreamMute() unmuting non muted stream!"); + if (!outputDesc->isMuted(volumeSource)) { + ALOGV("%s unmuting non muted attributes!", __func__); return; } - if (outputDesc->decMuteCount(streamToVolumeSource(stream)) == 0) { - checkAndSetVolume(stream, + if (outputDesc->decMuteCount(volumeSource) == 0) { + checkAndSetVolume(curves, volumeSource, curves.getVolumeIndex(device), outputDesc, device, diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h index 3a31e1e314..2b65f45c02 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.h +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h @@ -174,8 +174,7 @@ public: status_t setVolumeGroupIndex(IVolumeCurves &volumeCurves, volume_group_t group, int index, audio_devices_t device, const audio_attributes_t attributes); - status_t setVolumeCurveIndex(volume_group_t volumeGroup, - int index, + status_t setVolumeCurveIndex(int index, audio_devices_t device, IVolumeCurves &volumeCurves); @@ -358,6 +357,30 @@ protected: return mDefaultOutputDevice; } + std::vector getVolumeGroups() const + { + return mEngine->getVolumeGroups(); + } + + VolumeSource toVolumeSource(volume_group_t volumeGroup) const + { + return static_cast(volumeGroup); + } + VolumeSource toVolumeSource(const audio_attributes_t &attributes) const + { + return toVolumeSource(mEngine->getVolumeGroupForAttributes(attributes)); + } + VolumeSource toVolumeSource(audio_stream_type_t stream) const + { + return toVolumeSource(mEngine->getVolumeGroupForStreamType(stream)); + } + IVolumeCurves &getVolumeCurves(VolumeSource volumeSource) + { + auto *curves = mEngine->getVolumeCurvesForVolumeGroup( + static_cast(volumeSource)); + ALOG_ASSERT(curves != nullptr, "No curves for volume source %d", volumeSource); + return *curves; + } IVolumeCurves &getVolumeCurves(const audio_attributes_t &attr) { auto *curves = mEngine->getVolumeCurvesForAttributes(attr); @@ -395,7 +418,8 @@ protected: // compute the actual volume for a given stream according to the requested index and a particular // device - virtual float computeVolume(audio_stream_type_t stream, + virtual float computeVolume(IVolumeCurves &curves, + VolumeSource volumeSource, int index, audio_devices_t device); @@ -404,7 +428,8 @@ protected: audio_stream_type_t srcStream, audio_stream_type_t dstStream); // check that volume change is permitted, compute and send new volume to audio hardware - virtual status_t checkAndSetVolume(audio_stream_type_t stream, int index, + virtual status_t checkAndSetVolume(IVolumeCurves &curves, + VolumeSource volumeSource, int index, const sp& outputDesc, audio_devices_t device, int delayMs = 0, bool force = false); @@ -428,12 +453,22 @@ protected: int delayMs = 0, audio_devices_t device = AUDIO_DEVICE_NONE); - // Mute or unmute the stream on the specified output - void setStreamMute(audio_stream_type_t stream, - bool on, - const sp& outputDesc, - int delayMs = 0, - audio_devices_t device = (audio_devices_t)0); + /** + * @brief setVolumeSourceMute Mute or unmute the volume source on the specified output + * @param volumeSource to be muted/unmute (may host legacy streams or by extension set of + * audio attributes) + * @param on true to mute, false to umute + * @param outputDesc on which the client following the volume group shall be muted/umuted + * @param delayMs + * @param device + * @param activeOnly if true, mute only if the volume group is active on the output. + */ + void setVolumeSourceMute(VolumeSource volumeSource, + bool on, + const sp& outputDesc, + int delayMs = 0, + audio_devices_t device = AUDIO_DEVICE_NONE, + bool activeOnly = false); audio_mode_t getPhoneState();