Merge changes from topic "policy_volume_emulator"

* changes:
  Revert "Revert "audiopolicy: engine: use apm XML config file for volume curves""
  Revert "Revert "audiopolicy: moves Stream Volume Curves to Engine""
gugelfrei
Eric Laurent 5 years ago committed by Android (Google) Code Review
commit ea69bfb0f5

@ -19,7 +19,6 @@ cc_library_static {
"src/Serializer.cpp",
"src/SoundTriggerSession.cpp",
"src/TypeConverter.cpp",
"src/VolumeCurve.cpp",
],
shared_libs: [
"libcutils",

@ -20,7 +20,6 @@
#include <unordered_set>
#include <AudioGain.h>
#include <VolumeCurve.h>
#include <AudioPort.h>
#include <AudioPatch.h>
#include <DeviceDescriptor.h>
@ -40,13 +39,11 @@ public:
AudioPolicyConfig(HwModuleCollection &hwModules,
DeviceVector &availableOutputDevices,
DeviceVector &availableInputDevices,
sp<DeviceDescriptor> &defaultOutputDevice,
VolumeCurvesCollection *volumes = nullptr)
sp<DeviceDescriptor> &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<DeviceDescriptor> &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.

@ -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 <system/audio.h>
#include <Volume.h>
#include <utils/Errors.h>
#include <utils/String8.h>
#include <vector>
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

@ -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 <system/audio.h>
#include <Volume.h>
#include <utils/Errors.h>
#include <utils/String8.h>
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

@ -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 <policy.h>
#include <utils/RefBase.h>
#include <utils/String8.h>
#include <utils/SortedVector.h>
#include <utils/KeyedVector.h>
#include <system/audio.h>
#include <cutils/config_utils.h>
#include <string>
#include <utility>
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<CurvePoint> mCurvePoints;
device_category mDeviceCategory;
audio_stream_type_t mStreamType;
};
// Volume Curves for a given use case indexed by device category
class VolumeCurvesForStream : public KeyedVector<device_category, sp<VolumeCurve> >
{
public:
VolumeCurvesForStream() : mIndexMin(0), mIndexMax(1), mCanBeMuted(true)
{
mIndexCur.add(AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME, 0);
}
sp<VolumeCurve> 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<VolumeCurve> 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> &volumeCurve)
{
ALOG_ASSERT(indexOfKey(deviceCategory) >= 0, "Invalid device category for Volume Curve");
replaceValueFor(deviceCategory, volumeCurve);
}
ssize_t add(const sp<VolumeCurve> &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<VolumeCurve> 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<device_category, sp<VolumeCurve> > mOriginVolumeCurves;
KeyedVector<audio_devices_t, int> 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<audio_stream_type_t, VolumeCurvesForStream>,
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<audio_stream_type_t>(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> &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

@ -201,25 +201,6 @@ struct GlobalConfigTraits
static status_t deserialize(const xmlNode *root, AudioPolicyConfig *config);
};
struct VolumeTraits : public AndroidCollectionTraits<VolumeCurve, VolumeCurvesCollection>
{
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<Element> 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::Element> 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<VolumeTraits>(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<const xmlChar*>(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<const char*>(pointDefinition.get()));
std::vector<int32_t> point;
collectionFromString<DefaultTraits<int32_t>>(
reinterpret_cast<const char*>(pointDefinition.get()), point, ",");
if (point.size() != 2) {
ALOGE("%s: Invalid %s: %s", __func__, volumePointTag,
reinterpret_cast<const char*>(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<VolumeTraits>(root, &volumes, config);
if (status != NO_ERROR) {
return status;
}
config->setVolumes(volumes);
// Global Configuration
GlobalConfigTraits::deserialize(root, config);

@ -191,7 +191,11 @@
</modules>
<!-- End of Modules section -->
<!-- Volume section -->
<!-- Volume section:
IMPORTANT NOTE: Volume tables have been moved to engine configuration.
Keep it here for legacy.
Engine will fallback on these files if none are provided by engine.
-->
<xi:include href="audio_policy_volumes.xml"/>
<xi:include href="default_volume_tables.xml"/>

@ -30,7 +30,11 @@
</modules>
<!-- End of Modules section -->
<!-- Volume section -->
<!-- Volume section:
IMPORTANT NOTE: Volume tables have been moved to engine configuration.
Keep it here for legacy.
Engine will fallback on these files if none are provided by engine.
-->
<xi:include href="audio_policy_volumes.xml"/>
<xi:include href="default_volume_tables.xml"/>

@ -19,6 +19,7 @@
#include <EngineConfig.h>
#include <AudioPolicyManagerInterface.h>
#include <ProductStrategy.h>
#include <StreamVolumeCurves.h>
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<VolumeSource>(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

@ -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 <VolumeCurve.h>
#include <map>
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<audio_stream_type_t, VolumeCurves> mCurves;
};
} // namespace android

@ -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 <policy.h>
#include <utils/RefBase.h>
#include <utils/String8.h>
#include <utils/SortedVector.h>
#include <utils/KeyedVector.h>
#include <system/audio.h>
#include <cutils/config_utils.h>
#include <string>
#include <map>
#include <utility>
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<CurvePoint> mCurvePoints;
};
// Volume Curves for a given use case indexed by device category
class VolumeCurves : public KeyedVector<device_category, sp<VolumeCurve> >,
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<VolumeCurve> 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<VolumeCurve> 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> &volumeCurve)
{
ALOG_ASSERT(indexOfKey(deviceCategory) >= 0, "Invalid device category for Volume Curve");
replaceValueFor(deviceCategory, volumeCurve);
}
ssize_t add(const sp<VolumeCurve> &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<VolumeCurve> 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<device_category, sp<VolumeCurve> > mOriginVolumeCurves;
std::map<audio_devices_t, int> 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

@ -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<VolumeCurve> 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<engineConfig::Config>(gDefaultEngineConfig), 0};
engineConfig::Config config = gDefaultEngineConfig;
android::status_t ret = engineConfig::parseLegacyVolumes(config.volumeGroups);
result = {std::make_unique<engineConfig::Config>(config),
static_cast<size_t>(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

@ -135,6 +135,7 @@ const engineConfig::Config gDefaultEngineConfig = {
1.0,
gOrderedStrategies,
{},
{},
{}
};
} // namespace android

@ -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 <TypeConverter.h>
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

@ -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);
}
}

@ -23,7 +23,8 @@ LOCAL_SHARED_LIBRARIES := \
libandroidicu \
libxml2 \
libutils \
liblog
liblog \
libcutils
LOCAL_STATIC_LIBRARIES := \
libaudiopolicycomponents

@ -45,6 +45,27 @@ struct AttributesGroup {
using AttributesGroups = std::vector<AttributesGroup>;
struct CurvePoint {
int index;
int attenuationInMb;
};
using CurvePoints = std::vector<CurvePoint>;
struct VolumeCurve {
std::string deviceCategory;
CurvePoints curvePoints;
};
using VolumeCurves = std::vector<VolumeCurve>;
struct VolumeGroup {
std::string name;
std::string stream;
int indexMin;
int indexMax;
VolumeCurves volumeCurves;
};
using VolumeGroups = std::vector<VolumeGroup>;
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

@ -19,6 +19,7 @@
#include "EngineConfig.h"
#include <policy.h>
#include <cutils/properties.h>
#include <media/TypeConverter.h>
#include <media/convert.h>
#include <utils/Log.h>
@ -26,6 +27,7 @@
#include <libxml/xinclude.h>
#include <string>
#include <vector>
#include <map>
#include <sstream>
#include <istream>
@ -107,6 +109,35 @@ struct CriterionTraits : public BaseSerializerTraits<Criterion, Criteria> {
static android::status_t deserialize(_xmlDoc *doc, const _xmlNode *root,
Collection &collection);
};
struct VolumeTraits : public BaseSerializerTraits<VolumeCurve, VolumeCurves> {
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<VolumeGroup, VolumeGroups> {
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<xmlChar, decltype(xmlFree)>;
using xmlCharUnique = std::unique_ptr<xmlChar, decltype(xmlFree)>;
@ -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<const char*>(pointXml.get()));
std::vector<int> point;
collectionFromString<DefaultTraits<int>>(
reinterpret_cast<const char*>(pointXml.get()), point, ",");
if (point.size() != 2) {
ALOGE("%s: Invalid %s: %s", __func__, volumePointTag,
reinterpret_cast<const char*>(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<const char*>(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<const char*>(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<const char*>(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<const char*>(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<VolumeTraits>(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<std::string, VolumeCurves> &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<const char*>(pointXml.get()));
std::vector<int> point;
collectionFromString<DefaultTraits<int>>(
reinterpret_cast<const char*>(pointXml.get()), point, ",");
if (point.size() != 2) {
ALOGE("%s: Invalid %s: %s", __func__, VolumeTraits::volumePointTag,
reinterpret_cast<const char*>(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<std::string, VolumeCurves> 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<CriterionTypeTraits>(
doc, cur, config->criterionTypes, nbSkippedElements);
deserializeCollection<VolumeGroupTraits>(
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<const char *> 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

@ -18,6 +18,7 @@
#include <AudioPolicyManagerObserver.h>
#include <media/AudioProductStrategy.h>
#include <IVolumeCurves.h>
#include <policy.h>
#include <Volume.h>
#include <HwModule.h>
@ -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:

@ -16,7 +16,6 @@
#pragma once
#include <IVolumeCurvesCollection.h>
#include <AudioGain.h>
#include <AudioPort.h>
#include <AudioPatch.h>
@ -51,8 +50,6 @@ public:
virtual const DeviceVector &getAvailableInputDevices() const = 0;
virtual IVolumeCurvesCollection &getVolumeCurves() = 0;
virtual const sp<DeviceDescriptor> &getDefaultOutputDevice() const = 0;
protected:

@ -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

@ -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)

@ -17,6 +17,8 @@
<configuration version="1.0" xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include href="audio_policy_engine_product_strategies.xml"/>
<xi:include href="audio_policy_engine_stream_volumes.xml"/>
<xi:include href="audio_policy_engine_default_stream_volumes.xml"/>
</configuration>

@ -0,0 +1,136 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- 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.
-->
<!-- Default Volume Tables included by Audio Policy Configuration file -->
<!-- Full Default Volume table for all device category -->
<volumes>
<reference name="FULL_SCALE_VOLUME_CURVE">
<!-- Full Scale reference Volume Curve -->
<point>0,0</point>
<point>100,0</point>
</reference>
<reference name="SILENT_VOLUME_CURVE">
<point>0,-9600</point>
<point>100,-9600</point>
</reference>
<reference name="DEFAULT_SYSTEM_VOLUME_CURVE">
<!-- Default System reference Volume Curve -->
<point>1,-2400</point>
<point>33,-1800</point>
<point>66,-1200</point>
<point>100,-600</point>
</reference>
<reference name="DEFAULT_MEDIA_VOLUME_CURVE">
<!-- Default Media reference Volume Curve -->
<point>1,-5800</point>
<point>20,-4000</point>
<point>60,-1700</point>
<point>100,0</point>
</reference>
<reference name="DEFAULT_DEVICE_CATEGORY_HEADSET_VOLUME_CURVE">
<!--Default Volume Curve -->
<point>1,-4950</point>
<point>33,-3350</point>
<point>66,-1700</point>
<point>100,0</point>
</reference>
<reference name="DEFAULT_DEVICE_CATEGORY_SPEAKER_VOLUME_CURVE">
<!-- Default is Speaker Media Volume Curve -->
<point>1,-5800</point>
<point>20,-4000</point>
<point>60,-1700</point>
<point>100,0</point>
</reference>
<reference name="DEFAULT_DEVICE_CATEGORY_SPEAKER_SYSTEM_VOLUME_CURVE">
<!-- Default is Speaker System Volume Curve -->
<point>1,-4680</point>
<point>42,-2070</point>
<point>85,-540</point>
<point>100,0</point>
</reference>
<reference name="DEFAULT_DEVICE_CATEGORY_EARPIECE_VOLUME_CURVE">
<!--Default Volume Curve -->
<point>1,-4950</point>
<point>33,-3350</point>
<point>66,-1700</point>
<point>100,0</point>
</reference>
<reference name="DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE">
<!-- Default is Ext Media System Volume Curve -->
<point>1,-5800</point>
<point>20,-4000</point>
<point>60,-2100</point>
<point>100,-1000</point>
</reference>
<reference name="DEFAULT_HEARING_AID_VOLUME_CURVE">
<!-- Default Hearing Aid Volume Curve -->
<point>1,-12700</point>
<point>20,-8000</point>
<point>60,-4000</point>
<point>100,0</point>
</reference>
<!-- **************************************************************** -->
<!-- Non-mutable default volume curves: -->
<!-- * first point is always for index 0 -->
<!-- * attenuation is small enough that stream can still be heard -->
<reference name="DEFAULT_NON_MUTABLE_VOLUME_CURVE">
<!-- Default non-mutable reference Volume Curve -->
<!-- based on DEFAULT_MEDIA_VOLUME_CURVE -->
<point>0,-5800</point>
<point>20,-4000</point>
<point>60,-1700</point>
<point>100,0</point>
</reference>
<reference name="DEFAULT_NON_MUTABLE_HEADSET_VOLUME_CURVE">
<!--Default non-mutable Volume Curve for headset -->
<!-- based on DEFAULT_DEVICE_CATEGORY_HEADSET_VOLUME_CURVE -->
<point>0,-4950</point>
<point>33,-3350</point>
<point>66,-1700</point>
<point>100,0</point>
</reference>
<reference name="DEFAULT_NON_MUTABLE_SPEAKER_VOLUME_CURVE">
<!-- Default non-mutable Speaker Volume Curve -->
<!-- based on DEFAULT_DEVICE_CATEGORY_SPEAKER_VOLUME_CURVE -->
<point>0,-5800</point>
<point>20,-4000</point>
<point>60,-1700</point>
<point>100,0</point>
</reference>
<reference name="DEFAULT_NON_MUTABLE_EARPIECE_VOLUME_CURVE">
<!--Default non-mutable Volume Curve -->
<!-- based on DEFAULT_DEVICE_CATEGORY_EARPIECE_VOLUME_CURVE -->
<point>0,-4950</point>
<point>33,-3350</point>
<point>66,-1700</point>
<point>100,0</point>
</reference>
<reference name="DEFAULT_NON_MUTABLE_EXT_VOLUME_CURVE">
<!-- Default non-mutable Ext Media System Volume Curve -->
<!-- based on DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE -->
<point>0,-5800</point>
<point>20,-4000</point>
<point>60,-2100</point>
<point>100,-1000</point>
</reference>
<reference name="DEFAULT_NON_MUTABLE_HEARING_AID_VOLUME_CURVE">
<!-- Default non-mutable Hearing Aid Volume Curve -->
<!-- based on DEFAULT_HEARING_AID_VOLUME_CURVE -->
<point>0,-12700</point>
<point>20,-8000</point>
<point>60,-4000</point>
<point>100,0</point>
</reference>
</volumes>

@ -0,0 +1,231 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- 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.
-->
<!-- Volume section defines a volume curve for a given use case and device category.
It contains a list of points of this curve expressing the attenuation in Millibels for a given
volume index from 0 to 100.
<volume stream=”AUDIO_STREAM_MUSIC” deviceCategory=””>
<point>0,-9600</point>
<point>100,0</point>
</volume>
-->
<volumeGroups>
<volumeGroup>
<stream>AUDIO_STREAM_VOICE_CALL</stream>
<indexMin>1</indexMin>
<indexMax>7</indexMax>
<volume deviceCategory="DEVICE_CATEGORY_HEADSET">
<point>0,-4200</point>
<point>33,-2800</point>
<point>66,-1400</point>
<point>100,0</point>
</volume>
<volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
<point>0,-2400</point>
<point>33,-1600</point>
<point>66,-800</point>
<point>100,0</point>
</volume>
<volume deviceCategory="DEVICE_CATEGORY_EARPIECE">
<point>0,-2700</point>
<point>33,-1800</point>
<point>66,-900</point>
<point>100,0</point>
</volume>
<volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
</volumeGroup>
<volumeGroup>
<stream>AUDIO_STREAM_SYSTEM</stream>
<indexMin>0</indexMin>
<indexMax>7</indexMax>
<volume deviceCategory="DEVICE_CATEGORY_HEADSET">
<point>1,-3000</point>
<point>33,-2600</point>
<point>66,-2200</point>
<point>100,-1800</point>
</volume>
<volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
<point>1,-5100</point>
<point>57,-2800</point>
<point>71,-2500</point>
<point>85,-2300</point>
<point>100,-2100</point>
</volume>
<!--volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_SYSTEM_VOLUME_CURVE"/-->
<volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_SYSTEM_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
</volumeGroup>
<volumeGroup>
<stream>AUDIO_STREAM_RING</stream>
<indexMin>0</indexMin>
<indexMax>7</indexMax>
<volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_DEVICE_CATEGORY_HEADSET_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_DEVICE_CATEGORY_SPEAKER_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_DEVICE_CATEGORY_EARPIECE_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
</volumeGroup>
<volumeGroup>
<stream>AUDIO_STREAM_MUSIC</stream>
<indexMin>0</indexMin>
<indexMax>25</indexMax>
<volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_DEVICE_CATEGORY_SPEAKER_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
</volumeGroup>
<volumeGroup>
<stream>AUDIO_STREAM_ALARM</stream>
<indexMin>1</indexMin>
<indexMax>7</indexMax>
<volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_NON_MUTABLE_HEADSET_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_NON_MUTABLE_SPEAKER_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_NON_MUTABLE_EARPIECE_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_NON_MUTABLE_EXT_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_NON_MUTABLE_HEARING_AID_VOLUME_CURVE"/>
</volumeGroup>
<volumeGroup>
<stream>AUDIO_STREAM_NOTIFICATION</stream>
<indexMin>0</indexMin>
<indexMax>7</indexMax>
<volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_DEVICE_CATEGORY_HEADSET_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_DEVICE_CATEGORY_SPEAKER_SYSTEM_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_DEVICE_CATEGORY_EARPIECE_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_DEVICE_CATEGORY_HEADSET_VOLUME_CURVE"/>
</volumeGroup>
<volumeGroup>
<stream>AUDIO_STREAM_BLUETOOTH_SCO</stream>
<indexMin>0</indexMin>
<indexMax>15</indexMax>
<volume deviceCategory="DEVICE_CATEGORY_HEADSET">
<point>0,-4200</point>
<point>33,-2800</point>
<point>66,-1400</point>
<point>100,0</point>
</volume>
<volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
<point>0,-2400</point>
<point>33,-1600</point>
<point>66,-800</point>
<point>100,0</point>
</volume>
<volume deviceCategory="DEVICE_CATEGORY_EARPIECE">
<point>0,-4200</point>
<point>33,-2800</point>
<point>66,-1400</point>
<point>100,0</point>
</volume>
<volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
</volumeGroup>
<volumeGroup>
<stream>AUDIO_STREAM_ENFORCED_AUDIBLE</stream>
<indexMin>0</indexMin>
<indexMax>7</indexMax>
<volume deviceCategory="DEVICE_CATEGORY_HEADSET">
<point>1,-3000</point>
<point>33,-2600</point>
<point>66,-2200</point>
<point>100,-1800</point>
</volume>
<volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
<point>1,-3400</point>
<point>71,-2400</point>
<point>100,-2000</point>
</volume>
<!--volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_SYSTEM_VOLUME_CURVE"/-->
<volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_SYSTEM_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
</volumeGroup>
<volumeGroup>
<stream>AUDIO_STREAM_DTMF</stream>
<indexMin>0</indexMin>
<indexMax>15</indexMax>
<volume deviceCategory="DEVICE_CATEGORY_HEADSET">
<point>1,-3000</point>
<point>33,-2600</point>
<point>66,-2200</point>
<point>100,-1800</point>
</volume>
<volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
<point>1,-4000</point>
<point>71,-2400</point>
<point>100,-1400</point>
</volume>
<!--volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_SYSTEM_VOLUME_CURVE"/-->
<volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_SYSTEM_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
</volumeGroup>
<volumeGroup>
<stream>AUDIO_STREAM_TTS</stream>
<indexMin>0</indexMin>
<indexMax>15</indexMax>
<volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="SILENT_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="FULL_SCALE_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="SILENT_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="SILENT_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="SILENT_VOLUME_CURVE"/>
</volumeGroup>
<volumeGroup>
<stream>AUDIO_STREAM_ACCESSIBILITY</stream>
<indexMin>1</indexMin>
<indexMax>15</indexMax>
<volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_NON_MUTABLE_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_NON_MUTABLE_SPEAKER_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_NON_MUTABLE_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_NON_MUTABLE_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_NON_MUTABLE_HEARING_AID_VOLUME_CURVE"/>
</volumeGroup>
<volumeGroup>
<stream>AUDIO_STREAM_REROUTING</stream>
<indexMin>0</indexMin>
<indexMax>1</indexMax>
<volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="FULL_SCALE_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="FULL_SCALE_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="FULL_SCALE_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="FULL_SCALE_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="FULL_SCALE_VOLUME_CURVE"/>
</volumeGroup>
<volumeGroup>
<stream>AUDIO_STREAM_PATCH</stream>
<indexMin>0</indexMin>
<indexMax>1</indexMax>
<volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="FULL_SCALE_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="FULL_SCALE_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="FULL_SCALE_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="FULL_SCALE_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="FULL_SCALE_VOLUME_CURVE"/>
</volumeGroup>
</volumeGroups>

@ -113,7 +113,7 @@ bool Engine::setVolumeProfileForStream(const audio_stream_type_t &stream,
const audio_stream_type_t &profile)
{
if (setPropertyForKey<audio_stream_type_t, audio_stream_type_t>(stream, profile)) {
getApmObserver()->getVolumeCurves().switchVolumeCurve(profile, stream);
switchVolumeCurve(profile, stream);
return true;
}
return false;

@ -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

@ -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)

@ -17,6 +17,8 @@
<configuration version="1.0" xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include href="audio_policy_engine_product_strategies.xml"/>
<xi:include href="audio_policy_engine_stream_volumes.xml"/>
<xi:include href="audio_policy_engine_default_stream_volumes.xml"/>
</configuration>

@ -0,0 +1,136 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- 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.
-->
<!-- Default Volume Tables included by Audio Policy Configuration file -->
<!-- Full Default Volume table for all device category -->
<volumes>
<reference name="FULL_SCALE_VOLUME_CURVE">
<!-- Full Scale reference Volume Curve -->
<point>0,0</point>
<point>100,0</point>
</reference>
<reference name="SILENT_VOLUME_CURVE">
<point>0,-9600</point>
<point>100,-9600</point>
</reference>
<reference name="DEFAULT_SYSTEM_VOLUME_CURVE">
<!-- Default System reference Volume Curve -->
<point>1,-2400</point>
<point>33,-1800</point>
<point>66,-1200</point>
<point>100,-600</point>
</reference>
<reference name="DEFAULT_MEDIA_VOLUME_CURVE">
<!-- Default Media reference Volume Curve -->
<point>1,-5800</point>
<point>20,-4000</point>
<point>60,-1700</point>
<point>100,0</point>
</reference>
<reference name="DEFAULT_DEVICE_CATEGORY_HEADSET_VOLUME_CURVE">
<!--Default Volume Curve -->
<point>1,-4950</point>
<point>33,-3350</point>
<point>66,-1700</point>
<point>100,0</point>
</reference>
<reference name="DEFAULT_DEVICE_CATEGORY_SPEAKER_VOLUME_CURVE">
<!-- Default is Speaker Media Volume Curve -->
<point>1,-5800</point>
<point>20,-4000</point>
<point>60,-1700</point>
<point>100,0</point>
</reference>
<reference name="DEFAULT_DEVICE_CATEGORY_SPEAKER_SYSTEM_VOLUME_CURVE">
<!-- Default is Speaker System Volume Curve -->
<point>1,-4680</point>
<point>42,-2070</point>
<point>85,-540</point>
<point>100,0</point>
</reference>
<reference name="DEFAULT_DEVICE_CATEGORY_EARPIECE_VOLUME_CURVE">
<!--Default Volume Curve -->
<point>1,-4950</point>
<point>33,-3350</point>
<point>66,-1700</point>
<point>100,0</point>
</reference>
<reference name="DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE">
<!-- Default is Ext Media System Volume Curve -->
<point>1,-5800</point>
<point>20,-4000</point>
<point>60,-2100</point>
<point>100,-1000</point>
</reference>
<reference name="DEFAULT_HEARING_AID_VOLUME_CURVE">
<!-- Default Hearing Aid Volume Curve -->
<point>1,-12700</point>
<point>20,-8000</point>
<point>60,-4000</point>
<point>100,0</point>
</reference>
<!-- **************************************************************** -->
<!-- Non-mutable default volume curves: -->
<!-- * first point is always for index 0 -->
<!-- * attenuation is small enough that stream can still be heard -->
<reference name="DEFAULT_NON_MUTABLE_VOLUME_CURVE">
<!-- Default non-mutable reference Volume Curve -->
<!-- based on DEFAULT_MEDIA_VOLUME_CURVE -->
<point>0,-5800</point>
<point>20,-4000</point>
<point>60,-1700</point>
<point>100,0</point>
</reference>
<reference name="DEFAULT_NON_MUTABLE_HEADSET_VOLUME_CURVE">
<!--Default non-mutable Volume Curve for headset -->
<!-- based on DEFAULT_DEVICE_CATEGORY_HEADSET_VOLUME_CURVE -->
<point>0,-4950</point>
<point>33,-3350</point>
<point>66,-1700</point>
<point>100,0</point>
</reference>
<reference name="DEFAULT_NON_MUTABLE_SPEAKER_VOLUME_CURVE">
<!-- Default non-mutable Speaker Volume Curve -->
<!-- based on DEFAULT_DEVICE_CATEGORY_SPEAKER_VOLUME_CURVE -->
<point>0,-5800</point>
<point>20,-4000</point>
<point>60,-1700</point>
<point>100,0</point>
</reference>
<reference name="DEFAULT_NON_MUTABLE_EARPIECE_VOLUME_CURVE">
<!--Default non-mutable Volume Curve -->
<!-- based on DEFAULT_DEVICE_CATEGORY_EARPIECE_VOLUME_CURVE -->
<point>0,-4950</point>
<point>33,-3350</point>
<point>66,-1700</point>
<point>100,0</point>
</reference>
<reference name="DEFAULT_NON_MUTABLE_EXT_VOLUME_CURVE">
<!-- Default non-mutable Ext Media System Volume Curve -->
<!-- based on DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE -->
<point>0,-5800</point>
<point>20,-4000</point>
<point>60,-2100</point>
<point>100,-1000</point>
</reference>
<reference name="DEFAULT_NON_MUTABLE_HEARING_AID_VOLUME_CURVE">
<!-- Default non-mutable Hearing Aid Volume Curve -->
<!-- based on DEFAULT_HEARING_AID_VOLUME_CURVE -->
<point>0,-12700</point>
<point>20,-8000</point>
<point>60,-4000</point>
<point>100,0</point>
</reference>
</volumes>

@ -0,0 +1,231 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- 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.
-->
<!-- Volume section defines a volume curve for a given use case and device category.
It contains a list of points of this curve expressing the attenuation in Millibels for a given
volume index from 0 to 100.
<volume stream=”AUDIO_STREAM_MUSIC” deviceCategory=””>
<point>0,-9600</point>
<point>100,0</point>
</volume>
-->
<volumeGroups>
<volumeGroup>
<stream>AUDIO_STREAM_VOICE_CALL</stream>
<indexMin>1</indexMin>
<indexMax>7</indexMax>
<volume deviceCategory="DEVICE_CATEGORY_HEADSET">
<point>0,-4200</point>
<point>33,-2800</point>
<point>66,-1400</point>
<point>100,0</point>
</volume>
<volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
<point>0,-2400</point>
<point>33,-1600</point>
<point>66,-800</point>
<point>100,0</point>
</volume>
<volume deviceCategory="DEVICE_CATEGORY_EARPIECE">
<point>0,-2700</point>
<point>33,-1800</point>
<point>66,-900</point>
<point>100,0</point>
</volume>
<volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
</volumeGroup>
<volumeGroup>
<stream>AUDIO_STREAM_SYSTEM</stream>
<indexMin>0</indexMin>
<indexMax>7</indexMax>
<volume deviceCategory="DEVICE_CATEGORY_HEADSET">
<point>1,-3000</point>
<point>33,-2600</point>
<point>66,-2200</point>
<point>100,-1800</point>
</volume>
<volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
<point>1,-5100</point>
<point>57,-2800</point>
<point>71,-2500</point>
<point>85,-2300</point>
<point>100,-2100</point>
</volume>
<!--volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_SYSTEM_VOLUME_CURVE"/-->
<volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_SYSTEM_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
</volumeGroup>
<volumeGroup>
<stream>AUDIO_STREAM_RING</stream>
<indexMin>0</indexMin>
<indexMax>7</indexMax>
<volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_DEVICE_CATEGORY_HEADSET_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_DEVICE_CATEGORY_SPEAKER_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_DEVICE_CATEGORY_EARPIECE_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
</volumeGroup>
<volumeGroup>
<stream>AUDIO_STREAM_MUSIC</stream>
<indexMin>0</indexMin>
<indexMax>25</indexMax>
<volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_DEVICE_CATEGORY_SPEAKER_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
</volumeGroup>
<volumeGroup>
<stream>AUDIO_STREAM_ALARM</stream>
<indexMin>1</indexMin>
<indexMax>7</indexMax>
<volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_NON_MUTABLE_HEADSET_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_NON_MUTABLE_SPEAKER_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_NON_MUTABLE_EARPIECE_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_NON_MUTABLE_EXT_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_NON_MUTABLE_HEARING_AID_VOLUME_CURVE"/>
</volumeGroup>
<volumeGroup>
<stream>AUDIO_STREAM_NOTIFICATION</stream>
<indexMin>0</indexMin>
<indexMax>7</indexMax>
<volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_DEVICE_CATEGORY_HEADSET_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_DEVICE_CATEGORY_SPEAKER_SYSTEM_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_DEVICE_CATEGORY_EARPIECE_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_DEVICE_CATEGORY_HEADSET_VOLUME_CURVE"/>
</volumeGroup>
<volumeGroup>
<stream>AUDIO_STREAM_BLUETOOTH_SCO</stream>
<indexMin>0</indexMin>
<indexMax>15</indexMax>
<volume deviceCategory="DEVICE_CATEGORY_HEADSET">
<point>0,-4200</point>
<point>33,-2800</point>
<point>66,-1400</point>
<point>100,0</point>
</volume>
<volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
<point>0,-2400</point>
<point>33,-1600</point>
<point>66,-800</point>
<point>100,0</point>
</volume>
<volume deviceCategory="DEVICE_CATEGORY_EARPIECE">
<point>0,-4200</point>
<point>33,-2800</point>
<point>66,-1400</point>
<point>100,0</point>
</volume>
<volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
</volumeGroup>
<volumeGroup>
<stream>AUDIO_STREAM_ENFORCED_AUDIBLE</stream>
<indexMin>0</indexMin>
<indexMax>7</indexMax>
<volume deviceCategory="DEVICE_CATEGORY_HEADSET">
<point>1,-3000</point>
<point>33,-2600</point>
<point>66,-2200</point>
<point>100,-1800</point>
</volume>
<volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
<point>1,-3400</point>
<point>71,-2400</point>
<point>100,-2000</point>
</volume>
<!--volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_SYSTEM_VOLUME_CURVE"/-->
<volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_SYSTEM_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
</volumeGroup>
<volumeGroup>
<stream>AUDIO_STREAM_DTMF</stream>
<indexMin>0</indexMin>
<indexMax>15</indexMax>
<volume deviceCategory="DEVICE_CATEGORY_HEADSET">
<point>1,-3000</point>
<point>33,-2600</point>
<point>66,-2200</point>
<point>100,-1800</point>
</volume>
<volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
<point>1,-4000</point>
<point>71,-2400</point>
<point>100,-1400</point>
</volume>
<!--volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_SYSTEM_VOLUME_CURVE"/-->
<volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_SYSTEM_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
</volumeGroup>
<volumeGroup>
<stream>AUDIO_STREAM_TTS</stream>
<indexMin>0</indexMin>
<indexMax>15</indexMax>
<volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="SILENT_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="FULL_SCALE_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="SILENT_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="SILENT_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="SILENT_VOLUME_CURVE"/>
</volumeGroup>
<volumeGroup>
<stream>AUDIO_STREAM_ACCESSIBILITY</stream>
<indexMin>1</indexMin>
<indexMax>15</indexMax>
<volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_NON_MUTABLE_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_NON_MUTABLE_SPEAKER_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_NON_MUTABLE_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_NON_MUTABLE_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_NON_MUTABLE_HEARING_AID_VOLUME_CURVE"/>
</volumeGroup>
<volumeGroup>
<stream>AUDIO_STREAM_REROUTING</stream>
<indexMin>0</indexMin>
<indexMax>1</indexMax>
<volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="FULL_SCALE_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="FULL_SCALE_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="FULL_SCALE_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="FULL_SCALE_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="FULL_SCALE_VOLUME_CURVE"/>
</volumeGroup>
<volumeGroup>
<stream>AUDIO_STREAM_PATCH</stream>
<indexMin>0</indexMin>
<indexMax>1</indexMax>
<volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="FULL_SCALE_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="FULL_SCALE_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="FULL_SCALE_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="FULL_SCALE_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="FULL_SCALE_VOLUME_CURVE"/>
</volumeGroup>
</volumeGroups>

@ -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) {

@ -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;

@ -1710,7 +1710,7 @@ status_t AudioPolicyManager::startSource(const sp<SwAudioOutputDescriptor>& 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<audio_stream_type_t>(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<VolumeCurvesCollection*>(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<AudioOutputDescriptor>& outputDesc,
audio_devices_t device,
int delayMs,
bool force)
int index,
const sp<AudioOutputDescriptor>& 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<AudioOutputDescriptor>& 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);

@ -49,7 +49,7 @@
#include <AudioPolicyMix.h>
#include <EffectDescriptor.h>
#include <SoundTriggerSession.h>
#include <VolumeCurve.h>
#include "TypeConverter.h"
namespace android {
@ -310,12 +310,24 @@ protected:
{
return mAvailableInputDevices;
}
virtual IVolumeCurvesCollection &getVolumeCurves() { return *mVolumeCurves; }
virtual const sp<DeviceDescriptor> &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<SwAudioOutputDescriptor>& outputDesc);
void removeOutput(audio_io_handle_t output);
void addInput(audio_io_handle_t input, const sp<AudioInputDescriptor>& 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<IVolumeCurvesCollection> mVolumeCurves; // Volume Curves per use case and device category
EffectDescriptorCollection mEffects; // list of registered audio effects
sp<DeviceDescriptor> 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<uint32_t> mAudioPortGeneration;

Loading…
Cancel
Save