From 251c7f0a9dc35dd3024fb4b42d27454abbd89d50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Gaffie?= Date: Wed, 7 Nov 2018 10:41:08 +0100 Subject: [PATCH] audiopolicy: engine: Add Volume Groups to common Engine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This CL adds the concept of Volume Group to the engine. It generalizes the volume management today controled by stream types and hard coded into AOSP. The goal is to control the volume per attributes, being able to define a group of attributes that follow the same volume curves. It intends to replace the concept of aliases in AudioService. Bug: 124767636 Test: build Change-Id: Icd079374cc1680d074b01836eca0bceb0b0c5247 Signed-off-by: François Gaffie --- media/libaudioclient/AudioAttributes.cpp | 4 +- .../include/media/AudioAttributes.h | 7 +- .../include/media/AudioCommonTypes.h | 6 +- services/audiopolicy/common/include/Volume.h | 1 + .../include/IVolumeCurves.h | 2 + .../managerdefinitions/src/HwModule.cpp | 2 +- .../engine/common/include/EngineBase.h | 25 ++- .../engine/common/include/ProductStrategy.h | 21 +- .../common/include/StreamVolumeCurves.h | 95 --------- .../engine/common/include/VolumeCurve.h | 28 +-- .../engine/common/include/VolumeGroup.h | 62 ++++++ .../engine/common/src/EngineBase.cpp | 112 +++++++--- .../engine/common/src/EngineDefaultConfig.h | 26 +-- .../engine/common/src/ProductStrategy.cpp | 73 ++++++- .../engine/common/src/StreamVolumeCurves.cpp | 47 ----- .../engine/common/src/VolumeCurve.cpp | 35 +++- .../engine/common/src/VolumeGroup.cpp | 75 +++++++ .../engine/config/include/EngineConfig.h | 2 +- .../engine/config/src/EngineConfig.cpp | 51 +++-- .../interface/AudioPolicyManagerInterface.h | 42 +++- .../audiopolicy/engineconfigurable/Android.mk | 2 +- .../config/example/Android.mk | 11 +- .../audio_policy_engine_configuration.xml | 1 + ...audio_policy_engine_product_strategies.xml | 39 ++-- .../audio_policy_engine_volumes.xml | 192 ++++++++++++++++++ ...audio_policy_engine_product_strategies.xml | 26 +-- .../audio_policy_engine_stream_volumes.xml | 28 +-- services/audiopolicy/enginedefault/Android.mk | 4 +- ...audio_policy_engine_product_strategies.xml | 26 +-- .../audio_policy_engine_stream_volumes.xml | 28 +-- .../managerdefault/AudioPolicyManager.cpp | 7 +- .../managerdefault/AudioPolicyManager.h | 14 +- 32 files changed, 771 insertions(+), 323 deletions(-) delete mode 100644 services/audiopolicy/engine/common/include/StreamVolumeCurves.h create mode 100644 services/audiopolicy/engine/common/include/VolumeGroup.h delete mode 100644 services/audiopolicy/engine/common/src/StreamVolumeCurves.cpp create mode 100644 services/audiopolicy/engine/common/src/VolumeGroup.cpp create mode 100644 services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_volumes.xml diff --git a/media/libaudioclient/AudioAttributes.cpp b/media/libaudioclient/AudioAttributes.cpp index 0f327cf3b6..1ee6930fbc 100644 --- a/media/libaudioclient/AudioAttributes.cpp +++ b/media/libaudioclient/AudioAttributes.cpp @@ -43,7 +43,7 @@ status_t AudioAttributes::readFromParcel(const Parcel *parcel) strcpy(mAttributes.tags, ""); } mStreamType = static_cast(parcel->readInt32()); - mGroupId = parcel->readUint32(); + mGroupId = static_cast(parcel->readUint32()); return NO_ERROR; } @@ -60,7 +60,7 @@ status_t AudioAttributes::writeToParcel(Parcel *parcel) const parcel->writeUtf8AsUtf16(mAttributes.tags); } parcel->writeInt32(static_cast(mStreamType)); - parcel->writeUint32(mGroupId); + parcel->writeUint32(static_cast(mGroupId)); return NO_ERROR; } diff --git a/media/libaudioclient/include/media/AudioAttributes.h b/media/libaudioclient/include/media/AudioAttributes.h index edf26ebe7c..0a35e9e89d 100644 --- a/media/libaudioclient/include/media/AudioAttributes.h +++ b/media/libaudioclient/include/media/AudioAttributes.h @@ -17,6 +17,7 @@ #pragma once +#include #include #include #include @@ -28,7 +29,7 @@ class AudioAttributes : public Parcelable public: AudioAttributes() = default; AudioAttributes(const audio_attributes_t &attributes) : mAttributes(attributes) {} - AudioAttributes(uint32_t groupId, + AudioAttributes(volume_group_t groupId, audio_stream_type_t stream, const audio_attributes_t &attributes) : mAttributes(attributes), mStreamType(stream), mGroupId(groupId) {} @@ -39,7 +40,7 @@ public: status_t writeToParcel(Parcel *parcel) const override; audio_stream_type_t getStreamType() const { return mStreamType; } - uint32_t getGroupId() const { return mGroupId; } + volume_group_t getGroupId() const { return mGroupId; } private: audio_attributes_t mAttributes = AUDIO_ATTRIBUTES_INITIALIZER; @@ -53,7 +54,7 @@ private: * @brief mGroupId: for future volume management, define groups within a strategy that follows * the same curves of volume (extension of stream types to manage volume) */ - uint32_t mGroupId = 0; + volume_group_t mGroupId = VOLUME_GROUP_NONE; }; } // namespace android diff --git a/media/libaudioclient/include/media/AudioCommonTypes.h b/media/libaudioclient/include/media/AudioCommonTypes.h index 5188da1fd3..8e446ea48c 100644 --- a/media/libaudioclient/include/media/AudioCommonTypes.h +++ b/media/libaudioclient/include/media/AudioCommonTypes.h @@ -27,7 +27,7 @@ enum product_strategy_t : uint32_t; const product_strategy_t PRODUCT_STRATEGY_NONE = static_cast(-1); using AttributesVector = std::vector; -using StreamTypes = std::vector; +using StreamTypeVector = std::vector; constexpr bool operator==(const audio_attributes_t &lhs, const audio_attributes_t &rhs) { @@ -38,5 +38,9 @@ constexpr bool operator!=(const audio_attributes_t &lhs, const audio_attributes_ { return !(lhs==rhs); } + +enum volume_group_t : uint32_t; +static const volume_group_t VOLUME_GROUP_NONE = static_cast(-1); + } // namespace android diff --git a/services/audiopolicy/common/include/Volume.h b/services/audiopolicy/common/include/Volume.h index a3b6b36fd2..48b5271932 100644 --- a/services/audiopolicy/common/include/Volume.h +++ b/services/audiopolicy/common/include/Volume.h @@ -21,6 +21,7 @@ #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 diff --git a/services/audiopolicy/common/managerdefinitions/include/IVolumeCurves.h b/services/audiopolicy/common/managerdefinitions/include/IVolumeCurves.h index 93022fb2a0..d408446f62 100644 --- a/services/audiopolicy/common/managerdefinitions/include/IVolumeCurves.h +++ b/services/audiopolicy/common/managerdefinitions/include/IVolumeCurves.h @@ -38,6 +38,8 @@ public: virtual float volIndexToDb(device_category device, int indexInUi) const = 0; virtual bool hasVolumeIndexForDevice(audio_devices_t device) const = 0; virtual status_t initVolume(int indexMin, int indexMax) = 0; + virtual std::vector getAttributes() const = 0; + virtual std::vector getStreamTypes() const = 0; virtual void dump(String8 *dst, int spaces = 0, bool curvePoints = false) const = 0; }; diff --git a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp index e0b233d18c..ec7ff572da 100644 --- a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp +++ b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp @@ -341,7 +341,7 @@ sp HwModuleCollection::getDeviceDescriptor(const audio_devices } } if (!allowToCreate) { - ALOGE("%s: could not find HW module for device %s %04x address %s", __FUNCTION__, + ALOGV("%s: could not find HW module for device %s %04x address %s", __FUNCTION__, name, deviceType, address); return nullptr; } diff --git a/services/audiopolicy/engine/common/include/EngineBase.h b/services/audiopolicy/engine/common/include/EngineBase.h index bc027e2a3f..35d86ee665 100644 --- a/services/audiopolicy/engine/common/include/EngineBase.h +++ b/services/audiopolicy/engine/common/include/EngineBase.h @@ -19,7 +19,7 @@ #include #include #include -#include +#include namespace android { namespace audio_policy { @@ -68,9 +68,25 @@ public: status_t listAudioProductStrategies(AudioProductStrategyVector &strategies) const override; - VolumeCurves *getVolumeCurvesForAttributes(const audio_attributes_t &attr) override; + VolumeCurves *getVolumeCurvesForAttributes(const audio_attributes_t &attr) const override; - VolumeCurves *getVolumeCurvesForStreamType(audio_stream_type_t stream) override; + VolumeCurves *getVolumeCurvesForStreamType(audio_stream_type_t stream) const override; + + IVolumeCurves *getVolumeCurvesForVolumeGroup(volume_group_t group) const override + { + return mVolumeGroups.find(group) != end(mVolumeGroups) ? + mVolumeGroups.at(group)->getVolumeCurves() : nullptr; + } + + VolumeGroupVector getVolumeGroups() const override; + + volume_group_t getVolumeGroupForAttributes(const audio_attributes_t &attr) const override; + + 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; void dump(String8 *dst) const override; @@ -105,12 +121,11 @@ public: AudioPolicyManagerObserver *mApmObserver = nullptr; ProductStrategyMap mProductStrategies; + VolumeGroupMap mVolumeGroups; audio_mode_t mPhoneState = AUDIO_MODE_NORMAL; /**< current phone state. */ /** current forced use configuration. */ audio_policy_forced_cfg_t mForceUse[AUDIO_POLICY_FORCE_USE_CNT] = {}; - - StreamVolumeCurves mStreamVolumeCurves; }; } // namespace audio_policy diff --git a/services/audiopolicy/engine/common/include/ProductStrategy.h b/services/audiopolicy/engine/common/include/ProductStrategy.h index 72505b29aa..767a8ed583 100644 --- a/services/audiopolicy/engine/common/include/ProductStrategy.h +++ b/services/audiopolicy/engine/common/include/ProductStrategy.h @@ -16,6 +16,8 @@ #pragma once +#include "VolumeGroup.h" + #include #include #include @@ -38,7 +40,7 @@ class ProductStrategy : public virtual RefBase, private HandleGenerator > { public: + /** + * @brief initialize: set default product strategy in cache. + */ + void initialize(); /** * @brief getProductStrategyForAttribute. The order of the vector is dimensionning. * @param attr @@ -136,9 +148,16 @@ public: std::string getDeviceAddressForProductStrategy(product_strategy_t strategy) const; + volume_group_t getVolumeGroupForAttributes(const audio_attributes_t &attr) const; + + volume_group_t getVolumeGroupForStreamType(audio_stream_type_t stream) const; + product_strategy_t getDefault() const; void dump(String8 *dst, int spaces = 0) const; + +private: + product_strategy_t mDefaultStrategy = PRODUCT_STRATEGY_NONE; }; } // namespace android diff --git a/services/audiopolicy/engine/common/include/StreamVolumeCurves.h b/services/audiopolicy/engine/common/include/StreamVolumeCurves.h deleted file mode 100644 index 5b0b7d6272..0000000000 --- a/services/audiopolicy/engine/common/include/StreamVolumeCurves.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include - -namespace android { - -class StreamVolumeCurves -{ -public: - StreamVolumeCurves() = default; - - /** - * @brief switchVolumeCurve control API for Engine, allows to switch the volume curves - * from one stream type to another. - * @param src source stream type - * @param dst destination stream type - */ - status_t switchVolumeCurve(audio_stream_type_t streamSrc, audio_stream_type_t streamDst) - { - if (!hasCurvesFor(streamSrc) || !hasCurvesFor(streamDst)) { - ALOGE("%s: No curves defined for streams %d %d", __FUNCTION__, streamSrc, streamDst); - return NO_INIT; - } - const VolumeCurves &sourceCurves = getCurvesFor(streamSrc); - VolumeCurves &dstCurves = editCurvesFor(streamDst); - return dstCurves.switchCurvesFrom(sourceCurves); - } - void dump(String8 *dst, int spaces = 0) const; - - void add(const VolumeCurves &curves, audio_stream_type_t streamType) - { - mCurves.emplace(streamType, curves); - } - - bool hasCurvesFor(audio_stream_type_t stream) - { - return mCurves.find(stream) != end(mCurves); - } - - VolumeCurves &editCurvesFor(audio_stream_type_t stream) - { - ALOG_ASSERT(mCurves.find(stream) != end(mCurves), "Invalid stream type for Volume Curve"); - return mCurves[stream]; - } - const VolumeCurves &getCurvesFor(audio_stream_type_t stream) const - { - ALOG_ASSERT(mCurves.find(stream) != end(mCurves), "Invalid stream type for Volume Curve"); - return mCurves.at(stream); - } - /** - * @brief getVolumeCurvesForStream - * @param stream type for which the volume curves interface is requested - * @return the VolumeCurves for a given stream type. - */ - VolumeCurves &getVolumeCurvesForStream(audio_stream_type_t stream) - { - ALOG_ASSERT(mCurves.find(stream) != end(mCurves), "Invalid stream type for Volume Curve"); - return mCurves[stream]; - } - /** - * @brief restoreOriginVolumeCurve helper control API for engine to restore the original volume - * curves for a given stream type - * @param stream for which the volume curves will be restored. - */ - status_t restoreOriginVolumeCurve(audio_stream_type_t stream) - { - if (!hasCurvesFor(stream)) { - ALOGE("%s: No curves defined for streams", __FUNCTION__); - return NO_INIT; - } - return switchVolumeCurve(stream, stream); - } - -private: - std::map mCurves; -}; - -} // namespace android diff --git a/services/audiopolicy/engine/common/include/VolumeCurve.h b/services/audiopolicy/engine/common/include/VolumeCurve.h index 0ec63e19fc..54314e3a03 100644 --- a/services/audiopolicy/engine/common/include/VolumeCurve.h +++ b/services/audiopolicy/engine/common/include/VolumeCurve.h @@ -18,7 +18,9 @@ #include "IVolumeCurves.h" #include +#include #include +#include #include #include #include @@ -71,18 +73,11 @@ class VolumeCurves : public KeyedVector >, { public: VolumeCurves(int indexMin = 0, int indexMax = 100) : - mIndexMin(indexMin), mIndexMax(indexMax), mStream(AUDIO_STREAM_DEFAULT) + mIndexMin(indexMin), mIndexMax(indexMax) { addCurrentVolumeIndex(AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME, 0); } - VolumeCurves(audio_stream_type_t stream, int indexMin, int indexMax) : - mIndexMin(indexMin), mIndexMax(indexMax), mStream(stream) - { - addCurrentVolumeIndex(AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME, 0); - } - - // Once XML has been parsed, must be call first to sanity check table and initialize indexes - virtual status_t initVolume(int indexMin, int indexMax) + status_t initVolume(int indexMin, int indexMax) override { mIndexMin = indexMin; mIndexMax = indexMax; @@ -174,8 +169,16 @@ public: return 0.0f; } } - - audio_stream_type_t getStreamType() const { return mStream; } + void addAttributes(const audio_attributes_t &attr) + { + mAttributes.push_back(attr); + } + AttributesVector getAttributes() const override { return mAttributes; } + void addStreamType(audio_stream_type_t stream) + { + mStreams.push_back(stream); + } + StreamTypeVector getStreamTypes() const override { return mStreams; } void dump(String8 *dst, int spaces = 0, bool curvePoints = false) const override; @@ -186,7 +189,8 @@ private: int mIndexMax; /**< max volume index. */ const bool mCanBeMuted = true; /**< true is the stream can be muted. */ - const audio_stream_type_t mStream; /**< Keep it for legacy. */ + AttributesVector mAttributes; + StreamTypeVector mStreams; /**< Keep it for legacy. */ }; } // namespace android diff --git a/services/audiopolicy/engine/common/include/VolumeGroup.h b/services/audiopolicy/engine/common/include/VolumeGroup.h new file mode 100644 index 0000000000..c34b4062ff --- /dev/null +++ b/services/audiopolicy/engine/common/include/VolumeGroup.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace android { + +class VolumeGroup : public virtual RefBase, private HandleGenerator +{ +public: + VolumeGroup(const std::string &name, int indexMin, int indexMax); + std::string getName() const { return mName; } + volume_group_t getId() const { return mId; } + + void add(const sp &curve); + + VolumeCurves *getVolumeCurves() { return &mGroupVolumeCurves; } + + void addSupportedAttributes(const audio_attributes_t &attr); + AttributesVector getSupportedAttributes() const { return mGroupVolumeCurves.getAttributes(); } + + void addSupportedStream(audio_stream_type_t stream); + StreamTypeVector getStreamTypes() const { return mGroupVolumeCurves.getStreamTypes(); } + + void dump(String8 *dst, int spaces = 0) const; + +private: + const std::string mName; + const volume_group_t mId; + VolumeCurves mGroupVolumeCurves; +}; + +class VolumeGroupMap : public std::map > +{ +public: + void dump(String8 *dst, int spaces = 0) const; +}; + +} // namespace android diff --git a/services/audiopolicy/engine/common/src/EngineBase.cpp b/services/audiopolicy/engine/common/src/EngineBase.cpp index 6e2ab4cdfa..4d7c4a05bb 100644 --- a/services/audiopolicy/engine/common/src/EngineBase.cpp +++ b/services/audiopolicy/engine/common/src/EngineBase.cpp @@ -15,7 +15,7 @@ */ #define LOG_TAG "APM::AudioPolicyEngine/Base" -#define LOG_NDEBUG 0 +//#define LOG_NDEBUG 0 #include "EngineBase.h" #include "EngineDefaultConfig.h" @@ -96,46 +96,47 @@ product_strategy_t EngineBase::getProductStrategyByName(const std::string &name) engineConfig::ParsingResult EngineBase::loadAudioPolicyEngineConfig() { auto loadProductStrategies = - [](auto& strategyConfigs, auto& productStrategies) { - uint32_t groupid = 0; + [](auto& strategyConfigs, auto& productStrategies, auto& volumeGroups) { for (auto& strategyConfig : strategyConfigs) { sp strategy = new ProductStrategy(strategyConfig.name); for (const auto &group : strategyConfig.attributesGroups) { + const auto &iter = std::find_if(begin(volumeGroups), end(volumeGroups), + [&group](const auto &volumeGroup) { + return group.volumeGroup == volumeGroup.second->getName(); }); + ALOG_ASSERT(iter != end(volumeGroups), "Invalid Volume Group Name %s", + group.volumeGroup.c_str()); + if (group.stream != AUDIO_STREAM_DEFAULT) { + iter->second->addSupportedStream(group.stream); + } for (const auto &attr : group.attributesVect) { - strategy->addAttributes({group.stream, groupid, attr}); + strategy->addAttributes({group.stream, iter->second->getId(), attr}); + iter->second->addSupportedAttributes(attr); } - groupid += 1; } product_strategy_t strategyId = strategy->getId(); productStrategies[strategyId] = strategy; } }; - auto loadVolumeCurves = [](const auto &configVolumes, auto &streamVolumeCollection) { - for (auto &configVolume : configVolumes) { - audio_stream_type_t streamType = AUDIO_STREAM_DEFAULT; - if (configVolume.stream.empty() || - !StreamTypeConverter::fromString(configVolume.stream, streamType)) { - ALOGE("%s: Invalid stream type", __FUNCTION__); - continue; - } - VolumeCurves volumeCurves(streamType, configVolume.indexMin, configVolume.indexMax); - for (auto &configCurve : configVolume.volumeCurves) { - device_category deviceCategory = DEVICE_CATEGORY_SPEAKER; - if (!DeviceCategoryConverter::fromString(configCurve.deviceCategory, - deviceCategory)) { + auto loadVolumeGroups = [](auto &volumeConfigs, auto &volumeGroups) { + for (auto &volumeConfig : volumeConfigs) { + sp volumeGroup = new VolumeGroup(volumeConfig.name, volumeConfig.indexMin, + volumeConfig.indexMax); + volumeGroups[volumeGroup->getId()] = volumeGroup; + + for (auto &configCurve : volumeConfig.volumeCurves) { + device_category deviceCat = DEVICE_CATEGORY_SPEAKER; + if (!DeviceCategoryConverter::fromString(configCurve.deviceCategory, deviceCat)) { ALOGE("%s: Invalid %s", __FUNCTION__, configCurve.deviceCategory.c_str()); continue; } - sp curve = new VolumeCurve(deviceCategory); + sp curve = new VolumeCurve(deviceCat); for (auto &point : configCurve.curvePoints) { curve->add({point.index, point.attenuationInMb}); } - volumeCurves.add(curve); + volumeGroup->add(curve); } - streamVolumeCollection.add(volumeCurves, streamType); } }; - auto result = engineConfig::parse(); if (result.parsedConfig == nullptr) { ALOGW("%s: No configuration found, using default matching phone experience.", __FUNCTION__); @@ -145,8 +146,10 @@ engineConfig::ParsingResult EngineBase::loadAudioPolicyEngineConfig() static_cast(ret == NO_ERROR ? 0 : 1)}; } ALOGE_IF(result.nbSkippedElement != 0, "skipped %zu elements", result.nbSkippedElement); - loadProductStrategies(result.parsedConfig->productStrategies, mProductStrategies); - loadVolumeCurves(result.parsedConfig->volumeGroups, mStreamVolumeCurves); + loadVolumeGroups(result.parsedConfig->volumeGroups, mVolumeGroups); + loadProductStrategies(result.parsedConfig->productStrategies, mProductStrategies, + mVolumeGroups); + mProductStrategies.initialize(); return result; } @@ -204,30 +207,77 @@ status_t EngineBase::listAudioProductStrategies(AudioProductStrategyVector &stra return NO_ERROR; } -VolumeCurves *EngineBase::getVolumeCurvesForAttributes(const audio_attributes_t &attr) +VolumeCurves *EngineBase::getVolumeCurvesForAttributes(const audio_attributes_t &attr) const { - return &mStreamVolumeCurves.getVolumeCurvesForStream(getStreamTypeForAttributes(attr)); + volume_group_t volGr = mProductStrategies.getVolumeGroupForAttributes(attr); + const auto &iter = mVolumeGroups.find(volGr); + LOG_ALWAYS_FATAL_IF(iter == std::end(mVolumeGroups), "No volume groups for %s", toString(attr).c_str()); + return mVolumeGroups.at(volGr)->getVolumeCurves(); } -VolumeCurves *EngineBase::getVolumeCurvesForStreamType(audio_stream_type_t stream) +VolumeCurves *EngineBase::getVolumeCurvesForStreamType(audio_stream_type_t stream) const { - return &mStreamVolumeCurves.getVolumeCurvesForStream(stream); + volume_group_t volGr = mProductStrategies.getVolumeGroupForStreamType(stream); + const auto &iter = mVolumeGroups.find(volGr); + LOG_ALWAYS_FATAL_IF(iter == std::end(mVolumeGroups), "No volume groups for %s", + toString(stream).c_str()); + return mVolumeGroups.at(volGr)->getVolumeCurves(); } status_t EngineBase::switchVolumeCurve(audio_stream_type_t streamSrc, audio_stream_type_t streamDst) { - return mStreamVolumeCurves.switchVolumeCurve(streamSrc, streamDst);; + auto srcCurves = getVolumeCurvesForStreamType(streamSrc); + auto dstCurves = getVolumeCurvesForStreamType(streamDst); + + if (srcCurves == nullptr || dstCurves == nullptr) { + return BAD_VALUE; + } + return dstCurves->switchCurvesFrom(*srcCurves); } status_t EngineBase::restoreOriginVolumeCurve(audio_stream_type_t stream) { - return mStreamVolumeCurves.restoreOriginVolumeCurve(stream); + VolumeCurves *curves = getVolumeCurvesForStreamType(stream); + return curves != nullptr ? curves->switchCurvesFrom(*curves) : BAD_VALUE; +} + +VolumeGroupVector EngineBase::getVolumeGroups() const +{ + VolumeGroupVector group; + for (const auto &iter : mVolumeGroups) { + group.push_back(iter.first); + } + return group; +} + +volume_group_t EngineBase::getVolumeGroupForAttributes(const audio_attributes_t &attr) const +{ + return mProductStrategies.getVolumeGroupForAttributes(attr); +} + +volume_group_t EngineBase::getVolumeGroupForStreamType(audio_stream_type_t stream) const +{ + 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(); } void EngineBase::dump(String8 *dst) const { mProductStrategies.dump(dst, 2); - mStreamVolumeCurves.dump(dst, 2); + mVolumeGroups.dump(dst, 2); } } // namespace audio_policy diff --git a/services/audiopolicy/engine/common/src/EngineDefaultConfig.h b/services/audiopolicy/engine/common/src/EngineDefaultConfig.h index f1642c5e3c..fede0d93de 100644 --- a/services/audiopolicy/engine/common/src/EngineDefaultConfig.h +++ b/services/audiopolicy/engine/common/src/EngineDefaultConfig.h @@ -25,11 +25,11 @@ namespace android { const engineConfig::ProductStrategies gOrderedStrategies = { {"STRATEGY_PHONE", { - {"phone", AUDIO_STREAM_VOICE_CALL, + {"phone", AUDIO_STREAM_VOICE_CALL, "AUDIO_STREAM_VOICE_CALL", {{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_VOICE_COMMUNICATION, AUDIO_SOURCE_DEFAULT, 0, ""}}, }, - {"sco", AUDIO_STREAM_BLUETOOTH_SCO, + {"sco", AUDIO_STREAM_BLUETOOTH_SCO, "AUDIO_STREAM_BLUETOOTH_SCO", {{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_SCO, ""}}, } @@ -37,18 +37,18 @@ const engineConfig::ProductStrategies gOrderedStrategies = { }, {"STRATEGY_SONIFICATION", { - {"ring", AUDIO_STREAM_RING, + {"ring", AUDIO_STREAM_RING, "AUDIO_STREAM_RING", {{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE, AUDIO_SOURCE_DEFAULT, 0, ""}} }, - {"alarm", AUDIO_STREAM_ALARM, + {"alarm", AUDIO_STREAM_ALARM, "AUDIO_STREAM_ALARM", {{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_ALARM, AUDIO_SOURCE_DEFAULT, 0, ""}}, } }, }, {"STRATEGY_ENFORCED_AUDIBLE", { - {"", AUDIO_STREAM_ENFORCED_AUDIBLE, + {"", AUDIO_STREAM_ENFORCED_AUDIBLE, "AUDIO_STREAM_ENFORCED_AUDIBLE", {{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_AUDIBILITY_ENFORCED, ""}} } @@ -56,7 +56,7 @@ const engineConfig::ProductStrategies gOrderedStrategies = { }, {"STRATEGY_ACCESSIBILITY", { - {"", AUDIO_STREAM_ACCESSIBILITY, + {"", AUDIO_STREAM_ACCESSIBILITY, "AUDIO_STREAM_ACCESSIBILITY", {{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY, AUDIO_SOURCE_DEFAULT, 0, ""}} } @@ -64,7 +64,7 @@ const engineConfig::ProductStrategies gOrderedStrategies = { }, {"STRATEGY_SONIFICATION_RESPECTFUL", { - {"", AUDIO_STREAM_NOTIFICATION, + {"", AUDIO_STREAM_NOTIFICATION, "AUDIO_STREAM_NOTIFICATION", { {AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_NOTIFICATION, AUDIO_SOURCE_DEFAULT, 0, ""}, {AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST, @@ -81,7 +81,7 @@ const engineConfig::ProductStrategies gOrderedStrategies = { }, {"STRATEGY_MEDIA", { - {"music", AUDIO_STREAM_MUSIC, + {"music", AUDIO_STREAM_MUSIC, "AUDIO_STREAM_MUSIC", { {AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_MEDIA, AUDIO_SOURCE_DEFAULT, 0, ""}, {AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_GAME, AUDIO_SOURCE_DEFAULT, 0, ""}, @@ -91,7 +91,7 @@ const engineConfig::ProductStrategies gOrderedStrategies = { {AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_DEFAULT, 0, ""} }, }, - {"system", AUDIO_STREAM_SYSTEM, + {"system", AUDIO_STREAM_SYSTEM, "AUDIO_STREAM_SYSTEM", {{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_ASSISTANCE_SONIFICATION, AUDIO_SOURCE_DEFAULT, 0, ""}} } @@ -99,7 +99,7 @@ const engineConfig::ProductStrategies gOrderedStrategies = { }, {"STRATEGY_DTMF", { - {"", AUDIO_STREAM_DTMF, + {"", AUDIO_STREAM_DTMF, "AUDIO_STREAM_DTMF", { {AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING, AUDIO_SOURCE_DEFAULT, 0, ""} @@ -109,7 +109,7 @@ const engineConfig::ProductStrategies gOrderedStrategies = { }, {"STRATEGY_TRANSMITTED_THROUGH_SPEAKER", { - {"", AUDIO_STREAM_TTS, + {"", AUDIO_STREAM_TTS, "AUDIO_STREAM_TTS", {{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_BEACON, ""}} } @@ -117,14 +117,14 @@ const engineConfig::ProductStrategies gOrderedStrategies = { }, {"STRATEGY_REROUTING", { - {"", AUDIO_STREAM_REROUTING, + {"", AUDIO_STREAM_REROUTING, "AUDIO_STREAM_REROUTING", {{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_DEFAULT, 0, ""}} } }, }, {"STRATEGY_PATCH", { - {"", AUDIO_STREAM_PATCH, + {"", AUDIO_STREAM_PATCH, "AUDIO_STREAM_PATCH", {{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_DEFAULT, 0, ""}} } }, diff --git a/services/audiopolicy/engine/common/src/ProductStrategy.cpp b/services/audiopolicy/engine/common/src/ProductStrategy.cpp index 71607d1be4..16e6690a58 100644 --- a/services/audiopolicy/engine/common/src/ProductStrategy.cpp +++ b/services/audiopolicy/engine/common/src/ProductStrategy.cpp @@ -44,7 +44,7 @@ std::vector ProductStrategy::listAudioAttributes() con { std::vector androidAa; for (const auto &attr : mAttributesVector) { - androidAa.push_back({attr.mGroupId, attr.mStream, attr.mAttributes}); + androidAa.push_back({attr.mVolumeGroup, attr.mStream, attr.mAttributes}); } return androidAa; } @@ -69,7 +69,8 @@ bool ProductStrategy::matches(const audio_attributes_t attr) const }) != end(mAttributesVector); } -audio_stream_type_t ProductStrategy::getStreamTypeForAttributes(const audio_attributes_t &attr) const +audio_stream_type_t ProductStrategy::getStreamTypeForAttributes( + const audio_attributes_t &attr) const { const auto iter = std::find_if(begin(mAttributesVector), end(mAttributesVector), [&attr](const auto &supportedAttr) { @@ -110,6 +111,33 @@ bool ProductStrategy::supportStreamType(const audio_stream_type_t &streamType) c return supportedAttr.mStream == streamType; }) != end(mAttributesVector); } +volume_group_t ProductStrategy::getVolumeGroupForAttributes(const audio_attributes_t &attr) const +{ + for (const auto &supportedAttr : mAttributesVector) { + if (AudioProductStrategy::attributesMatches(supportedAttr.mAttributes, attr)) { + return supportedAttr.mVolumeGroup; + } + } + return VOLUME_GROUP_NONE; +} + +volume_group_t ProductStrategy::getVolumeGroupForStreamType(audio_stream_type_t stream) const +{ + for (const auto &supportedAttr : mAttributesVector) { + if (supportedAttr.mStream == stream) { + return supportedAttr.mVolumeGroup; + } + } + return VOLUME_GROUP_NONE; +} + +volume_group_t ProductStrategy::getDefaultVolumeGroup() const +{ + const auto &iter = std::find_if(begin(mAttributesVector), end(mAttributesVector), + [](const auto &attr) {return attr.mAttributes == defaultAttr;}); + return iter != end(mAttributesVector) ? iter->mVolumeGroup : VOLUME_GROUP_NONE; +} + void ProductStrategy::dump(String8 *dst, int spaces) const { dst->appendFormat("\n%*s-%s (id: %d)\n", spaces, "", mName.c_str(), mId); @@ -121,7 +149,7 @@ void ProductStrategy::dump(String8 *dst, int spaces) const deviceLiteral.c_str(), mDeviceAddress.c_str()); for (const auto &attr : mAttributesVector) { - dst->appendFormat("%*sGroup: %d stream: %s\n", spaces + 3, "", attr.mGroupId, + dst->appendFormat("%*sGroup: %d stream: %s\n", spaces + 3, "", attr.mVolumeGroup, android::toString(attr.mStream).c_str()); dst->appendFormat("%*s Attributes: ", spaces + 3, ""); std::string attStr = @@ -172,6 +200,9 @@ audio_stream_type_t ProductStrategyMap::getStreamTypeForAttributes( product_strategy_t ProductStrategyMap::getDefault() const { + if (mDefaultStrategy != PRODUCT_STRATEGY_NONE) { + return mDefaultStrategy; + } for (const auto &iter : *this) { if (iter.second->isDefault()) { ALOGV("%s: using default %s", __FUNCTION__, iter.second->getName().c_str()); @@ -231,6 +262,42 @@ std::string ProductStrategyMap::getDeviceAddressForProductStrategy(product_strat return at(psId)->getDeviceAddress(); } +volume_group_t ProductStrategyMap::getVolumeGroupForAttributes(const audio_attributes_t &attr) const +{ + for (const auto &iter : *this) { + volume_group_t group = iter.second->getVolumeGroupForAttributes(attr); + if (group != VOLUME_GROUP_NONE) { + return group; + } + } + product_strategy_t defaultStrategy = getDefault(); + if (defaultStrategy == PRODUCT_STRATEGY_NONE) { + return VOLUME_GROUP_NONE; + } + return at(defaultStrategy)->getDefaultVolumeGroup(); +} + +volume_group_t ProductStrategyMap::getVolumeGroupForStreamType(audio_stream_type_t stream) const +{ + for (const auto &iter : *this) { + volume_group_t group = iter.second->getVolumeGroupForStreamType(stream); + if (group != VOLUME_GROUP_NONE) { + return group; + } + } + product_strategy_t defaultStrategy = getDefault(); + if (defaultStrategy == PRODUCT_STRATEGY_NONE) { + return VOLUME_GROUP_NONE; + } + return at(defaultStrategy)->getDefaultVolumeGroup(); +} + +void ProductStrategyMap::initialize() +{ + mDefaultStrategy = getDefault(); + ALOG_ASSERT(mDefaultStrategy != PRODUCT_STRATEGY_NONE, "No default product strategy found"); +} + void ProductStrategyMap::dump(String8 *dst, int spaces) const { dst->appendFormat("%*sProduct Strategies dump:", spaces, ""); diff --git a/services/audiopolicy/engine/common/src/StreamVolumeCurves.cpp b/services/audiopolicy/engine/common/src/StreamVolumeCurves.cpp deleted file mode 100644 index fe3b0007b6..0000000000 --- a/services/audiopolicy/engine/common/src/StreamVolumeCurves.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "APM::Engine::StreamVolumeCurves" -//#define LOG_NDEBUG 0 - -#include "StreamVolumeCurves.h" -#include - -namespace android { - -void StreamVolumeCurves::dump(String8 *dst, int spaces) const -{ - if (mCurves.empty()) { - return; - } - dst->appendFormat("\n%*sStreams dump:\n", spaces, ""); - dst->appendFormat( - "%*sStream Can be muted Index Min Index Max Index Cur [device : index]...\n", spaces + 2, ""); - for (const auto &streamCurve : mCurves) { - streamCurve.second.dump(dst, spaces + 2, false); - } - dst->appendFormat("\n%*sVolume Curves for Use Cases (aka Stream types) dump:\n", spaces, ""); - for (const auto &streamCurve : mCurves) { - std::string streamTypeLiteral; - StreamTypeConverter::toString(streamCurve.first, streamTypeLiteral); - dst->appendFormat( - " %s (%02d): Curve points for device category (index, attenuation in millibel)\n", - streamTypeLiteral.c_str(), streamCurve.first); - streamCurve.second.dump(dst, spaces + 2, true); - } -} - -} // namespace android diff --git a/services/audiopolicy/engine/common/src/VolumeCurve.cpp b/services/audiopolicy/engine/common/src/VolumeCurve.cpp index be2ca730ef..c352578d5c 100644 --- a/services/audiopolicy/engine/common/src/VolumeCurve.cpp +++ b/services/audiopolicy/engine/common/src/VolumeCurve.cpp @@ -19,13 +19,17 @@ #include "VolumeCurve.h" #include "TypeConverter.h" +#include namespace android { float VolumeCurve::volIndexToDb(int indexInUi, int volIndexMin, int volIndexMax) const { ALOG_ASSERT(!mCurvePoints.isEmpty(), "Invalid volume curve"); - + if (volIndexMin < 0 || volIndexMax < 0) { + // In order to let AudioService initialize the min and max, convention is to use -1 + return NAN; + } if (indexInUi < volIndexMin) { // an index of 0 means mute request when volIndexMin > 0 if (indexInUi == 0) { @@ -80,8 +84,8 @@ void VolumeCurve::dump(String8 *dst, int spaces, bool curvePoints) const } dst->append(" {"); for (size_t i = 0; i < mCurvePoints.size(); i++) { - dst->appendFormat("%*s (%3d, %5d)", spaces, "", - mCurvePoints[i].mIndex, mCurvePoints[i].mAttenuationInMb); + dst->appendFormat("%*s(%3d, %5d)", spaces, "", mCurvePoints[i].mIndex, + mCurvePoints[i].mAttenuationInMb); dst->appendFormat(i == (mCurvePoints.size() - 1) ? " }\n" : ", "); } } @@ -89,19 +93,36 @@ void VolumeCurve::dump(String8 *dst, int spaces, bool curvePoints) const void VolumeCurves::dump(String8 *dst, int spaces, bool curvePoints) const { if (!curvePoints) { - dst->appendFormat("%*s%02d %s %03d %03d ", spaces, "", - mStream, mCanBeMuted ? "true " : "false", mIndexMin, mIndexMax); +// dst->appendFormat("%*s%02d %s %03d %03d ", spaces, "", +// mStream, mCanBeMuted ? "true " : "false", mIndexMin, mIndexMax); + dst->appendFormat("%*s Can be muted Index Min Index Max Index Cur [device : index]...\n", + spaces + 1, ""); + dst->appendFormat("%*s %s %02d %02d ", spaces + 1, "", + mCanBeMuted ? "true " : "false", mIndexMin, mIndexMax); for (const auto &pair : mIndexCur) { - dst->appendFormat("%*s %04x : %02d, ", spaces, "", pair.first, pair.second); + dst->appendFormat("%04x : %02d, ", pair.first, pair.second); } dst->appendFormat("\n"); return; } + std::string streamNames; + for (const auto &stream : mStreams) { + streamNames += android::toString(stream) + "("+std::to_string(stream)+") "; + } + dst->appendFormat("%*sVolume Curves Streams/Attributes, Curve points Streams for device" + " category (index, attenuation in millibel)\n", spaces, ""); + dst->appendFormat("%*s Streams: %s \n", spaces, "", streamNames.c_str()); + if (!mAttributes.empty()) dst->appendFormat("%*s Attributes:", spaces, ""); + for (const auto &attributes : mAttributes) { + std::string attStr = attributes == defaultAttr ? "{ Any }" : android::toString(attributes); + dst->appendFormat("%*s %s\n", attributes == mAttributes.front() ? 0 : spaces + 13, "", + attStr.c_str()); + } for (size_t i = 0; i < size(); i++) { std::string deviceCatLiteral; DeviceCategoryConverter::toString(keyAt(i), deviceCatLiteral); dst->appendFormat("%*s %s :", spaces, "", deviceCatLiteral.c_str()); - valueAt(i)->dump(dst, 2, true); + valueAt(i)->dump(dst, 1, true); } } diff --git a/services/audiopolicy/engine/common/src/VolumeGroup.cpp b/services/audiopolicy/engine/common/src/VolumeGroup.cpp new file mode 100644 index 0000000000..e1898070cb --- /dev/null +++ b/services/audiopolicy/engine/common/src/VolumeGroup.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "APM::AudioPolicyEngine/VolumeGroup" +//#define LOG_NDEBUG 0 + +#include "VolumeGroup.h" +#include +#include +#include +#include + +#include + + +namespace android { + +// +// VolumeGroup implementation +// +VolumeGroup::VolumeGroup(const std::string &name, int indexMin, int indexMax) : + mName(name), mId(static_cast(HandleGenerator::getNextHandle())), + mGroupVolumeCurves(VolumeCurves(indexMin, indexMax)) +{ +} + +void VolumeGroup::dump(String8 *dst, int spaces) const +{ + dst->appendFormat("\n%*s-%s (id: %d)\n", spaces, "", mName.c_str(), mId); + mGroupVolumeCurves.dump(dst, spaces + 2, true); + mGroupVolumeCurves.dump(dst, spaces + 2, false); + dst->appendFormat("\n"); +} + +void VolumeGroup::add(const sp &curve) +{ + mGroupVolumeCurves.add(curve); +} + +void VolumeGroup::addSupportedAttributes(const audio_attributes_t &attr) +{ + mGroupVolumeCurves.addAttributes(attr); +} + +void VolumeGroup::addSupportedStream(audio_stream_type_t stream) +{ + mGroupVolumeCurves.addStreamType(stream); +} + +// +// VolumeGroupMap implementation +// +void VolumeGroupMap::dump(String8 *dst, int spaces) const +{ + dst->appendFormat("\n%*sVolume Groups dump:", spaces, ""); + for (const auto &iter : *this) { + iter.second->dump(dst, spaces + 2); + } +} + +} // namespace android + diff --git a/services/audiopolicy/engine/config/include/EngineConfig.h b/services/audiopolicy/engine/config/include/EngineConfig.h index a188115fff..7f5ed5eb9d 100644 --- a/services/audiopolicy/engine/config/include/EngineConfig.h +++ b/services/audiopolicy/engine/config/include/EngineConfig.h @@ -40,6 +40,7 @@ using StreamVector = std::vector; struct AttributesGroup { std::string name; audio_stream_type_t stream; + std::string volumeGroup; AttributesVector attributesVect; }; @@ -59,7 +60,6 @@ using VolumeCurves = std::vector; struct VolumeGroup { std::string name; - std::string stream; int indexMin; int indexMax; VolumeCurves volumeCurves; diff --git a/services/audiopolicy/engine/config/src/EngineConfig.cpp b/services/audiopolicy/engine/config/src/EngineConfig.cpp index 00fbac411b..1ad773939a 100644 --- a/services/audiopolicy/engine/config/src/EngineConfig.cpp +++ b/services/audiopolicy/engine/config/src/EngineConfig.cpp @@ -59,6 +59,7 @@ struct AttributesGroupTraits : public BaseSerializerTraits { struct Attributes { static constexpr const char *deviceCategory = "deviceCategory"; + static constexpr const char *stream = "stream"; // For legacy volume curves static constexpr const char *reference = "ref"; /**< For volume curves factorization. */ }; @@ -139,8 +141,6 @@ struct VolumeGroupTraits : public BaseSerializerTraits; -using xmlCharUnique = std::unique_ptr; - std::string getXmlAttribute(const xmlNode *cur, const char *attribute) { xmlCharUnique charPtr(xmlGetProp(cur, reinterpret_cast(attribute)), xmlFree); @@ -304,6 +304,12 @@ status_t AttributesGroupTraits::deserialize(_xmlDoc *doc, const _xmlNode *child, } ALOGV("%s: %s = %s", __FUNCTION__, Attributes::name, name.c_str()); + std::string volumeGroup = getXmlAttribute(child, Attributes::volumeGroup); + if (volumeGroup.empty()) { + ALOGE("%s: No attribute %s found", __FUNCTION__, Attributes::volumeGroup); + } + ALOGV("%s: %s = %s", __FUNCTION__, Attributes::volumeGroup, volumeGroup.c_str()); + audio_stream_type_t streamType = AUDIO_STREAM_DEFAULT; std::string streamTypeXml = getXmlAttribute(child, Attributes::streamType); if (streamTypeXml.empty()) { @@ -318,7 +324,7 @@ status_t AttributesGroupTraits::deserialize(_xmlDoc *doc, const _xmlNode *child, AttributesVector attributesVect; deserializeAttributesCollection(doc, child, attributesVect); - attributesGroup.push_back({name, streamType, attributesVect}); + attributesGroup.push_back({name, streamType, volumeGroup, attributesVect}); return NO_ERROR; } @@ -420,7 +426,6 @@ status_t VolumeTraits::deserialize(_xmlDoc *doc, const _xmlNode *root, Collectio if (deviceCategory.empty()) { ALOGW("%s: No %s found", __FUNCTION__, Attributes::deviceCategory); } - std::string referenceName = getXmlAttribute(root, Attributes::reference); const _xmlNode *ref = NULL; if (!referenceName.empty()) { @@ -458,9 +463,10 @@ status_t VolumeTraits::deserialize(_xmlDoc *doc, const _xmlNode *root, Collectio status_t VolumeGroupTraits::deserialize(_xmlDoc *doc, const _xmlNode *root, Collection &volumes) { std::string name; - std::string stream = {}; int indexMin = 0; int indexMax = 0; + StreamVector streams = {}; + AttributesVector attributesVect = {}; for (const xmlNode *child = root->xmlChildrenNode; child != NULL; child = child->next) { if (not xmlStrcmp(child->name, (const xmlChar *)Attributes::name)) { @@ -470,13 +476,6 @@ status_t VolumeGroupTraits::deserialize(_xmlDoc *doc, const _xmlNode *root, Coll } name = reinterpret_cast(nameXml.get()); } - if (not xmlStrcmp(child->name, (const xmlChar *)Attributes::stream)) { - xmlCharUnique streamXml(xmlNodeListGetString(doc, child->xmlChildrenNode, 1), xmlFree); - if (streamXml == nullptr) { - return BAD_VALUE; - } - stream = reinterpret_cast(streamXml.get()); - } if (not xmlStrcmp(child->name, (const xmlChar *)Attributes::indexMin)) { xmlCharUnique indexMinXml(xmlNodeListGetString(doc, child->xmlChildrenNode, 1), xmlFree); if (indexMinXml == nullptr) { @@ -498,13 +497,23 @@ status_t VolumeGroupTraits::deserialize(_xmlDoc *doc, const _xmlNode *root, Coll } } } - ALOGV("%s: group=%s stream=%s indexMin=%d, indexMax=%d", - __func__, name.c_str(), stream.c_str(), indexMin, indexMax); + deserializeAttributesCollection(doc, root, attributesVect); + + std::string streamNames; + for (const auto &stream : streams) { + streamNames += android::toString(stream) + " "; + } + std::string attrmNames; + for (const auto &attr : attributesVect) { + attrmNames += android::toString(attr) + "\n"; + } + ALOGV("%s: group=%s indexMin=%d, indexMax=%d streams=%s attributes=%s", + __func__, name.c_str(), indexMin, indexMax, streamNames.c_str(), attrmNames.c_str( )); VolumeCurves groupVolumeCurves; size_t skipped = 0; deserializeCollection(doc, root, groupVolumeCurves, skipped); - volumes.push_back({ name, stream, indexMin, indexMax, groupVolumeCurves }); + volumes.push_back({ name, indexMin, indexMax, groupVolumeCurves }); return NO_ERROR; } @@ -580,8 +589,16 @@ static status_t deserializeLegacyVolumeCollection(_xmlDoc *doc, const _xmlNode * } } for (const auto &volumeMapIter : legacyVolumeMap) { - volumeGroups.push_back({ volumeMapIter.first, volumeMapIter.first, 0, 100, - volumeMapIter.second }); + // In order to let AudioService setting the min and max (compatibility), set Min and Max + // to -1 except for private streams + audio_stream_type_t streamType; + if (!StreamTypeConverter::fromString(volumeMapIter.first, streamType)) { + ALOGE("%s: Invalid stream %s", __func__, volumeMapIter.first.c_str()); + return BAD_VALUE; + } + int indexMin = streamType >= AUDIO_STREAM_PUBLIC_CNT ? 0 : -1; + int indexMax = streamType >= AUDIO_STREAM_PUBLIC_CNT ? 100 : -1; + volumeGroups.push_back({ volumeMapIter.first, indexMin, indexMax, volumeMapIter.second }); } return NO_ERROR; } diff --git a/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h b/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h index c9e9507705..07acd2e5a7 100644 --- a/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h +++ b/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h @@ -32,7 +32,7 @@ namespace android { using DeviceStrategyMap = std::map; using StrategyVector = std::vector; - +using VolumeGroupVector = std::vector; /** * This interface is dedicated to the policy manager that a Policy Engine shall implement. @@ -182,6 +182,7 @@ public: /** * @brief getAttributesForStream get the audio attributes from legacy stream type + * Attributes returned might only be used to check upon routing decision, not volume decisions. * @param stream to consider * @return audio attributes matching the legacy stream type */ @@ -241,14 +242,49 @@ public: * @param attr to be considered * @return IVolumeCurves interface pointer if found, nullptr otherwise */ - virtual IVolumeCurves *getVolumeCurvesForAttributes(const audio_attributes_t &attr) = 0; + virtual IVolumeCurves *getVolumeCurvesForAttributes(const audio_attributes_t &attr) const = 0; /** * @brief getVolumeCurvesForStreamType retrieves the Volume Curves interface for the stream * @param stream to be considered * @return IVolumeCurves interface pointer if found, nullptr otherwise */ - virtual IVolumeCurves *getVolumeCurvesForStreamType(audio_stream_type_t stream) = 0; + virtual IVolumeCurves *getVolumeCurvesForStreamType(audio_stream_type_t stream) const = 0; + + /** + * @brief getVolumeCurvesForVolumeGroup retrieves the Volume Curves interface for volume group + * @param group to be considered + * @return IVolumeCurves interface pointer if found, nullptr otherwise + */ + virtual IVolumeCurves *getVolumeCurvesForVolumeGroup(volume_group_t group) const = 0; + + /** + * @brief getVolumeGroups retrieves the collection of volume groups. + * @return vector of volume groups + */ + virtual VolumeGroupVector getVolumeGroups() const = 0; + + /** + * @brief getVolumeGroupForAttributes gets the appropriate volume group to be used for a given + * Audio Attributes. + * @param attr to be considered + * @return volume group associated to the given audio attributes, default group if none + * applicable, VOLUME_GROUP_NONE if no default group defined. + */ + virtual volume_group_t getVolumeGroupForAttributes(const audio_attributes_t &attr) const = 0; + + /** + * @brief getVolumeGroupForStreamType gets the appropriate volume group to be used for a given + * legacy stream type + * @param stream type to be considered + * @return volume group associated to the given stream type, default group if none applicable, + * VOLUME_GROUP_NONE if no default group defined. + */ + 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; virtual void dump(String8 *dst) const = 0; diff --git a/services/audiopolicy/engineconfigurable/Android.mk b/services/audiopolicy/engineconfigurable/Android.mk index 2b7e4c8dbc..4eff6e64d6 100644 --- a/services/audiopolicy/engineconfigurable/Android.mk +++ b/services/audiopolicy/engineconfigurable/Android.mk @@ -13,7 +13,7 @@ LOCAL_SRC_FILES := \ src/Stream.cpp \ src/InputSource.cpp \ ../engine/common/src/VolumeCurve.cpp \ - ../engine/common/src/StreamVolumeCurves.cpp \ + ../engine/common/src/VolumeGroup.cpp \ ../engine/common/src/ProductStrategy.cpp \ ../engine/common/src/EngineBase.cpp diff --git a/services/audiopolicy/engineconfigurable/config/example/Android.mk b/services/audiopolicy/engineconfigurable/config/example/Android.mk index ef476f765c..45419f04b1 100644 --- a/services/audiopolicy/engineconfigurable/config/example/Android.mk +++ b/services/audiopolicy/engineconfigurable/config/example/Android.mk @@ -72,7 +72,8 @@ LOCAL_SRC_FILES := automotive/$(LOCAL_MODULE_STEM) LOCAL_REQUIRED_MODULES := \ audio_policy_engine_product_strategies_automotive.xml \ audio_policy_engine_criteria.xml \ - audio_policy_engine_criterion_types.xml + audio_policy_engine_criterion_types.xml \ + audio_policy_engine_volumes.xml include $(BUILD_PREBUILT) @@ -89,6 +90,14 @@ LOCAL_VENDOR_MODULE := true LOCAL_SRC_FILES := automotive/$(LOCAL_MODULE_STEM) include $(BUILD_PREBUILT) +include $(CLEAR_VARS) +LOCAL_MODULE := audio_policy_engine_volumes.xml +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_CLASS := ETC +LOCAL_VENDOR_MODULE := true +LOCAL_SRC_FILES := automotive/$(LOCAL_MODULE) +include $(BUILD_PREBUILT) + endif #ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), automotive_configurable) ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),phone_configurable automotive_configurable)) diff --git a/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_configuration.xml b/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_configuration.xml index e2fb02b140..28a140a957 100644 --- a/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_configuration.xml +++ b/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_configuration.xml @@ -19,6 +19,7 @@ + diff --git a/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_product_strategies.xml b/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_product_strategies.xml index 543a2f0971..c487da9e24 100644 --- a/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_product_strategies.xml +++ b/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_product_strategies.xml @@ -31,7 +31,7 @@ limitations under the License. --> - + @@ -39,14 +39,14 @@ limitations under the License. - + - + @@ -70,21 +70,21 @@ limitations under the License. ( type == CAR_AUDIO_TYPE_RADIO ) ) --> - + - + - + @@ -96,7 +96,7 @@ limitations under the License. - + @@ -112,7 +112,7 @@ limitations under the License. - + @@ -121,29 +121,31 @@ limitations under the License. - + - + + + - + - + - + @@ -152,10 +154,17 @@ limitations under the License. - + - + + + + + + diff --git a/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_volumes.xml b/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_volumes.xml new file mode 100644 index 0000000000..b326b50de3 --- /dev/null +++ b/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_volumes.xml @@ -0,0 +1,192 @@ + + + + + + + + + oem_traffic_anouncement + 0 + 40 + + 0,-4200 + 33,-2800 + 66,-1400 + 100,0 + + + 0,-4200 + 33,-2800 + 66,-1400 + 100,0 + + + 0,-4200 + 33,-2800 + 66,-1400 + 100,0 + + + 0,-4200 + 33,-2800 + 66,-1400 + 100,0 + + + + + + oem_adas_2 + 0 + 40 + + 0,-4200 + 33,-2800 + 66,-1400 + 100,0 + + + 0,-4200 + 33,-2800 + 66,-1400 + 100,0 + + + + oem_adas_3 + 0 + 40 + + 0,-2400 + 33,-1600 + 66,-800 + 100,0 + + + 0,-2400 + 33,-1600 + 66,-800 + 100,0 + + + + + + media_car_audio_type_3 + 0 + 40 + + 0,-4200 + 33,-2800 + 66,-1400 + 100,0 + + + + media_car_audio_type_7 + 0 + 40 + + 0,-2400 + 33,-1600 + 66,-800 + 100,0 + + + + media + 0 + 40 + + 0,-2400 + 33,-1600 + 66,-800 + 100,0 + + + + + speech + 1 + 40 + + 0,-4200 + 33,-2800 + 66,-1400 + 100,0 + + + + + system + 0 + 40 + + 0,-4200 + 33,-2800 + 66,-1400 + 100,0 + + + + + phone + 1 + 40 + + 0,-4200 + 33,-2800 + 66,-1400 + 100,0 + + + + + ring + 0 + 40 + + 0,-4200 + 33,-2800 + 66,-1400 + 100,0 + + + + + tts + 0 + 15 + + 0,-0 + 100,0 + + + + diff --git a/services/audiopolicy/engineconfigurable/config/example/phone/audio_policy_engine_product_strategies.xml b/services/audiopolicy/engineconfigurable/config/example/phone/audio_policy_engine_product_strategies.xml index f72e37916d..939874353a 100644 --- a/services/audiopolicy/engineconfigurable/config/example/phone/audio_policy_engine_product_strategies.xml +++ b/services/audiopolicy/engineconfigurable/config/example/phone/audio_policy_engine_product_strategies.xml @@ -25,37 +25,37 @@ enforced. --> - + - + - + - + - + - + - + @@ -65,20 +65,20 @@ - + - + - + @@ -86,21 +86,21 @@ - + - + - + diff --git a/services/audiopolicy/engineconfigurable/config/example/phone/audio_policy_engine_stream_volumes.xml b/services/audiopolicy/engineconfigurable/config/example/phone/audio_policy_engine_stream_volumes.xml index 73bde1fb7e..707a18471c 100644 --- a/services/audiopolicy/engineconfigurable/config/example/phone/audio_policy_engine_stream_volumes.xml +++ b/services/audiopolicy/engineconfigurable/config/example/phone/audio_policy_engine_stream_volumes.xml @@ -16,7 +16,7 @@ - + - + - + - + - + - + - + @@ -65,20 +65,20 @@ - + - + - + @@ -86,21 +86,21 @@ - + - + - + diff --git a/services/audiopolicy/enginedefault/config/example/phone/audio_policy_engine_stream_volumes.xml b/services/audiopolicy/enginedefault/config/example/phone/audio_policy_engine_stream_volumes.xml index 73bde1fb7e..707a18471c 100644 --- a/services/audiopolicy/enginedefault/config/example/phone/audio_policy_engine_stream_volumes.xml +++ b/services/audiopolicy/enginedefault/config/example/phone/audio_policy_engine_stream_volumes.xml @@ -16,7 +16,7 @@