Limit recursive volume calculation
Added boolean to indicate that recursive volume calculation should not
continue for internal calls. This prevents infinity recursion for
calculatations as the interaction are limited to the
first level.
Bug: 331657393
Test: Manual switch of phone call while media is active
Change-Id: I8536aa5988f905e05243c5568b0b1cee65a920e0
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 2dea379..3c3a43a 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -7834,10 +7834,18 @@
float AudioPolicyManager::computeVolume(IVolumeCurves &curves,
VolumeSource volumeSource,
int index,
- const DeviceTypeSet& deviceTypes)
+ const DeviceTypeSet& deviceTypes,
+ bool computeInternalInteraction)
{
float volumeDb = curves.volIndexToDb(Volume::getDeviceCategory(deviceTypes), index);
+ ALOGV("%s volume source %d, index %d, devices %s, compute internal %b ", __func__,
+ volumeSource, index, dumpDeviceTypes(deviceTypes).c_str(), computeInternalInteraction);
+
+ if (!computeInternalInteraction) {
+ return volumeDb;
+ }
+
// handle the case of accessibility active while a ringtone is playing: if the ringtone is much
// louder than the accessibility prompt, the prompt cannot be heard, thus masking the touch
// exploration of the dialer UI. In this situation, bring the accessibility volume closer to
@@ -7847,14 +7855,11 @@
const auto musicVolumeSrc = toVolumeSource(AUDIO_STREAM_MUSIC, false);
const auto alarmVolumeSrc = toVolumeSource(AUDIO_STREAM_ALARM, false);
const auto a11yVolumeSrc = toVolumeSource(AUDIO_STREAM_ACCESSIBILITY, false);
- // Verify that the current volume source is not the ringer volume to prevent recursively
- // calling to compute volume. This could happen in cases where a11y and ringer sounds belong
- // to the same volume group.
- if (volumeSource != ringVolumeSrc && volumeSource == a11yVolumeSrc
- && (AUDIO_MODE_RINGTONE == mEngine->getPhoneState()) &&
+ if (AUDIO_MODE_RINGTONE == mEngine->getPhoneState() &&
mOutputs.isActive(ringVolumeSrc, 0)) {
auto &ringCurves = getVolumeCurves(AUDIO_STREAM_RING);
- const float ringVolumeDb = computeVolume(ringCurves, ringVolumeSrc, index, deviceTypes);
+ const float ringVolumeDb = computeVolume(ringCurves, ringVolumeSrc, index, deviceTypes,
+ /* computeInternalInteraction= */ false);
return ringVolumeDb - 4 > volumeDb ? ringVolumeDb - 4 : volumeDb;
}
@@ -7871,7 +7876,8 @@
auto &voiceCurves = getVolumeCurves(callVolumeSrc);
int voiceVolumeIndex = voiceCurves.getVolumeIndex(deviceTypes);
const float maxVoiceVolDb =
- computeVolume(voiceCurves, callVolumeSrc, voiceVolumeIndex, deviceTypes)
+ computeVolume(voiceCurves, callVolumeSrc, voiceVolumeIndex, deviceTypes,
+ /* computeInternalInteraction= */ false)
+ IN_CALL_EARPIECE_HEADROOM_DB;
// FIXME: Workaround for call screening applications until a proper audio mode is defined
// to support this scenario : Exempt the RING stream from the audio cap if the audio was
@@ -7913,12 +7919,8 @@
// 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
- // Verify that the current volume source is not the music volume to prevent recursively
- // calling to compute volume. This could happen in cases where music and
- // (alarm, ring, notification, system, etc.) sounds belong to the same volume group.
- if (volumeSource != musicVolumeSrc &&
- (isStreamActive(AUDIO_STREAM_MUSIC, SONIFICATION_HEADSET_MUSIC_DELAY)
- || mLimitRingtoneVolume)) {
+ if (isStreamActive(AUDIO_STREAM_MUSIC, SONIFICATION_HEADSET_MUSIC_DELAY)
+ || mLimitRingtoneVolume) {
volumeDb += SONIFICATION_HEADSET_VOLUME_FACTOR_DB;
DeviceTypeSet musicDevice =
mEngine->getOutputDevicesForAttributes(attributes_initializer(AUDIO_USAGE_MEDIA),
@@ -7927,7 +7929,8 @@
float musicVolDb = computeVolume(musicCurves,
musicVolumeSrc,
musicCurves.getVolumeIndex(musicDevice),
- musicDevice);
+ musicDevice,
+ /* computeInternalInteraction= */ false);
float minVolDb = (musicVolDb > SONIFICATION_HEADSET_VOLUME_MIN_DB) ?
musicVolDb : SONIFICATION_HEADSET_VOLUME_MIN_DB;
if (volumeDb > minVolDb) {
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 0454e6e..50e8ed8 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -565,12 +565,36 @@
status_t resetInputDevice(audio_io_handle_t input,
audio_patch_handle_t *patchHandle = NULL);
- // compute the actual volume for a given stream according to the requested index and a particular
- // device
- virtual float computeVolume(IVolumeCurves &curves,
- VolumeSource volumeSource,
- int index,
- const DeviceTypeSet& deviceTypes);
+ /**
+ * Compute volume in DB that should be applied for a volume source and device types for a
+ * particular volume index.
+ *
+ * <p><b>Note:</b>Internally the compute method recursively calls itself to accurately
+ * determine the volume given the currently active sources and devices. Some of the
+ * interaction that require recursive computation are:
+ * <ul>
+ * <li>Match accessibility volume if ringtone volume is much louder</li>
+ * <li>If voice call is active cap other volumes (except ringtone and accessibility)</li>
+ * <li>Attenuate notification if headset is connected to prevent burst in user's ear</li>
+ * <li>Attenuate ringtone if headset is connected and music is not playing and speaker is
+ * part of the devices to prevent burst in user's ear</li>
+ * <li>Limit music volume if headset is connected and notification is also active</li>
+ * </ul>
+ *
+ * @param curves volume curves to use for calculating volume value given the index
+ * @param volumeSource source (use case) of the volume
+ * @param index index to match in the volume curves for the calculation
+ * @param deviceTypes devices that should be considered in the volume curves for the
+ * calculation
+ * @param computeInternalInteraction boolean indicating whether recursive volume computation
+ * should continue within the volume computation. Defaults to {@code true} so the
+ * volume interactions can be computed. Calls within the method should always set the
+ * the value to {@code false} to prevent infinite recursion.
+ * @return computed volume in DB
+ */
+ virtual float computeVolume(IVolumeCurves &curves, VolumeSource volumeSource,
+ int index, const DeviceTypeSet& deviceTypes,
+ bool computeInternalInteraction = true);
// rescale volume index from srcStream within range of dstStream
int rescaleVolumeIndex(int srcIndex,