Initialize volume as 0 for volume control effect.
If a effect is going to be the effect that controls volume, initialize
the volume as 0 for safe ramping. The actual volume is always set when
preparing the tracks. However, the effect can still be enabled after
that and before the next tracks preparation. In that case, initialize
the volume as 0 can help avoid sound blast out when the effect is
enabled.
Bug: 328598362
Test: atest AudioEffectTest
Test: repo steps in the bug
Change-Id: I24eb3c7f21dee8dd4bf9337010b05c09f8f00873
Merged-In: I24eb3c7f21dee8dd4bf9337010b05c09f8f00873
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 4e195a9..43231ff 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -1357,7 +1357,7 @@
}
}
-status_t EffectModule::setVolume(uint32_t* left, uint32_t* right, bool controller) {
+status_t EffectModule::setVolume(uint32_t* left, uint32_t* right, bool controller, bool force) {
AutoLockReentrant _l(mutex(), mSetVolumeReentrantTid);
if (mStatus != NO_ERROR) {
return mStatus;
@@ -1365,7 +1365,7 @@
status_t status = NO_ERROR;
// Send volume indication if EFFECT_FLAG_VOLUME_IND is set and read back altered volume
// if controller flag is set (Note that controller == TRUE => EFFECT_FLAG_VOLUME_CTRL set)
- if (isProcessEnabled() &&
+ if ((isProcessEnabled() || force) &&
((mDescriptor.flags & EFFECT_FLAG_VOLUME_MASK) == EFFECT_FLAG_VOLUME_CTRL ||
(mDescriptor.flags & EFFECT_FLAG_VOLUME_MASK) == EFFECT_FLAG_VOLUME_IND ||
(mDescriptor.flags & EFFECT_FLAG_VOLUME_MASK) == EFFECT_FLAG_VOLUME_MONITOR)) {
@@ -1376,6 +1376,9 @@
status_t EffectModule::setVolumeInternal(
uint32_t *left, uint32_t *right, bool controller) {
+ if (mVolume.has_value() && *left == mVolume.value()[0] && *right == mVolume.value()[1]) {
+ return NO_ERROR;
+ }
uint32_t volume[2] = {*left, *right};
uint32_t *pVolume = controller ? volume : nullptr;
uint32_t size = sizeof(volume);
@@ -1387,6 +1390,7 @@
if (controller && status == NO_ERROR && size == sizeof(volume)) {
*left = volume[0];
*right = volume[1];
+ mVolume = {*left, *right};
}
return status;
}
@@ -2329,10 +2333,11 @@
effect->setCallback(mEffectCallback);
effect_descriptor_t desc = effect->desc();
+ ssize_t idx_insert = 0;
if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
// Auxiliary effects are inserted at the beginning of mEffects vector as
// they are processed first and accumulated in chain input buffer
- mEffects.insertAt(effect, 0);
+ mEffects.insertAt(effect, idx_insert);
// the input buffer for auxiliary effect contains mono samples in
// 32 bit format. This is to avoid saturation in AudoMixer
@@ -2352,7 +2357,7 @@
// by insert effects
effect->setOutBuffer(mInBuffer);
} else {
- ssize_t idx_insert = getInsertIndex_l(desc);
+ idx_insert = getInsertIndex_l(desc);
if (idx_insert < 0) {
return INVALID_OPERATION;
}
@@ -2401,6 +2406,18 @@
}
effect->configure_l();
+ if (effect->isVolumeControl()) {
+ const auto volumeControlIndex = findVolumeControl_l(0, mEffects.size());
+ if (!volumeControlIndex.has_value() || (ssize_t)volumeControlIndex.value() < idx_insert) {
+ // If this effect will be the new volume control effect when it is enabled, force
+ // initializing the volume as 0 for volume control effect for safer ramping. The actual
+ // volume will be set from setVolume_l.
+ uint32_t left = 0;
+ uint32_t right = 0;
+ effect->setVolume(&left, &right, true /*controller*/, true /*force*/);
+ }
+ }
+
return NO_ERROR;
}
@@ -2609,21 +2626,16 @@
return volumeControlIndex.has_value();
}
- if (volumeControlEffect != cachedVolumeControlEffect) {
- // The volume control effect is a new one. Set the old one as full volume. Set the new onw
- // as zero for safe ramping.
- if (cachedVolumeControlEffect != nullptr) {
+ for (int i = 0; i < ctrlIdx; ++i) {
+ // For all volume control effects before the effect that controls volume, set the volume
+ // to maximum to avoid double attenuation.
+ if (mEffects[i]->isVolumeControl()) {
uint32_t leftMax = 1 << 24;
uint32_t rightMax = 1 << 24;
- cachedVolumeControlEffect->setVolume(&leftMax, &rightMax, true /*controller*/);
+ mEffects[i]->setVolume(&leftMax, &rightMax, true /*controller*/, true /*force*/);
}
- if (volumeControlEffect != nullptr) {
- uint32_t leftZero = 0;
- uint32_t rightZero = 0;
- volumeControlEffect->setVolume(&leftZero, &rightZero, true /*controller*/);
- }
- mVolumeControlEffect = volumeControlEffect;
}
+
mLeftVolume = newLeft;
mRightVolume = newRight;