audio policy: fix volume burst on user switch.
Fix two main problems in setStreamVolumeIndex():
1) the conventional initialization or user switch behavior consisting in first
applying volume for AUDIO_DEVICE_OUT_DEFAULT device which resets all volumes
and then apply device specific volumes is problematic: if this is done while
a stream is active, it will temporarily reset the volume to its default
(usually loud) and then back causing an audible glitch.
2) The logic consisting in applying the requested volume to all outputs with a
device selected by the routing strategy corresponding to the requested stream
is problematic: it will cause device specific volumes for other devices than
current one to be applied to active streams.
Restrict the logic to cases of multiple device selections including the
requested device.
Bug: 27557733
Change-Id: Ia14cd51766a7516c42221abff76843d47699105f
diff --git a/services/audiopolicy/common/managerdefinitions/include/IVolumeCurvesCollection.h b/services/audiopolicy/common/managerdefinitions/include/IVolumeCurvesCollection.h
index 8dc3eda..a3de686 100644
--- a/services/audiopolicy/common/managerdefinitions/include/IVolumeCurvesCollection.h
+++ b/services/audiopolicy/common/managerdefinitions/include/IVolumeCurvesCollection.h
@@ -42,6 +42,8 @@
{
switchVolumeCurve(stream, stream);
}
+ virtual bool hasVolumeIndexForDevice(audio_stream_type_t stream,
+ audio_devices_t device) const = 0;
virtual status_t dump(int fd) const = 0;
diff --git a/services/audiopolicy/common/managerdefinitions/include/StreamDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/StreamDescriptor.h
index af178f9..424df84 100644
--- a/services/audiopolicy/common/managerdefinitions/include/StreamDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/StreamDescriptor.h
@@ -38,6 +38,11 @@
int getVolumeIndexMax() const { return mIndexMax; }
void setVolumeIndexMin(int volIndexMin);
void setVolumeIndexMax(int volIndexMax);
+ bool hasVolumeIndexForDevice(audio_devices_t device) const
+ {
+ device = Volume::getDeviceForVolume(device);
+ return mIndexCur.indexOfKey(device) >= 0;
+ }
void dump(int fd) const;
@@ -85,6 +90,11 @@
virtual status_t initStreamVolume(audio_stream_type_t stream, int indexMin, int indexMax);
virtual void initializeVolumeCurves(bool isSpeakerDrcEnabled);
virtual void switchVolumeCurve(audio_stream_type_t streamSrc, audio_stream_type_t streamDst);
+ virtual bool hasVolumeIndexForDevice(audio_stream_type_t stream,
+ audio_devices_t device) const
+ {
+ return valueFor(stream).hasVolumeIndexForDevice(device);
+ }
virtual status_t dump(int fd) const;
diff --git a/services/audiopolicy/common/managerdefinitions/include/VolumeCurve.h b/services/audiopolicy/common/managerdefinitions/include/VolumeCurve.h
index 009a26f..7c486c8 100644
--- a/services/audiopolicy/common/managerdefinitions/include/VolumeCurve.h
+++ b/services/audiopolicy/common/managerdefinitions/include/VolumeCurve.h
@@ -44,8 +44,8 @@
return lhs.mIndex < rhs.mIndex;
}
-// A volume curve for a given use case and device cateory
-// It contains of list of points of this cuive expressing the atteunation in Millibels for
+// 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
{
@@ -105,6 +105,12 @@
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");
@@ -200,6 +206,11 @@
{
return getCurvesFor(stream).volIndexToDb(cat, indexInUi);
}
+ virtual bool hasVolumeIndexForDevice(audio_stream_type_t stream,
+ audio_devices_t device) const
+ {
+ return getCurvesFor(stream).hasVolumeIndexForDevice(device);
+ }
virtual status_t dump(int fd) const;
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 35c868e..07c470d 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1821,15 +1821,9 @@
// Force max volume if stream cannot be muted
if (!mVolumeCurves->canBeMuted(stream)) index = mVolumeCurves->getVolumeIndexMax(stream);
- ALOGV("setStreamVolumeIndex() stream %d, device %04x, index %d",
+ ALOGV("setStreamVolumeIndex() stream %d, device %08x, index %d",
stream, device, index);
- // if device is AUDIO_DEVICE_OUT_DEFAULT set default value and
- // clear all device specific values
- if (device == AUDIO_DEVICE_OUT_DEFAULT) {
- mVolumeCurves->clearCurrentVolumeIndex(stream);
- }
-
// update other private stream volumes which follow this one
for (int curStream = 0; curStream < AUDIO_STREAM_FOR_POLICY_CNT; curStream++) {
if (!streamsMatchForvolume(stream, (audio_stream_type_t)curStream)) {
@@ -1838,8 +1832,14 @@
mVolumeCurves->addCurrentVolumeIndex((audio_stream_type_t)curStream, device, index);
}
- // update volume on all outputs whose current device is also selected by the same
- // strategy as the device specified by the caller
+ // update volume on all outputs and streams matching the following:
+ // - The requested stream (or a stream matching for volume control) is active on the output
+ // - The device (or devices) selected by the strategy corresponding to this stream includes
+ // the requested device
+ // - For non default requested device, currently selected device on the output is either the
+ // requested device or one of the devices selected by the strategy
+ // - For default requested device (AUDIO_DEVICE_OUT_DEFAULT), apply volume only if no specific
+ // device volume value exists for currently selected device.
status_t status = NO_ERROR;
for (size_t i = 0; i < mOutputs.size(); i++) {
sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
@@ -1848,16 +1848,23 @@
if (!streamsMatchForvolume(stream, (audio_stream_type_t)curStream)) {
continue;
}
+ if (!desc->isStreamActive((audio_stream_type_t)curStream)) {
+ continue;
+ }
routing_strategy curStrategy = getStrategy((audio_stream_type_t)curStream);
audio_devices_t curStreamDevice = getDeviceForStrategy(curStrategy, true /*fromCache*/);
- // it is possible that the requested device is not selected by the strategy
- // (e.g an explicit audio patch is active causing getDevicesForStream()
- // to return this device. We must make sure that the device passed is part of the
- // devices considered when applying volume below.
- curStreamDevice |= device;
+ if ((curStreamDevice & device) == 0) {
+ continue;
+ }
+ bool applyDefault = false;
+ if (device != AUDIO_DEVICE_OUT_DEFAULT) {
+ curStreamDevice |= device;
+ } else if (!mVolumeCurves->hasVolumeIndexForDevice(
+ stream, Volume::getDeviceForVolume(curStreamDevice))) {
+ applyDefault = true;
+ }
- if (((device == AUDIO_DEVICE_OUT_DEFAULT) ||
- ((curDevice & curStreamDevice) != 0))) {
+ if (applyDefault || ((curDevice & curStreamDevice) != 0)) {
status_t volStatus =
checkAndSetVolume((audio_stream_type_t)curStream, index, desc, curDevice);
if (volStatus != NO_ERROR) {