diff --git a/services/audiopolicy/common/managerdefinitions/Android.bp b/services/audiopolicy/common/managerdefinitions/Android.bp index e5ebab7e16..c9037a1daa 100644 --- a/services/audiopolicy/common/managerdefinitions/Android.bp +++ b/services/audiopolicy/common/managerdefinitions/Android.bp @@ -19,7 +19,6 @@ cc_library_static { "src/Serializer.cpp", "src/SoundTriggerSession.cpp", "src/TypeConverter.cpp", - "src/VolumeCurve.cpp", ], shared_libs: [ "libcutils", diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h index d52eb3d35c..2264d8f718 100644 --- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h +++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h @@ -20,7 +20,6 @@ #include #include -#include #include #include #include @@ -40,13 +39,11 @@ public: AudioPolicyConfig(HwModuleCollection &hwModules, DeviceVector &availableOutputDevices, DeviceVector &availableInputDevices, - sp &defaultOutputDevice, - VolumeCurvesCollection *volumes = nullptr) + sp &defaultOutputDevice) : mHwModules(hwModules), mAvailableOutputDevices(availableOutputDevices), mAvailableInputDevices(availableInputDevices), mDefaultOutputDevice(defaultOutputDevice), - mVolumeCurves(volumes), mIsSpeakerDrcEnabled(false) {} @@ -58,13 +55,6 @@ public: mSource = file; } - void setVolumes(const VolumeCurvesCollection &volumes) - { - if (mVolumeCurves != nullptr) { - *mVolumeCurves = volumes; - } - } - void setHwModules(const HwModuleCollection &hwModules) { mHwModules = hwModules; @@ -182,7 +172,6 @@ private: DeviceVector &mAvailableOutputDevices; DeviceVector &mAvailableInputDevices; sp &mDefaultOutputDevice; - VolumeCurvesCollection *mVolumeCurves; // TODO: remove when legacy conf file is removed. true on devices that use DRC on the // DEVICE_CATEGORY_SPEAKER path to boost soft sounds, used to adjust volume curves accordingly. // Note: remove also speaker_drc_enabled from global configuration of XML config file. diff --git a/services/audiopolicy/common/managerdefinitions/include/IVolumeCurves.h b/services/audiopolicy/common/managerdefinitions/include/IVolumeCurves.h new file mode 100644 index 0000000000..93022fb2a0 --- /dev/null +++ b/services/audiopolicy/common/managerdefinitions/include/IVolumeCurves.h @@ -0,0 +1,44 @@ +/* + * 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 + +namespace android { + +class IVolumeCurves +{ +public: + virtual ~IVolumeCurves() = default; + + virtual void clearCurrentVolumeIndex() = 0; + virtual void addCurrentVolumeIndex(audio_devices_t device, int index) = 0; + virtual bool canBeMuted() const = 0; + virtual int getVolumeIndexMin() const = 0; + virtual int getVolumeIndex(audio_devices_t device) const = 0; + virtual int getVolumeIndexMax() const = 0; + 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 void dump(String8 *dst, int spaces = 0, bool curvePoints = false) const = 0; +}; + +} // namespace android diff --git a/services/audiopolicy/common/managerdefinitions/include/IVolumeCurvesCollection.h b/services/audiopolicy/common/managerdefinitions/include/IVolumeCurvesCollection.h deleted file mode 100644 index 750da55519..0000000000 --- a/services/audiopolicy/common/managerdefinitions/include/IVolumeCurvesCollection.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2015 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 - -namespace android { - -class IVolumeCurvesCollection -{ -public: - virtual ~IVolumeCurvesCollection() = default; - - virtual void clearCurrentVolumeIndex(audio_stream_type_t stream) = 0; - virtual void addCurrentVolumeIndex(audio_stream_type_t stream, audio_devices_t device, - int index) = 0; - virtual bool canBeMuted(audio_stream_type_t stream) = 0; - virtual int getVolumeIndexMin(audio_stream_type_t stream) const = 0; - virtual int getVolumeIndex(audio_stream_type_t stream, audio_devices_t device) = 0; - virtual int getVolumeIndexMax(audio_stream_type_t stream) const = 0; - virtual float volIndexToDb(audio_stream_type_t stream, device_category device, - int indexInUi) const = 0; - virtual status_t initStreamVolume(audio_stream_type_t stream, int indexMin, int indexMax) = 0; - - virtual void initializeVolumeCurves(bool /*isSpeakerDrcEnabled*/) {} - virtual void switchVolumeCurve(audio_stream_type_t src, audio_stream_type_t dst) = 0; - virtual void restoreOriginVolumeCurve(audio_stream_type_t stream) - { - switchVolumeCurve(stream, stream); - } - virtual bool hasVolumeIndexForDevice(audio_stream_type_t stream, - audio_devices_t device) const = 0; - - virtual void dump(String8 *dst) const = 0; -}; - -} // namespace android diff --git a/services/audiopolicy/common/managerdefinitions/include/VolumeCurve.h b/services/audiopolicy/common/managerdefinitions/include/VolumeCurve.h deleted file mode 100644 index 76ec198d02..0000000000 --- a/services/audiopolicy/common/managerdefinitions/include/VolumeCurve.h +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright (C) 2015 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 "IVolumeCurvesCollection.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace android { - -struct CurvePoint -{ - CurvePoint() {} - CurvePoint(int index, int attenuationInMb) : - mIndex(index), mAttenuationInMb(attenuationInMb) {} - uint32_t mIndex; - int mAttenuationInMb; -}; - -inline bool operator< (const CurvePoint &lhs, const CurvePoint &rhs) -{ - return lhs.mIndex < rhs.mIndex; -} - -// A volume curve for a given use case and device category -// It contains of list of points of this curve expressing the attenuation in Millibels for -// a given volume index from 0 to 100 -class VolumeCurve : public RefBase -{ -public: - VolumeCurve(device_category device, audio_stream_type_t stream) : - mDeviceCategory(device), mStreamType(stream) {} - - device_category getDeviceCategory() const { return mDeviceCategory; } - audio_stream_type_t getStreamType() const { return mStreamType; } - - void add(const CurvePoint &point) { mCurvePoints.add(point); } - - float volIndexToDb(int indexInUi, int volIndexMin, int volIndexMax) const; - - void dump(String8 *result) const; - -private: - SortedVector mCurvePoints; - device_category mDeviceCategory; - audio_stream_type_t mStreamType; -}; - -// Volume Curves for a given use case indexed by device category -class VolumeCurvesForStream : public KeyedVector > -{ -public: - VolumeCurvesForStream() : mIndexMin(0), mIndexMax(1), mCanBeMuted(true) - { - mIndexCur.add(AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME, 0); - } - - sp getCurvesFor(device_category device) const - { - if (indexOfKey(device) < 0) { - return 0; - } - return valueFor(device); - } - - int getVolumeIndex(audio_devices_t device) const - { - device = Volume::getDeviceForVolume(device); - // there is always a valid entry for AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME - if (mIndexCur.indexOfKey(device) < 0) { - device = AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME; - } - return mIndexCur.valueFor(device); - } - - bool canBeMuted() const { return mCanBeMuted; } - void clearCurrentVolumeIndex() { mIndexCur.clear(); } - void addCurrentVolumeIndex(audio_devices_t device, int index) { mIndexCur.add(device, index); } - - void setVolumeIndexMin(int volIndexMin) { mIndexMin = volIndexMin; } - int getVolumeIndexMin() const { return mIndexMin; } - - void setVolumeIndexMax(int volIndexMax) { mIndexMax = volIndexMax; } - int getVolumeIndexMax() const { return mIndexMax; } - - bool hasVolumeIndexForDevice(audio_devices_t device) const - { - device = Volume::getDeviceForVolume(device); - return mIndexCur.indexOfKey(device) >= 0; - } - - const sp getOriginVolumeCurve(device_category deviceCategory) const - { - ALOG_ASSERT(mOriginVolumeCurves.indexOfKey(deviceCategory) >= 0, "Invalid device category"); - return mOriginVolumeCurves.valueFor(deviceCategory); - } - void setVolumeCurve(device_category deviceCategory, const sp &volumeCurve) - { - ALOG_ASSERT(indexOfKey(deviceCategory) >= 0, "Invalid device category for Volume Curve"); - replaceValueFor(deviceCategory, volumeCurve); - } - - ssize_t add(const sp &volumeCurve) - { - device_category deviceCategory = volumeCurve->getDeviceCategory(); - ssize_t index = indexOfKey(deviceCategory); - if (index < 0) { - // Keep track of original Volume Curves per device category in order to switch curves. - mOriginVolumeCurves.add(deviceCategory, volumeCurve); - return KeyedVector::add(deviceCategory, volumeCurve); - } - return index; - } - - float volIndexToDb(device_category deviceCat, int indexInUi) const - { - sp vc = getCurvesFor(deviceCat); - if (vc != 0) { - return vc->volIndexToDb(indexInUi, mIndexMin, mIndexMax); - } else { - ALOGE("Invalid device category %d for Volume Curve", deviceCat); - return 0.0f; - } - } - - void dump(String8 *dst, int spaces, bool curvePoints = false) const; - -private: - KeyedVector > mOriginVolumeCurves; - KeyedVector mIndexCur; /**< current volume index per device. */ - int mIndexMin; /**< min volume index. */ - int mIndexMax; /**< max volume index. */ - bool mCanBeMuted; /**< true is the stream can be muted. */ -}; - -// Collection of Volume Curves indexed by use case -class VolumeCurvesCollection : public KeyedVector, - public IVolumeCurvesCollection -{ -public: - VolumeCurvesCollection() - { - // Create an empty collection of curves - for (ssize_t i = 0 ; i < AUDIO_STREAM_CNT; i++) { - audio_stream_type_t stream = static_cast(i); - KeyedVector::add(stream, VolumeCurvesForStream()); - } - } - - // Once XML has been parsed, must be call first to sanity check table and initialize indexes - virtual status_t initStreamVolume(audio_stream_type_t stream, int indexMin, int indexMax) - { - editValueAt(stream).setVolumeIndexMin(indexMin); - editValueAt(stream).setVolumeIndexMax(indexMax); - return NO_ERROR; - } - virtual void clearCurrentVolumeIndex(audio_stream_type_t stream) - { - editCurvesFor(stream).clearCurrentVolumeIndex(); - } - virtual void addCurrentVolumeIndex(audio_stream_type_t stream, audio_devices_t device, int index) - { - editCurvesFor(stream).addCurrentVolumeIndex(device, index); - } - virtual bool canBeMuted(audio_stream_type_t stream) { return getCurvesFor(stream).canBeMuted(); } - - virtual int getVolumeIndexMin(audio_stream_type_t stream) const - { - return getCurvesFor(stream).getVolumeIndexMin(); - } - virtual int getVolumeIndexMax(audio_stream_type_t stream) const - { - return getCurvesFor(stream).getVolumeIndexMax(); - } - virtual int getVolumeIndex(audio_stream_type_t stream, audio_devices_t device) - { - return getCurvesFor(stream).getVolumeIndex(device); - } - virtual void switchVolumeCurve(audio_stream_type_t streamSrc, audio_stream_type_t streamDst) - { - const VolumeCurvesForStream &sourceCurves = getCurvesFor(streamSrc); - VolumeCurvesForStream &dstCurves = editCurvesFor(streamDst); - ALOG_ASSERT(sourceCurves.size() == dstCurves.size(), "device category not aligned"); - for (size_t index = 0; index < sourceCurves.size(); index++) { - device_category cat = sourceCurves.keyAt(index); - dstCurves.setVolumeCurve(cat, sourceCurves.getOriginVolumeCurve(cat)); - } - } - virtual float volIndexToDb(audio_stream_type_t stream, device_category cat, int indexInUi) const - { - return getCurvesFor(stream).volIndexToDb(cat, indexInUi); - } - virtual bool hasVolumeIndexForDevice(audio_stream_type_t stream, - audio_devices_t device) const - { - return getCurvesFor(stream).hasVolumeIndexForDevice(device); - } - - void dump(String8 *dst) const override; - - ssize_t add(const sp &volumeCurve) - { - audio_stream_type_t streamType = volumeCurve->getStreamType(); - return editCurvesFor(streamType).add(volumeCurve); - } - VolumeCurvesForStream &editCurvesFor(audio_stream_type_t stream) - { - ALOG_ASSERT(indexOfKey(stream) >= 0, "Invalid stream type for Volume Curve"); - return editValueAt(stream); - } - const VolumeCurvesForStream &getCurvesFor(audio_stream_type_t stream) const - { - ALOG_ASSERT(indexOfKey(stream) >= 0, "Invalid stream type for Volume Curve"); - return valueFor(stream); - } -}; - -} // namespace android diff --git a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp index 98d375c115..81d3968c76 100644 --- a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp +++ b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp @@ -201,25 +201,6 @@ struct GlobalConfigTraits static status_t deserialize(const xmlNode *root, AudioPolicyConfig *config); }; -struct VolumeTraits : public AndroidCollectionTraits -{ - static constexpr const char *tag = "volume"; - static constexpr const char *collectionTag = "volumes"; - static constexpr const char *volumePointTag = "point"; - static constexpr const char *referenceTag = "reference"; - - struct Attributes - { - static constexpr const char *stream = "stream"; - static constexpr const char *deviceCategory = "deviceCategory"; - static constexpr const char *reference = "ref"; - static constexpr const char *referenceName = "name"; - }; - - static Return deserialize(const xmlNode *cur, PtrSerializingCtx serializingContext); - // No Children -}; - struct SurroundSoundTraits { static constexpr const char *tag = "surroundSound"; @@ -703,67 +684,6 @@ status_t GlobalConfigTraits::deserialize(const xmlNode *root, AudioPolicyConfig return NO_ERROR; } -Return VolumeTraits::deserialize(const xmlNode *cur, - PtrSerializingCtx /*serializingContext*/) -{ - std::string streamTypeLiteral = getXmlAttribute(cur, Attributes::stream); - if (streamTypeLiteral.empty()) { - ALOGE("%s: No %s found", __func__, Attributes::stream); - return Status::fromStatusT(BAD_VALUE); - } - audio_stream_type_t streamType; - if (!StreamTypeConverter::fromString(streamTypeLiteral, streamType)) { - ALOGE("%s: Invalid %s", __func__, Attributes::stream); - return Status::fromStatusT(BAD_VALUE); - } - std::string deviceCategoryLiteral = getXmlAttribute(cur, Attributes::deviceCategory); - if (deviceCategoryLiteral.empty()) { - ALOGE("%s: No %s found", __func__, Attributes::deviceCategory); - return Status::fromStatusT(BAD_VALUE); - } - device_category deviceCategory; - if (!DeviceCategoryConverter::fromString(deviceCategoryLiteral, deviceCategory)) { - ALOGE("%s: Invalid %s=%s", __func__, Attributes::deviceCategory, - deviceCategoryLiteral.c_str()); - return Status::fromStatusT(BAD_VALUE); - } - - std::string referenceName = getXmlAttribute(cur, Attributes::reference); - const xmlNode *ref = NULL; - if (!referenceName.empty()) { - ref = getReference(cur->parent, referenceName); - if (ref == NULL) { - ALOGE("%s: No reference Ptr found for %s", __func__, referenceName.c_str()); - return Status::fromStatusT(BAD_VALUE); - } - } - - Element volCurve = new VolumeCurve(deviceCategory, streamType); - - for (const xmlNode *child = referenceName.empty() ? cur->xmlChildrenNode : ref->xmlChildrenNode; - child != NULL; child = child->next) { - if (!xmlStrcmp(child->name, reinterpret_cast(volumePointTag))) { - auto pointDefinition = make_xmlUnique(xmlNodeListGetString( - child->doc, child->xmlChildrenNode, 1)); - if (pointDefinition == nullptr) { - return Status::fromStatusT(BAD_VALUE); - } - ALOGV("%s: %s=%s", - __func__, tag, reinterpret_cast(pointDefinition.get())); - std::vector point; - collectionFromString>( - reinterpret_cast(pointDefinition.get()), point, ","); - if (point.size() != 2) { - ALOGE("%s: Invalid %s: %s", __func__, volumePointTag, - reinterpret_cast(pointDefinition.get())); - return Status::fromStatusT(BAD_VALUE); - } - volCurve->add(CurvePoint(point[0], point[1])); - } - } - return volCurve; -} - status_t SurroundSoundTraits::deserialize(const xmlNode *root, AudioPolicyConfig *config) { config->setDefaultSurroundFormats(); @@ -851,14 +771,6 @@ status_t PolicySerializer::deserialize(const char *configFile, AudioPolicyConfig } config->setHwModules(modules); - // deserialize volume section - VolumeTraits::Collection volumes; - status = deserializeCollection(root, &volumes, config); - if (status != NO_ERROR) { - return status; - } - config->setVolumes(volumes); - // Global Configuration GlobalConfigTraits::deserialize(root, config); diff --git a/services/audiopolicy/config/audio_policy_configuration.xml b/services/audiopolicy/config/audio_policy_configuration.xml index 42c52deec9..b4cc1d3936 100644 --- a/services/audiopolicy/config/audio_policy_configuration.xml +++ b/services/audiopolicy/config/audio_policy_configuration.xml @@ -191,7 +191,11 @@ - + diff --git a/services/audiopolicy/config/audio_policy_configuration_generic.xml b/services/audiopolicy/config/audio_policy_configuration_generic.xml index 40dcc22b58..9ad609df2b 100644 --- a/services/audiopolicy/config/audio_policy_configuration_generic.xml +++ b/services/audiopolicy/config/audio_policy_configuration_generic.xml @@ -30,7 +30,11 @@ - + diff --git a/services/audiopolicy/engine/common/include/EngineBase.h b/services/audiopolicy/engine/common/include/EngineBase.h index 5c33fb39b8..bc027e2a3f 100644 --- a/services/audiopolicy/engine/common/include/EngineBase.h +++ b/services/audiopolicy/engine/common/include/EngineBase.h @@ -19,6 +19,7 @@ #include #include #include +#include namespace android { namespace audio_policy { @@ -67,6 +68,10 @@ public: status_t listAudioProductStrategies(AudioProductStrategyVector &strategies) const override; + VolumeCurves *getVolumeCurvesForAttributes(const audio_attributes_t &attr) override; + + VolumeCurves *getVolumeCurvesForStreamType(audio_stream_type_t stream) override; + void dump(String8 *dst) const override; @@ -87,7 +92,16 @@ public: return is_state_in_call(getPhoneState()); } -private: + VolumeSource toVolumeSource(audio_stream_type_t stream) const + { + return static_cast(stream); + } + + status_t switchVolumeCurve(audio_stream_type_t streamSrc, audio_stream_type_t streamDst); + + status_t restoreOriginVolumeCurve(audio_stream_type_t stream); + + private: AudioPolicyManagerObserver *mApmObserver = nullptr; ProductStrategyMap mProductStrategies; @@ -95,6 +109,8 @@ private: /** 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/StreamVolumeCurves.h b/services/audiopolicy/engine/common/include/StreamVolumeCurves.h new file mode 100644 index 0000000000..5b0b7d6272 --- /dev/null +++ b/services/audiopolicy/engine/common/include/StreamVolumeCurves.h @@ -0,0 +1,95 @@ +/* + * 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 new file mode 100644 index 0000000000..0ec63e19fc --- /dev/null +++ b/services/audiopolicy/engine/common/include/VolumeCurve.h @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2015 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 "IVolumeCurves.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace android { + +struct CurvePoint +{ + CurvePoint() {} + CurvePoint(int index, int attenuationInMb) : + mIndex(index), mAttenuationInMb(attenuationInMb) {} + uint32_t mIndex; + int mAttenuationInMb; +}; + +inline bool operator< (const CurvePoint &lhs, const CurvePoint &rhs) +{ + return lhs.mIndex < rhs.mIndex; +} + +// A volume curve for a given use case and device category +// It contains of list of points of this curve expressing the attenuation in Millibels for +// a given volume index from 0 to 100 +class VolumeCurve : public RefBase +{ +public: + VolumeCurve(device_category device) : mDeviceCategory(device) {} + + void add(const CurvePoint &point) { mCurvePoints.add(point); } + + float volIndexToDb(int indexInUi, int volIndexMin, int volIndexMax) const; + + void dump(String8 *dst, int spaces = 0, bool curvePoints = false) const; + + device_category getDeviceCategory() const { return mDeviceCategory; } + +private: + const device_category mDeviceCategory; + SortedVector mCurvePoints; +}; + +// Volume Curves for a given use case indexed by device category +class VolumeCurves : public KeyedVector >, + public IVolumeCurves +{ +public: + VolumeCurves(int indexMin = 0, int indexMax = 100) : + mIndexMin(indexMin), mIndexMax(indexMax), mStream(AUDIO_STREAM_DEFAULT) + { + 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) + { + mIndexMin = indexMin; + mIndexMax = indexMax; + return NO_ERROR; + } + + sp getCurvesFor(device_category device) const + { + if (indexOfKey(device) < 0) { + return 0; + } + return valueFor(device); + } + + virtual int getVolumeIndex(audio_devices_t device) const + { + device = Volume::getDeviceForVolume(device); + // there is always a valid entry for AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME + if (mIndexCur.find(device) == end(mIndexCur)) { + device = AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME; + } + return mIndexCur.at(device); + } + + virtual bool canBeMuted() const { return mCanBeMuted; } + virtual void clearCurrentVolumeIndex() { mIndexCur.clear(); } + void addCurrentVolumeIndex(audio_devices_t device, int index) override + { + mIndexCur[device] = index; + } + + int getVolumeIndexMin() const { return mIndexMin; } + + int getVolumeIndexMax() const { return mIndexMax; } + + bool hasVolumeIndexForDevice(audio_devices_t device) const + { + device = Volume::getDeviceForVolume(device); + return mIndexCur.find(device) != end(mIndexCur); + } + + status_t switchCurvesFrom(const VolumeCurves &referenceCurves) + { + if (size() != referenceCurves.size()) { + ALOGE("%s! device category not aligned, cannot switch", __FUNCTION__); + return BAD_TYPE; + } + for (size_t index = 0; index < size(); index++) { + device_category cat = keyAt(index); + setVolumeCurve(cat, referenceCurves.getOriginVolumeCurve(cat)); + } + return NO_ERROR; + } + status_t restoreOriginVolumeCurve() + { + return switchCurvesFrom(*this); + } + + const sp getOriginVolumeCurve(device_category deviceCategory) const + { + ALOG_ASSERT(mOriginVolumeCurves.indexOfKey(deviceCategory) >= 0, "Invalid device category"); + return mOriginVolumeCurves.valueFor(deviceCategory); + } + void setVolumeCurve(device_category deviceCategory, const sp &volumeCurve) + { + ALOG_ASSERT(indexOfKey(deviceCategory) >= 0, "Invalid device category for Volume Curve"); + replaceValueFor(deviceCategory, volumeCurve); + } + + ssize_t add(const sp &volumeCurve) + { + device_category deviceCategory = volumeCurve->getDeviceCategory(); + ssize_t index = indexOfKey(deviceCategory); + if (index < 0) { + // Keep track of original Volume Curves per device category in order to switch curves. + mOriginVolumeCurves.add(deviceCategory, volumeCurve); + return KeyedVector::add(deviceCategory, volumeCurve); + } + return index; + } + + virtual float volIndexToDb(device_category deviceCat, int indexInUi) const + { + sp vc = getCurvesFor(deviceCat); + if (vc != 0) { + return vc->volIndexToDb(indexInUi, mIndexMin, mIndexMax); + } else { + ALOGE("Invalid device category %d for Volume Curve", deviceCat); + return 0.0f; + } + } + + audio_stream_type_t getStreamType() const { return mStream; } + + void dump(String8 *dst, int spaces = 0, bool curvePoints = false) const override; + +private: + KeyedVector > mOriginVolumeCurves; + std::map mIndexCur; /**< current volume index per device. */ + int mIndexMin; /**< min volume index. */ + 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. */ +}; + +} // namespace android diff --git a/services/audiopolicy/engine/common/src/EngineBase.cpp b/services/audiopolicy/engine/common/src/EngineBase.cpp index 755f2a88e3..6e2ab4cdfa 100644 --- a/services/audiopolicy/engine/common/src/EngineBase.cpp +++ b/services/audiopolicy/engine/common/src/EngineBase.cpp @@ -55,8 +55,10 @@ status_t EngineBase::setPhoneState(audio_mode_t state) if (!is_state_in_call(oldState) && is_state_in_call(state)) { ALOGV(" Entering call in setPhoneState()"); + switchVolumeCurve(AUDIO_STREAM_VOICE_CALL, AUDIO_STREAM_DTMF); } else if (is_state_in_call(oldState) && !is_state_in_call(state)) { ALOGV(" Exiting call in setPhoneState()"); + restoreOriginVolumeCurve(AUDIO_STREAM_DTMF); } return NO_ERROR; } @@ -108,14 +110,43 @@ engineConfig::ParsingResult EngineBase::loadAudioPolicyEngineConfig() 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)) { + ALOGE("%s: Invalid %s", __FUNCTION__, configCurve.deviceCategory.c_str()); + continue; + } + sp curve = new VolumeCurve(deviceCategory); + for (auto &point : configCurve.curvePoints) { + curve->add({point.index, point.attenuationInMb}); + } + volumeCurves.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__); - result = {std::make_unique(gDefaultEngineConfig), 0}; + engineConfig::Config config = gDefaultEngineConfig; + android::status_t ret = engineConfig::parseLegacyVolumes(config.volumeGroups); + result = {std::make_unique(config), + 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); return result; } @@ -173,9 +204,30 @@ status_t EngineBase::listAudioProductStrategies(AudioProductStrategyVector &stra return NO_ERROR; } +VolumeCurves *EngineBase::getVolumeCurvesForAttributes(const audio_attributes_t &attr) +{ + return &mStreamVolumeCurves.getVolumeCurvesForStream(getStreamTypeForAttributes(attr)); +} + +VolumeCurves *EngineBase::getVolumeCurvesForStreamType(audio_stream_type_t stream) +{ + return &mStreamVolumeCurves.getVolumeCurvesForStream(stream); +} + +status_t EngineBase::switchVolumeCurve(audio_stream_type_t streamSrc, audio_stream_type_t streamDst) +{ + return mStreamVolumeCurves.switchVolumeCurve(streamSrc, streamDst);; +} + +status_t EngineBase::restoreOriginVolumeCurve(audio_stream_type_t stream) +{ + return mStreamVolumeCurves.restoreOriginVolumeCurve(stream); +} + void EngineBase::dump(String8 *dst) const { mProductStrategies.dump(dst, 2); + mStreamVolumeCurves.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 3940c0c929..f1642c5e3c 100644 --- a/services/audiopolicy/engine/common/src/EngineDefaultConfig.h +++ b/services/audiopolicy/engine/common/src/EngineDefaultConfig.h @@ -135,6 +135,7 @@ const engineConfig::Config gDefaultEngineConfig = { 1.0, gOrderedStrategies, {}, + {}, {} }; } // namespace android diff --git a/services/audiopolicy/engine/common/src/StreamVolumeCurves.cpp b/services/audiopolicy/engine/common/src/StreamVolumeCurves.cpp new file mode 100644 index 0000000000..fe3b0007b6 --- /dev/null +++ b/services/audiopolicy/engine/common/src/StreamVolumeCurves.cpp @@ -0,0 +1,47 @@ +/* + * 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/common/managerdefinitions/src/VolumeCurve.cpp b/services/audiopolicy/engine/common/src/VolumeCurve.cpp similarity index 68% rename from services/audiopolicy/common/managerdefinitions/src/VolumeCurve.cpp rename to services/audiopolicy/engine/common/src/VolumeCurve.cpp index 2625733f20..be2ca730ef 100644 --- a/services/audiopolicy/common/managerdefinitions/src/VolumeCurve.cpp +++ b/services/audiopolicy/engine/common/src/VolumeCurve.cpp @@ -64,8 +64,7 @@ float VolumeCurve::volIndexToDb(int indexInUi, int volIndexMin, int volIndexMax) ((float)(mCurvePoints[indexInUiPosition].mIndex - mCurvePoints[indexInUiPosition - 1].mIndex)) ); - ALOGV("VOLUME mDeviceCategory %d, mStreamType %d vol index=[%d %d %d], dB=[%.1f %.1f %.1f]", - mDeviceCategory, mStreamType, + ALOGV("VOLUME vol index=[%d %d %d], dB=[%.1f %.1f %.1f]", mCurvePoints[indexInUiPosition - 1].mIndex, volIdx, mCurvePoints[indexInUiPosition].mIndex, ((float)mCurvePoints[indexInUiPosition - 1].mAttenuationInMb / 100.0f), decibels, @@ -74,55 +73,35 @@ float VolumeCurve::volIndexToDb(int indexInUi, int volIndexMin, int volIndexMax) return decibels; } -void VolumeCurve::dump(String8 *dst) const +void VolumeCurve::dump(String8 *dst, int spaces, bool curvePoints) const { + if (!curvePoints) { + return; + } dst->append(" {"); for (size_t i = 0; i < mCurvePoints.size(); i++) { - dst->appendFormat("(%3d, %5d)", + dst->appendFormat("%*s (%3d, %5d)", spaces, "", mCurvePoints[i].mIndex, mCurvePoints[i].mAttenuationInMb); - dst->append(i == (mCurvePoints.size() - 1) ? " }\n" : ", "); + dst->appendFormat(i == (mCurvePoints.size() - 1) ? " }\n" : ", "); } } -void VolumeCurvesForStream::dump(String8 *dst, int spaces = 0, bool curvePoints) const +void VolumeCurves::dump(String8 *dst, int spaces, bool curvePoints) const { if (!curvePoints) { - dst->appendFormat("%s %02d %02d ", - mCanBeMuted ? "true " : "false", mIndexMin, mIndexMax); - for (size_t i = 0; i < mIndexCur.size(); i++) { - dst->appendFormat("%04x : %02d, ", mIndexCur.keyAt(i), mIndexCur.valueAt(i)); + dst->appendFormat("%*s%02d %s %03d %03d ", spaces, "", + mStream, mCanBeMuted ? "true " : "false", mIndexMin, mIndexMax); + for (const auto &pair : mIndexCur) { + dst->appendFormat("%*s %04x : %02d, ", spaces, "", pair.first, pair.second); } - dst->append("\n"); + dst->appendFormat("\n"); return; } - 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); - } - dst->append("\n"); -} - -void VolumeCurvesCollection::dump(String8 *dst) const -{ - dst->append("\nStreams dump:\n"); - dst->append( - " Stream Can be muted Index Min Index Max Index Cur [device : index]...\n"); - for (size_t i = 0; i < size(); i++) { - dst->appendFormat(" %02zu ", i); - valueAt(i).dump(dst); - } - dst->append("\nVolume Curves for Use Cases (aka Stream types) dump:\n"); - for (size_t i = 0; i < size(); i++) { - std::string streamTypeLiteral; - StreamTypeConverter::toString(keyAt(i), streamTypeLiteral); - dst->appendFormat( - " %s (%02zu): Curve points for device category (index, attenuation in millibel)\n", - streamTypeLiteral.c_str(), i); - valueAt(i).dump(dst, 2, true); + dst->appendFormat("%*s %s :", spaces, "", deviceCatLiteral.c_str()); + valueAt(i)->dump(dst, 2, true); } } diff --git a/services/audiopolicy/engine/config/Android.mk b/services/audiopolicy/engine/config/Android.mk index fe7d961799..0b292a5fa3 100644 --- a/services/audiopolicy/engine/config/Android.mk +++ b/services/audiopolicy/engine/config/Android.mk @@ -23,7 +23,8 @@ LOCAL_SHARED_LIBRARIES := \ libandroidicu \ libxml2 \ libutils \ - liblog + liblog \ + libcutils LOCAL_STATIC_LIBRARIES := \ libaudiopolicycomponents diff --git a/services/audiopolicy/engine/config/include/EngineConfig.h b/services/audiopolicy/engine/config/include/EngineConfig.h index e18f68759d..a188115fff 100644 --- a/services/audiopolicy/engine/config/include/EngineConfig.h +++ b/services/audiopolicy/engine/config/include/EngineConfig.h @@ -45,6 +45,27 @@ struct AttributesGroup { using AttributesGroups = std::vector; +struct CurvePoint { + int index; + int attenuationInMb; +}; +using CurvePoints = std::vector; + +struct VolumeCurve { + std::string deviceCategory; + CurvePoints curvePoints; +}; +using VolumeCurves = std::vector; + +struct VolumeGroup { + std::string name; + std::string stream; + int indexMin; + int indexMax; + VolumeCurves volumeCurves; +}; +using VolumeGroups = std::vector; + struct ProductStrategy { std::string name; AttributesGroups attributesGroups; @@ -78,6 +99,7 @@ struct Config { ProductStrategies productStrategies; Criteria criteria; CriterionTypes criterionTypes; + VolumeGroups volumeGroups; }; /** Result of `parse(const char*)` */ @@ -91,6 +113,7 @@ struct ParsingResult { * @return audio policy usage @see Config */ ParsingResult parse(const char* path = DEFAULT_PATH); +android::status_t parseLegacyVolumes(VolumeGroups &volumeGroups); } // namespace engineConfig } // namespace android diff --git a/services/audiopolicy/engine/config/src/EngineConfig.cpp b/services/audiopolicy/engine/config/src/EngineConfig.cpp index 3aa38cf965..00fbac411b 100644 --- a/services/audiopolicy/engine/config/src/EngineConfig.cpp +++ b/services/audiopolicy/engine/config/src/EngineConfig.cpp @@ -19,6 +19,7 @@ #include "EngineConfig.h" #include +#include #include #include #include @@ -26,6 +27,7 @@ #include #include #include +#include #include #include @@ -107,6 +109,35 @@ struct CriterionTraits : public BaseSerializerTraits { static android::status_t deserialize(_xmlDoc *doc, const _xmlNode *root, Collection &collection); }; +struct VolumeTraits : public BaseSerializerTraits { + static constexpr const char *tag = "volume"; + static constexpr const char *collectionTag = "volumes"; + static constexpr const char *volumePointTag = "point"; + + struct Attributes { + static constexpr const char *deviceCategory = "deviceCategory"; + static constexpr const char *reference = "ref"; /**< For volume curves factorization. */ + }; + + static android::status_t deserialize(_xmlDoc *doc, const _xmlNode *root, + Collection &collection); +}; +struct VolumeGroupTraits : public BaseSerializerTraits { + static constexpr const char *tag = "volumeGroup"; + static constexpr const char *collectionTag = "volumeGroups"; + + struct Attributes { + static constexpr const char *name = "name"; + static constexpr const char *stream = "stream"; // For legacy volume curves + static constexpr const char *indexMin = "indexMin"; + static constexpr const char *indexMax = "indexMax"; + }; + + static android::status_t deserialize(_xmlDoc *doc, const _xmlNode *root, + Collection &collection); +}; + +using xmlCharUnique = std::unique_ptr; using xmlCharUnique = std::unique_ptr; @@ -383,6 +414,178 @@ status_t ProductStrategyTraits::deserialize(_xmlDoc *doc, const _xmlNode *child, return NO_ERROR; } +status_t VolumeTraits::deserialize(_xmlDoc *doc, const _xmlNode *root, Collection &volumes) +{ + std::string deviceCategory = getXmlAttribute(root, Attributes::deviceCategory); + 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()) { + getReference(xmlDocGetRootElement(doc), ref, referenceName, collectionTag); + if (ref == NULL) { + ALOGE("%s: No reference Ptr found for %s", __FUNCTION__, referenceName.c_str()); + return BAD_VALUE; + } + } + // Retrieve curve point from reference element if found or directly from current curve + CurvePoints curvePoints; + for (const xmlNode *child = referenceName.empty() ? + root->xmlChildrenNode : ref->xmlChildrenNode; child != NULL; child = child->next) { + if (!xmlStrcmp(child->name, (const xmlChar *)volumePointTag)) { + xmlCharUnique pointXml(xmlNodeListGetString(doc, child->xmlChildrenNode, 1), xmlFree); + if (pointXml == NULL) { + return BAD_VALUE; + } + ALOGV("%s: %s=%s", __func__, tag, reinterpret_cast(pointXml.get())); + std::vector point; + collectionFromString>( + reinterpret_cast(pointXml.get()), point, ","); + if (point.size() != 2) { + ALOGE("%s: Invalid %s: %s", __func__, volumePointTag, + reinterpret_cast(pointXml.get())); + return BAD_VALUE; + } + curvePoints.push_back({point[0], point[1]}); + } + } + volumes.push_back({ deviceCategory, curvePoints }); + return NO_ERROR; +} + +status_t VolumeGroupTraits::deserialize(_xmlDoc *doc, const _xmlNode *root, Collection &volumes) +{ + std::string name; + std::string stream = {}; + int indexMin = 0; + int indexMax = 0; + + for (const xmlNode *child = root->xmlChildrenNode; child != NULL; child = child->next) { + if (not xmlStrcmp(child->name, (const xmlChar *)Attributes::name)) { + xmlCharUnique nameXml(xmlNodeListGetString(doc, child->xmlChildrenNode, 1), xmlFree); + if (nameXml == nullptr) { + return BAD_VALUE; + } + 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) { + return BAD_VALUE; + } + std::string indexMinLiteral(reinterpret_cast(indexMinXml.get())); + if (!convertTo(indexMinLiteral, indexMin)) { + return BAD_VALUE; + } + } + if (not xmlStrcmp(child->name, (const xmlChar *)Attributes::indexMax)) { + xmlCharUnique indexMaxXml(xmlNodeListGetString(doc, child->xmlChildrenNode, 1), xmlFree); + if (indexMaxXml == nullptr) { + return BAD_VALUE; + } + std::string indexMaxLiteral(reinterpret_cast(indexMaxXml.get())); + if (!convertTo(indexMaxLiteral, indexMax)) { + return BAD_VALUE; + } + } + } + ALOGV("%s: group=%s stream=%s indexMin=%d, indexMax=%d", + __func__, name.c_str(), stream.c_str(), indexMin, indexMax); + + VolumeCurves groupVolumeCurves; + size_t skipped = 0; + deserializeCollection(doc, root, groupVolumeCurves, skipped); + volumes.push_back({ name, stream, indexMin, indexMax, groupVolumeCurves }); + return NO_ERROR; +} + +static constexpr const char *legacyVolumecollectionTag = "volumes"; +static constexpr const char *legacyVolumeTag = "volume"; + +status_t deserializeLegacyVolume(_xmlDoc *doc, const _xmlNode *cur, + std::map &legacyVolumes) +{ + std::string streamTypeLiteral = getXmlAttribute(cur, "stream"); + if (streamTypeLiteral.empty()) { + ALOGE("%s: No attribute stream found", __func__); + return BAD_VALUE; + } + std::string deviceCategoryLiteral = getXmlAttribute(cur, "deviceCategory"); + if (deviceCategoryLiteral.empty()) { + ALOGE("%s: No attribute deviceCategory found", __func__); + return BAD_VALUE; + } + std::string referenceName = getXmlAttribute(cur, "ref"); + const xmlNode *ref = NULL; + if (!referenceName.empty()) { + getReference(xmlDocGetRootElement(doc), ref, referenceName, legacyVolumecollectionTag); + if (ref == NULL) { + ALOGE("%s: No reference Ptr found for %s", __func__, referenceName.c_str()); + return BAD_VALUE; + } + ALOGV("%s: reference found for %s", __func__, referenceName.c_str()); + } + CurvePoints curvePoints; + for (const xmlNode *child = referenceName.empty() ? + cur->xmlChildrenNode : ref->xmlChildrenNode; child != NULL; child = child->next) { + if (!xmlStrcmp(child->name, (const xmlChar *)VolumeTraits::volumePointTag)) { + xmlCharUnique pointXml(xmlNodeListGetString(doc, child->xmlChildrenNode, 1), xmlFree); + if (pointXml == NULL) { + return BAD_VALUE; + } + ALOGV("%s: %s=%s", __func__, legacyVolumeTag, + reinterpret_cast(pointXml.get())); + std::vector point; + collectionFromString>( + reinterpret_cast(pointXml.get()), point, ","); + if (point.size() != 2) { + ALOGE("%s: Invalid %s: %s", __func__, VolumeTraits::volumePointTag, + reinterpret_cast(pointXml.get())); + return BAD_VALUE; + } + curvePoints.push_back({point[0], point[1]}); + } + } + legacyVolumes[streamTypeLiteral].push_back({ deviceCategoryLiteral, curvePoints }); + return NO_ERROR; +} + +static status_t deserializeLegacyVolumeCollection(_xmlDoc *doc, const _xmlNode *cur, + VolumeGroups &volumeGroups, + size_t &nbSkippedElement) +{ + std::map legacyVolumeMap; + for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { + if (xmlStrcmp(cur->name, (const xmlChar *)legacyVolumecollectionTag)) { + continue; + } + const xmlNode *child = cur->xmlChildrenNode; + for (; child != NULL; child = child->next) { + if (!xmlStrcmp(child->name, (const xmlChar *)legacyVolumeTag)) { + + status_t status = deserializeLegacyVolume(doc, child, legacyVolumeMap); + if (status != NO_ERROR) { + nbSkippedElement += 1; + } + } + } + } + for (const auto &volumeMapIter : legacyVolumeMap) { + volumeGroups.push_back({ volumeMapIter.first, volumeMapIter.first, 0, 100, + volumeMapIter.second }); + } + return NO_ERROR; +} + ParsingResult parse(const char* path) { xmlDocPtr doc; doc = xmlParseFile(path); @@ -414,8 +617,66 @@ ParsingResult parse(const char* path) { doc, cur, config->criteria, nbSkippedElements); deserializeCollection( doc, cur, config->criterionTypes, nbSkippedElements); + deserializeCollection( + doc, cur, config->volumeGroups, nbSkippedElements); + return {std::move(config), nbSkippedElements}; } +android::status_t parseLegacyVolumeFile(const char* path, VolumeGroups &volumeGroups) { + xmlDocPtr doc; + doc = xmlParseFile(path); + if (doc == NULL) { + ALOGE("%s: Could not parse document %s", __FUNCTION__, path); + return BAD_VALUE; + } + xmlNodePtr cur = xmlDocGetRootElement(doc); + if (cur == NULL) { + ALOGE("%s: Could not parse: empty document %s", __FUNCTION__, path); + xmlFreeDoc(doc); + return BAD_VALUE; + } + if (xmlXIncludeProcess(doc) < 0) { + ALOGE("%s: libxml failed to resolve XIncludes on document %s", __FUNCTION__, path); + return BAD_VALUE; + } + size_t nbSkippedElements = 0; + return deserializeLegacyVolumeCollection(doc, cur, volumeGroups, nbSkippedElements); +} + +static const char *kConfigLocationList[] = {"/odm/etc", "/vendor/etc", "/system/etc"}; +static const int kConfigLocationListSize = + (sizeof(kConfigLocationList) / sizeof(kConfigLocationList[0])); +static const int gApmXmlConfigFilePathMaxLength = 128; + +static constexpr const char *apmXmlConfigFileName = "audio_policy_configuration.xml"; +static constexpr const char *apmA2dpOffloadDisabledXmlConfigFileName = + "audio_policy_configuration_a2dp_offload_disabled.xml"; + +android::status_t parseLegacyVolumes(VolumeGroups &volumeGroups) { + char audioPolicyXmlConfigFile[gApmXmlConfigFilePathMaxLength]; + std::vector fileNames; + status_t ret; + + if (property_get_bool("ro.bluetooth.a2dp_offload.supported", false) && + property_get_bool("persist.bluetooth.a2dp_offload.disabled", false)) { + // A2DP offload supported but disabled: try to use special XML file + fileNames.push_back(apmA2dpOffloadDisabledXmlConfigFileName); + } + fileNames.push_back(apmXmlConfigFileName); + + for (const char* fileName : fileNames) { + for (int i = 0; i < kConfigLocationListSize; i++) { + snprintf(audioPolicyXmlConfigFile, sizeof(audioPolicyXmlConfigFile), + "%s/%s", kConfigLocationList[i], fileName); + ret = parseLegacyVolumeFile(audioPolicyXmlConfigFile, volumeGroups); + if (ret == NO_ERROR) { + return ret; + } + } + } + return BAD_VALUE; +} + } // namespace engineConfig } // namespace android diff --git a/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h b/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h index 498cc3bf82..c9e9507705 100644 --- a/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h +++ b/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -234,6 +235,21 @@ public: */ virtual status_t listAudioProductStrategies(AudioProductStrategyVector &strategies) const = 0; + /** + * @brief getVolumeCurvesForAttributes retrieves the Volume Curves interface for the + * requested Audio Attributes. + * @param attr to be considered + * @return IVolumeCurves interface pointer if found, nullptr otherwise + */ + virtual IVolumeCurves *getVolumeCurvesForAttributes(const audio_attributes_t &attr) = 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 void dump(String8 *dst) const = 0; protected: diff --git a/services/audiopolicy/engine/interface/AudioPolicyManagerObserver.h b/services/audiopolicy/engine/interface/AudioPolicyManagerObserver.h index b7902cf2e5..43ba625f9c 100644 --- a/services/audiopolicy/engine/interface/AudioPolicyManagerObserver.h +++ b/services/audiopolicy/engine/interface/AudioPolicyManagerObserver.h @@ -16,7 +16,6 @@ #pragma once -#include #include #include #include @@ -51,8 +50,6 @@ public: virtual const DeviceVector &getAvailableInputDevices() const = 0; - virtual IVolumeCurvesCollection &getVolumeCurves() = 0; - virtual const sp &getDefaultOutputDevice() const = 0; protected: diff --git a/services/audiopolicy/engineconfigurable/Android.mk b/services/audiopolicy/engineconfigurable/Android.mk index bbd9688529..2b7e4c8dbc 100644 --- a/services/audiopolicy/engineconfigurable/Android.mk +++ b/services/audiopolicy/engineconfigurable/Android.mk @@ -12,6 +12,8 @@ LOCAL_SRC_FILES := \ src/EngineInstance.cpp \ src/Stream.cpp \ src/InputSource.cpp \ + ../engine/common/src/VolumeCurve.cpp \ + ../engine/common/src/StreamVolumeCurves.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 95a2ecc08d..ef476f765c 100644 --- a/services/audiopolicy/engineconfigurable/config/example/Android.mk +++ b/services/audiopolicy/engineconfigurable/config/example/Android.mk @@ -20,6 +20,8 @@ LOCAL_SRC_FILES := phone/$(LOCAL_MODULE_STEM) LOCAL_REQUIRED_MODULES := \ audio_policy_engine_product_strategies_phone.xml \ + audio_policy_engine_stream_volumes.xml \ + audio_policy_engine_default_stream_volumes.xml \ audio_policy_engine_criteria.xml \ audio_policy_engine_criterion_types.xml @@ -34,6 +36,22 @@ LOCAL_VENDOR_MODULE := true LOCAL_SRC_FILES := phone/$(LOCAL_MODULE_STEM) include $(BUILD_PREBUILT) +include $(CLEAR_VARS) +LOCAL_MODULE := audio_policy_engine_stream_volumes.xml +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_CLASS := ETC +LOCAL_VENDOR_MODULE := true +LOCAL_SRC_FILES := phone/$(LOCAL_MODULE) +include $(BUILD_PREBUILT) + +include $(CLEAR_VARS) +LOCAL_MODULE := audio_policy_engine_default_stream_volumes.xml +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_CLASS := ETC +LOCAL_VENDOR_MODULE := true +LOCAL_SRC_FILES := phone/$(LOCAL_MODULE) +include $(BUILD_PREBUILT) + endif # ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), phone_configurable) diff --git a/services/audiopolicy/engineconfigurable/config/example/phone/audio_policy_engine_configuration.xml b/services/audiopolicy/engineconfigurable/config/example/phone/audio_policy_engine_configuration.xml index ab61d8a937..4ca33b4525 100644 --- a/services/audiopolicy/engineconfigurable/config/example/phone/audio_policy_engine_configuration.xml +++ b/services/audiopolicy/engineconfigurable/config/example/phone/audio_policy_engine_configuration.xml @@ -17,6 +17,8 @@ + + diff --git a/services/audiopolicy/engineconfigurable/config/example/phone/audio_policy_engine_default_stream_volumes.xml b/services/audiopolicy/engineconfigurable/config/example/phone/audio_policy_engine_default_stream_volumes.xml new file mode 100644 index 0000000000..21e6dd58ac --- /dev/null +++ b/services/audiopolicy/engineconfigurable/config/example/phone/audio_policy_engine_default_stream_volumes.xml @@ -0,0 +1,136 @@ + + + + + + + + 0,0 + 100,0 + + + 0,-9600 + 100,-9600 + + + + 1,-2400 + 33,-1800 + 66,-1200 + 100,-600 + + + + 1,-5800 + 20,-4000 + 60,-1700 + 100,0 + + + + 1,-4950 + 33,-3350 + 66,-1700 + 100,0 + + + + 1,-5800 + 20,-4000 + 60,-1700 + 100,0 + + + + 1,-4680 + 42,-2070 + 85,-540 + 100,0 + + + + 1,-4950 + 33,-3350 + 66,-1700 + 100,0 + + + + 1,-5800 + 20,-4000 + 60,-2100 + 100,-1000 + + + + 1,-12700 + 20,-8000 + 60,-4000 + 100,0 + + + + + + + + + 0,-5800 + 20,-4000 + 60,-1700 + 100,0 + + + + + 0,-4950 + 33,-3350 + 66,-1700 + 100,0 + + + + + 0,-5800 + 20,-4000 + 60,-1700 + 100,0 + + + + + 0,-4950 + 33,-3350 + 66,-1700 + 100,0 + + + + + 0,-5800 + 20,-4000 + 60,-2100 + 100,-1000 + + + + + 0,-12700 + 20,-8000 + 60,-4000 + 100,0 + + 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 new file mode 100644 index 0000000000..73bde1fb7e --- /dev/null +++ b/services/audiopolicy/engineconfigurable/config/example/phone/audio_policy_engine_stream_volumes.xml @@ -0,0 +1,231 @@ + + + + + + + AUDIO_STREAM_VOICE_CALL + 1 + 7 + + 0,-4200 + 33,-2800 + 66,-1400 + 100,0 + + + 0,-2400 + 33,-1600 + 66,-800 + 100,0 + + + 0,-2700 + 33,-1800 + 66,-900 + 100,0 + + + + + + + AUDIO_STREAM_SYSTEM + 0 + 7 + + 1,-3000 + 33,-2600 + 66,-2200 + 100,-1800 + + + 1,-5100 + 57,-2800 + 71,-2500 + 85,-2300 + 100,-2100 + + + + + + + + + AUDIO_STREAM_RING + 0 + 7 + + + + + + + + + AUDIO_STREAM_MUSIC + 0 + 25 + + + + + + + + + AUDIO_STREAM_ALARM + 1 + 7 + + + + + + + + + AUDIO_STREAM_NOTIFICATION + 0 + 7 + + + + + + + + + AUDIO_STREAM_BLUETOOTH_SCO + 0 + 15 + + 0,-4200 + 33,-2800 + 66,-1400 + 100,0 + + + 0,-2400 + 33,-1600 + 66,-800 + 100,0 + + + 0,-4200 + 33,-2800 + 66,-1400 + 100,0 + + + + + + + AUDIO_STREAM_ENFORCED_AUDIBLE + 0 + 7 + + 1,-3000 + 33,-2600 + 66,-2200 + 100,-1800 + + + 1,-3400 + 71,-2400 + 100,-2000 + + + + + + + + + AUDIO_STREAM_DTMF + 0 + 15 + + 1,-3000 + 33,-2600 + 66,-2200 + 100,-1800 + + + 1,-4000 + 71,-2400 + 100,-1400 + + + + + + + + + AUDIO_STREAM_TTS + 0 + 15 + + + + + + + + + AUDIO_STREAM_ACCESSIBILITY + 1 + 15 + + + + + + + + + AUDIO_STREAM_REROUTING + 0 + 1 + + + + + + + + + AUDIO_STREAM_PATCH + 0 + 1 + + + + + + + + diff --git a/services/audiopolicy/engineconfigurable/src/Engine.cpp b/services/audiopolicy/engineconfigurable/src/Engine.cpp index 719ef01031..89a1694a92 100644 --- a/services/audiopolicy/engineconfigurable/src/Engine.cpp +++ b/services/audiopolicy/engineconfigurable/src/Engine.cpp @@ -113,7 +113,7 @@ bool Engine::setVolumeProfileForStream(const audio_stream_type_t &stream, const audio_stream_type_t &profile) { if (setPropertyForKey(stream, profile)) { - getApmObserver()->getVolumeCurves().switchVolumeCurve(profile, stream); + switchVolumeCurve(profile, stream); return true; } return false; diff --git a/services/audiopolicy/enginedefault/Android.mk b/services/audiopolicy/enginedefault/Android.mk index 95eac1c17e..94fa788a90 100644 --- a/services/audiopolicy/enginedefault/Android.mk +++ b/services/audiopolicy/enginedefault/Android.mk @@ -8,6 +8,8 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := \ src/Engine.cpp \ src/EngineInstance.cpp \ + ../engine/common/src/VolumeCurve.cpp \ + ../engine/common/src/StreamVolumeCurves.cpp \ ../engine/common/src/ProductStrategy.cpp \ ../engine/common/src/EngineBase.cpp diff --git a/services/audiopolicy/enginedefault/config/example/Android.mk b/services/audiopolicy/enginedefault/config/example/Android.mk index 866466fc14..f06ee4cf13 100644 --- a/services/audiopolicy/enginedefault/config/example/Android.mk +++ b/services/audiopolicy/enginedefault/config/example/Android.mk @@ -16,7 +16,9 @@ LOCAL_VENDOR_MODULE := true LOCAL_SRC_FILES := phone/$(LOCAL_MODULE_STEM) LOCAL_REQUIRED_MODULES := \ - audio_policy_engine_product_strategies_phone.xml + audio_policy_engine_product_strategies_phone.xml \ + audio_policy_engine_stream_volumes.xml \ + audio_policy_engine_default_stream_volumes.xml include $(BUILD_PREBUILT) @@ -29,4 +31,20 @@ LOCAL_VENDOR_MODULE := true LOCAL_SRC_FILES := phone/$(LOCAL_MODULE_STEM) include $(BUILD_PREBUILT) +include $(CLEAR_VARS) +LOCAL_MODULE := audio_policy_engine_stream_volumes.xml +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_CLASS := ETC +LOCAL_VENDOR_MODULE := true +LOCAL_SRC_FILES := phone/$(LOCAL_MODULE) +include $(BUILD_PREBUILT) + +include $(CLEAR_VARS) +LOCAL_MODULE := audio_policy_engine_default_stream_volumes.xml +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_CLASS := ETC +LOCAL_VENDOR_MODULE := true +LOCAL_SRC_FILES := phone/$(LOCAL_MODULE) +include $(BUILD_PREBUILT) + endif # ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), phone_default) diff --git a/services/audiopolicy/enginedefault/config/example/phone/audio_policy_engine_configuration.xml b/services/audiopolicy/enginedefault/config/example/phone/audio_policy_engine_configuration.xml index ab61d8a937..4ca33b4525 100644 --- a/services/audiopolicy/enginedefault/config/example/phone/audio_policy_engine_configuration.xml +++ b/services/audiopolicy/enginedefault/config/example/phone/audio_policy_engine_configuration.xml @@ -17,6 +17,8 @@ + + diff --git a/services/audiopolicy/enginedefault/config/example/phone/audio_policy_engine_default_stream_volumes.xml b/services/audiopolicy/enginedefault/config/example/phone/audio_policy_engine_default_stream_volumes.xml new file mode 100644 index 0000000000..21e6dd58ac --- /dev/null +++ b/services/audiopolicy/enginedefault/config/example/phone/audio_policy_engine_default_stream_volumes.xml @@ -0,0 +1,136 @@ + + + + + + + + 0,0 + 100,0 + + + 0,-9600 + 100,-9600 + + + + 1,-2400 + 33,-1800 + 66,-1200 + 100,-600 + + + + 1,-5800 + 20,-4000 + 60,-1700 + 100,0 + + + + 1,-4950 + 33,-3350 + 66,-1700 + 100,0 + + + + 1,-5800 + 20,-4000 + 60,-1700 + 100,0 + + + + 1,-4680 + 42,-2070 + 85,-540 + 100,0 + + + + 1,-4950 + 33,-3350 + 66,-1700 + 100,0 + + + + 1,-5800 + 20,-4000 + 60,-2100 + 100,-1000 + + + + 1,-12700 + 20,-8000 + 60,-4000 + 100,0 + + + + + + + + + 0,-5800 + 20,-4000 + 60,-1700 + 100,0 + + + + + 0,-4950 + 33,-3350 + 66,-1700 + 100,0 + + + + + 0,-5800 + 20,-4000 + 60,-1700 + 100,0 + + + + + 0,-4950 + 33,-3350 + 66,-1700 + 100,0 + + + + + 0,-5800 + 20,-4000 + 60,-2100 + 100,-1000 + + + + + 0,-12700 + 20,-8000 + 60,-4000 + 100,0 + + 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 new file mode 100644 index 0000000000..73bde1fb7e --- /dev/null +++ b/services/audiopolicy/enginedefault/config/example/phone/audio_policy_engine_stream_volumes.xml @@ -0,0 +1,231 @@ + + + + + + + AUDIO_STREAM_VOICE_CALL + 1 + 7 + + 0,-4200 + 33,-2800 + 66,-1400 + 100,0 + + + 0,-2400 + 33,-1600 + 66,-800 + 100,0 + + + 0,-2700 + 33,-1800 + 66,-900 + 100,0 + + + + + + + AUDIO_STREAM_SYSTEM + 0 + 7 + + 1,-3000 + 33,-2600 + 66,-2200 + 100,-1800 + + + 1,-5100 + 57,-2800 + 71,-2500 + 85,-2300 + 100,-2100 + + + + + + + + + AUDIO_STREAM_RING + 0 + 7 + + + + + + + + + AUDIO_STREAM_MUSIC + 0 + 25 + + + + + + + + + AUDIO_STREAM_ALARM + 1 + 7 + + + + + + + + + AUDIO_STREAM_NOTIFICATION + 0 + 7 + + + + + + + + + AUDIO_STREAM_BLUETOOTH_SCO + 0 + 15 + + 0,-4200 + 33,-2800 + 66,-1400 + 100,0 + + + 0,-2400 + 33,-1600 + 66,-800 + 100,0 + + + 0,-4200 + 33,-2800 + 66,-1400 + 100,0 + + + + + + + AUDIO_STREAM_ENFORCED_AUDIBLE + 0 + 7 + + 1,-3000 + 33,-2600 + 66,-2200 + 100,-1800 + + + 1,-3400 + 71,-2400 + 100,-2000 + + + + + + + + + AUDIO_STREAM_DTMF + 0 + 15 + + 1,-3000 + 33,-2600 + 66,-2200 + 100,-1800 + + + 1,-4000 + 71,-2400 + 100,-1400 + + + + + + + + + AUDIO_STREAM_TTS + 0 + 15 + + + + + + + + + AUDIO_STREAM_ACCESSIBILITY + 1 + 15 + + + + + + + + + AUDIO_STREAM_REROUTING + 0 + 1 + + + + + + + + + AUDIO_STREAM_PATCH + 0 + 1 + + + + + + + + diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp index 504f1c6357..f191738eec 100644 --- a/services/audiopolicy/enginedefault/src/Engine.cpp +++ b/services/audiopolicy/enginedefault/src/Engine.cpp @@ -66,35 +66,6 @@ Engine::Engine() } } -status_t Engine::setPhoneState(audio_mode_t state) -{ - ALOGV("setPhoneState() state %d", state); - - if (state < 0 || state >= AUDIO_MODE_CNT) { - ALOGW("setPhoneState() invalid state %d", state); - return BAD_VALUE; - } - - if (state == getPhoneState()) { - ALOGW("setPhoneState() setting same state %d", state); - return BAD_VALUE; - } - - // store previous phone state for management of sonification strategy below - int oldState = getPhoneState(); - EngineBase::setPhoneState(state); - - if (!is_state_in_call(oldState) && is_state_in_call(state)) { - ALOGV(" Entering call in setPhoneState()"); - getApmObserver()->getVolumeCurves().switchVolumeCurve(AUDIO_STREAM_VOICE_CALL, - AUDIO_STREAM_DTMF); - } else if (is_state_in_call(oldState) && !is_state_in_call(state)) { - ALOGV(" Exiting call in setPhoneState()"); - getApmObserver()->getVolumeCurves().restoreOriginVolumeCurve(AUDIO_STREAM_DTMF); - } - return NO_ERROR; -} - status_t Engine::setForceUse(audio_policy_force_use_t usage, audio_policy_forced_cfg_t config) { switch(usage) { diff --git a/services/audiopolicy/enginedefault/src/Engine.h b/services/audiopolicy/enginedefault/src/Engine.h index 15fc358687..d8a369891d 100644 --- a/services/audiopolicy/enginedefault/src/Engine.h +++ b/services/audiopolicy/enginedefault/src/Engine.h @@ -55,8 +55,6 @@ private: /// /// from EngineBase, so from AudioPolicyManagerInterface /// - status_t setPhoneState(audio_mode_t mode) override; - status_t setForceUse(audio_policy_force_use_t usage, audio_policy_forced_cfg_t config) override; diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp index 5b752ead9a..b563a042b2 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp @@ -1710,7 +1710,7 @@ status_t AudioPolicyManager::startSource(const sp& outp // apply volume rules for current stream and device if necessary checkAndSetVolume(stream, - mVolumeCurves->getVolumeIndex(stream, outputDesc->devices().types()), + getVolumeCurves(stream).getVolumeIndex(outputDesc->devices().types()), outputDesc, outputDesc->devices().types()); @@ -2382,14 +2382,15 @@ void AudioPolicyManager::initStreamVolume(audio_stream_type_t stream, ALOGE("%s for stream %d: invalid min %d or max %d", __func__, stream , indexMin, indexMax); return; } - mVolumeCurves->initStreamVolume(stream, indexMin, indexMax); + // @todo: our proposal now use XML to store Indexes Min & Max + getVolumeCurves(stream).initVolume(indexMin, indexMax); // initialize 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; } - mVolumeCurves->initStreamVolume((audio_stream_type_t)curStream, indexMin, indexMax); + getVolumeCurves((audio_stream_type_t)curStream).initVolume(indexMin, indexMax); } } @@ -2397,13 +2398,13 @@ 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 < mVolumeCurves->getVolumeIndexMin(stream)) && + if (((index < curves.getVolumeIndexMin()) && !((stream == AUDIO_STREAM_VOICE_CALL || stream == AUDIO_STREAM_BLUETOOTH_SCO) && index == 0)) || - (index > mVolumeCurves->getVolumeIndexMax(stream))) { + (index > curves.getVolumeIndexMax())) { return BAD_VALUE; } if (!audio_is_output_device(device)) { @@ -2411,7 +2412,7 @@ status_t AudioPolicyManager::setStreamVolumeIndex(audio_stream_type_t stream, } // Force max volume if stream cannot be muted - if (!mVolumeCurves->canBeMuted(stream)) index = mVolumeCurves->getVolumeIndexMax(stream); + if (!curves.canBeMuted()) index = curves.getVolumeIndexMax(); ALOGV("setStreamVolumeIndex() stream %d, device %08x, index %d", stream, device, index); @@ -2421,7 +2422,8 @@ status_t AudioPolicyManager::setStreamVolumeIndex(audio_stream_type_t stream, if (!streamsMatchForvolume(stream, (audio_stream_type_t)curStream)) { continue; } - mVolumeCurves->addCurrentVolumeIndex((audio_stream_type_t)curStream, device, index); + auto &curCurves = getVolumeCurves(static_cast(curStream)); + curCurves.addCurrentVolumeIndex(device, index); } // update volume on all outputs and streams matching the following: @@ -2455,8 +2457,7 @@ status_t AudioPolicyManager::setStreamVolumeIndex(audio_stream_type_t stream, curStreamDevice |= device; applyVolume = (Volume::getDeviceForVolume(curDevice) & curStreamDevice) != 0; } else { - applyVolume = !mVolumeCurves->hasVolumeIndexForDevice( - stream, curStreamDevice); + applyVolume = !curves.hasVolumeIndexForDevice(curStreamDevice); } // rescale index before applying to curStream as ranges may be different for // stream and curStream @@ -2465,9 +2466,10 @@ status_t AudioPolicyManager::setStreamVolumeIndex(audio_stream_type_t stream, //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); + 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; } @@ -2494,7 +2496,7 @@ status_t AudioPolicyManager::getStreamVolumeIndex(audio_stream_type_t stream, } device = Volume::getDeviceForVolume(device); - *index = mVolumeCurves->getVolumeIndex(stream, device); + *index = getVolumeCurves(stream).getVolumeIndex(device); ALOGV("getStreamVolumeIndex() stream %d device %08x index %d", stream, device, *index); return NO_ERROR; } @@ -2927,7 +2929,6 @@ void AudioPolicyManager::dump(String8 *dst) const mHwModulesAll.dump(dst); mOutputs.dump(dst); mInputs.dump(dst); - mVolumeCurves->dump(dst); mEffects.dump(dst); mAudioPatches.dump(dst); mPolicyMixes.dump(dst); @@ -4114,9 +4115,7 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa mpClientInterface(clientInterface), mLimitRingtoneVolume(false), mLastVoiceVolume(-1.0f), mA2dpSuspended(false), - mVolumeCurves(new VolumeCurvesCollection()), - mConfig(mHwModulesAll, mAvailableOutputDevices, mAvailableInputDevices, - mDefaultOutputDevice, static_cast(mVolumeCurves.get())), + mConfig(mHwModulesAll, mAvailableOutputDevices, mAvailableInputDevices, mDefaultOutputDevice), mAudioPortGeneration(1), mBeaconMuteRefCount(0), mBeaconPlayingRefCount(0), @@ -4150,8 +4149,6 @@ void AudioPolicyManager::loadConfig() { } status_t AudioPolicyManager::initialize() { - mVolumeCurves->initializeVolumeCurves(getConfig().isSpeakerDrcEnabled()); - // Once policy config has been parsed, retrieve an instance of the engine and initialize it. audio_policy::EngineInstance *engineInstance = audio_policy::EngineInstance::getInstance(); if (!engineInstance) { @@ -5532,7 +5529,8 @@ float AudioPolicyManager::computeVolume(audio_stream_type_t stream, int index, audio_devices_t device) { - float volumeDB = mVolumeCurves->volIndexToDb(stream, Volume::getDeviceCategory(device), index); + 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 @@ -5557,8 +5555,7 @@ float AudioPolicyManager::computeVolume(audio_stream_type_t stream, case AUDIO_STREAM_ENFORCED_AUDIBLE: case AUDIO_STREAM_DTMF: case AUDIO_STREAM_ACCESSIBILITY: { - int voiceVolumeIndex = - mVolumeCurves->getVolumeIndex(AUDIO_STREAM_VOICE_CALL, device); + int voiceVolumeIndex = getVolumeCurves(AUDIO_STREAM_VOICE_CALL).getVolumeIndex(device); const float maxVoiceVolDb = computeVolume(AUDIO_STREAM_VOICE_CALL, voiceVolumeIndex, device) + IN_CALL_EARPIECE_HEADROOM_DB; @@ -5592,7 +5589,7 @@ float AudioPolicyManager::computeVolume(audio_stream_type_t stream, || ((stream == AUDIO_STREAM_ENFORCED_AUDIBLE) && (mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_NONE))) && - mVolumeCurves->canBeMuted(stream)) { + getVolumeCurves(stream).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 @@ -5603,9 +5600,8 @@ float AudioPolicyManager::computeVolume(audio_stream_type_t stream, mEngine->getOutputDevicesForAttributes(attributes_initializer(AUDIO_USAGE_MEDIA), nullptr, true /*fromCache*/).types(); float musicVolDB = computeVolume(AUDIO_STREAM_MUSIC, - mVolumeCurves->getVolumeIndex(AUDIO_STREAM_MUSIC, - musicDevice), - musicDevice); + getVolumeCurves(AUDIO_STREAM_MUSIC).getVolumeIndex(musicDevice), + musicDevice); float minVolDB = (musicVolDB > SONIFICATION_HEADSET_VOLUME_MIN_DB) ? musicVolDB : SONIFICATION_HEADSET_VOLUME_MIN_DB; if (volumeDB > minVolDB) { @@ -5640,10 +5636,12 @@ int AudioPolicyManager::rescaleVolumeIndex(int srcIndex, if (srcStream == dstStream) { return srcIndex; } - float minSrc = (float)mVolumeCurves->getVolumeIndexMin(srcStream); - float maxSrc = (float)mVolumeCurves->getVolumeIndexMax(srcStream); - float minDst = (float)mVolumeCurves->getVolumeIndexMin(dstStream); - float maxDst = (float)mVolumeCurves->getVolumeIndexMax(dstStream); + auto &srcCurves = getVolumeCurves(srcStream); + auto &dstCurves = getVolumeCurves(dstStream); + float minSrc = (float)srcCurves.getVolumeIndexMin(); + float maxSrc = (float)srcCurves.getVolumeIndexMax(); + float minDst = (float)dstCurves.getVolumeIndexMin(); + float maxDst = (float)dstCurves.getVolumeIndexMax(); // preserve mute request or correct range if (srcIndex < minSrc) { @@ -5658,11 +5656,11 @@ int AudioPolicyManager::rescaleVolumeIndex(int srcIndex, } status_t AudioPolicyManager::checkAndSetVolume(audio_stream_type_t stream, - int index, - const sp& outputDesc, - audio_devices_t device, - int delayMs, - bool force) + 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))) { @@ -5698,7 +5696,7 @@ status_t AudioPolicyManager::checkAndSetVolume(audio_stream_type_t stream, 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)mVolumeCurves->getVolumeIndexMax(stream); + voiceVolume = (float)index/(float)getVolumeCurves(stream).getVolumeIndexMax(); } else { voiceVolume = 1.0; } @@ -5721,7 +5719,7 @@ void AudioPolicyManager::applyStreamVolumes(const sp& out for (int stream = 0; stream < AUDIO_STREAM_FOR_POLICY_CNT; stream++) { checkAndSetVolume((audio_stream_type_t)stream, - mVolumeCurves->getVolumeIndex((audio_stream_type_t)stream, device), + getVolumeCurves((audio_stream_type_t)stream).getVolumeIndex(device), outputDesc, device, delayMs, @@ -5754,10 +5752,10 @@ void AudioPolicyManager::setStreamMute(audio_stream_type_t stream, ALOGVV("setStreamMute() stream %d, mute %d, mMuteCount %d device %04x", stream, on, outputDesc->getMuteCount(stream), device); - + auto &curves = getVolumeCurves(stream); if (on) { if (!outputDesc->isMuted(streamToVolumeSource(stream))) { - if (mVolumeCurves->canBeMuted(stream) && + 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); @@ -5772,7 +5770,7 @@ void AudioPolicyManager::setStreamMute(audio_stream_type_t stream, } if (outputDesc->decMuteCount(streamToVolumeSource(stream)) == 0) { checkAndSetVolume(stream, - mVolumeCurves->getVolumeIndex(stream, device), + curves.getVolumeIndex(device), outputDesc, device, delayMs); diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h index 70ad6ac7aa..06a1f3e416 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.h +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h @@ -49,7 +49,7 @@ #include #include #include -#include +#include "TypeConverter.h" namespace android { @@ -310,12 +310,24 @@ protected: { return mAvailableInputDevices; } - virtual IVolumeCurvesCollection &getVolumeCurves() { return *mVolumeCurves; } virtual const sp &getDefaultOutputDevice() const { return mDefaultOutputDevice; } + IVolumeCurves &getVolumeCurves(const audio_attributes_t &attr) + { + auto *curves = mEngine->getVolumeCurvesForAttributes(attr); + ALOG_ASSERT(curves != nullptr, "No curves for attributes %s", toString(attr).c_str()); + return *curves; + } + IVolumeCurves &getVolumeCurves(audio_stream_type_t stream) + { + auto *curves = mEngine->getVolumeCurvesForStreamType(stream); + ALOG_ASSERT(curves != nullptr, "No curves for stream %s", toString(stream).c_str()); + return *curves; + } + void addOutput(audio_io_handle_t output, const sp& outputDesc); void removeOutput(audio_io_handle_t output); void addInput(audio_io_handle_t input, const sp& inputDesc); @@ -624,12 +636,12 @@ protected: float mLastVoiceVolume; // last voice volume value sent to audio HAL bool mA2dpSuspended; // true if A2DP output is suspended - std::unique_ptr mVolumeCurves; // Volume Curves per use case and device category EffectDescriptorCollection mEffects; // list of registered audio effects sp mDefaultOutputDevice; // output device selected by default at boot time HwModuleCollection mHwModules; // contains only modules that have been loaded successfully HwModuleCollection mHwModulesAll; // normally not needed, used during construction and for // dumps + AudioPolicyConfig mConfig; std::atomic mAudioPortGeneration;