AudioEffect: prevent adding effect for unknown session on first io
Bug: 309578734
Test: add an effect chain on a music ouput (first) and enable.
Add another chain on another output.
Ensure chain on music output is not suspended.
Adding a chain on a different output may suspend chain on default output
First output is assigned when an effect is created, then may be moved once the
session is associated to its output.
It leads to suspend the chain of first output.
This CL fixes this bug by adding effect in orphan chains until track is
created.
Test: atest CtsMediaAudioTestCases
Change-Id: I2ce880dea862df1b29a67893d60a9c98c4c4eb46
Merged-In: I2ce880dea862df1b29a67893d60a9c98c4c4eb46
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 4cb0f8b..4e195a9 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -2155,27 +2155,31 @@
/* static */
sp<IAfEffectChain> IAfEffectChain::create(
const sp<IAfThreadBase>& thread,
- audio_session_t sessionId)
+ audio_session_t sessionId,
+ const sp<IAfThreadCallback>& afThreadCallback)
{
- return sp<EffectChain>::make(thread, sessionId);
+ return sp<EffectChain>::make(thread, sessionId, afThreadCallback);
}
-EffectChain::EffectChain(const sp<IAfThreadBase>& thread,
- audio_session_t sessionId)
+EffectChain::EffectChain(const sp<IAfThreadBase>& thread, audio_session_t sessionId,
+ const sp<IAfThreadCallback>& afThreadCallback)
: mSessionId(sessionId), mActiveTrackCnt(0), mTrackCnt(0), mTailBufferCount(0),
mLeftVolume(UINT_MAX), mRightVolume(UINT_MAX),
mNewLeftVolume(UINT_MAX), mNewRightVolume(UINT_MAX),
- mEffectCallback(new EffectCallback(wp<EffectChain>(this), thread))
+ mEffectCallback(new EffectCallback(wp<EffectChain>(this), thread, afThreadCallback))
{
- mStrategy = thread->getStrategyForStream(AUDIO_STREAM_MUSIC);
- mMaxTailBuffers = ((kProcessTailDurationMs * thread->sampleRate()) / 1000) /
- thread->frameCount();
+ if (thread != nullptr) {
+ mStrategy = thread->getStrategyForStream(AUDIO_STREAM_MUSIC);
+ mMaxTailBuffers =
+ ((kProcessTailDurationMs * thread->sampleRate()) / 1000) /
+ thread->frameCount();
+ }
}
-// getEffectFromDesc_l() must be called with IAfThreadBase::mutex() held
-sp<IAfEffectModule> EffectChain::getEffectFromDesc_l(
+sp<IAfEffectModule> EffectChain::getEffectFromDesc(
effect_descriptor_t *descriptor) const
{
+ audio_utils::lock_guard _l(mutex());
size_t size = mEffects.size();
for (size_t i = 0; i < size; i++) {
@@ -2189,6 +2193,7 @@
// getEffectFromId_l() must be called with IAfThreadBase::mutex() held
sp<IAfEffectModule> EffectChain::getEffectFromId_l(int id) const
{
+ audio_utils::lock_guard _l(mutex());
size_t size = mEffects.size();
for (size_t i = 0; i < size; i++) {
@@ -2204,6 +2209,7 @@
sp<IAfEffectModule> EffectChain::getEffectFromType_l(
const effect_uuid_t *type) const
{
+ audio_utils::lock_guard _l(mutex());
size_t size = mEffects.size();
for (size_t i = 0; i < size; i++) {
@@ -2294,8 +2300,7 @@
}
}
-// createEffect_l() must be called with IAfThreadBase::mutex() held
-status_t EffectChain::createEffect_l(sp<IAfEffectModule>& effect,
+status_t EffectChain::createEffect(sp<IAfEffectModule>& effect,
effect_descriptor_t *desc,
int id,
audio_session_t sessionId,
@@ -2305,7 +2310,7 @@
effect = new EffectModule(mEffectCallback, desc, id, sessionId, pinned, AUDIO_PORT_HANDLE_NONE);
status_t lStatus = effect->status();
if (lStatus == NO_ERROR) {
- lStatus = addEffect_ll(effect);
+ lStatus = addEffect_l(effect);
}
if (lStatus != NO_ERROR) {
effect.clear();
@@ -2313,14 +2318,13 @@
return lStatus;
}
-// addEffect_l() must be called with IAfThreadBase::mutex() held
-status_t EffectChain::addEffect_l(const sp<IAfEffectModule>& effect)
+status_t EffectChain::addEffect(const sp<IAfEffectModule>& effect)
{
audio_utils::lock_guard _l(mutex());
- return addEffect_ll(effect);
+ return addEffect_l(effect);
}
-// addEffect_l() must be called with IAfThreadBase::mutex() and EffectChain::mutex() held
-status_t EffectChain::addEffect_ll(const sp<IAfEffectModule>& effect)
+// addEffect_l() must be called with EffectChain::mutex() held
+status_t EffectChain::addEffect_l(const sp<IAfEffectModule>& effect)
{
effect->setCallback(mEffectCallback);
@@ -2348,7 +2352,7 @@
// by insert effects
effect->setOutBuffer(mInBuffer);
} else {
- ssize_t idx_insert = getInsertIndex_ll(desc);
+ ssize_t idx_insert = getInsertIndex_l(desc);
if (idx_insert < 0) {
return INVALID_OPERATION;
}
@@ -2409,7 +2413,7 @@
return std::nullopt;
}
-ssize_t EffectChain::getInsertIndex_ll(const effect_descriptor_t& desc) {
+ssize_t EffectChain::getInsertIndex_l(const effect_descriptor_t& desc) {
// Insert effects are inserted at the end of mEffects vector as they are processed
// after track and auxiliary effects.
// Insert effect order as a function of indicated preference:
@@ -2482,8 +2486,7 @@
return idx_insert;
}
-// removeEffect_l() must be called with IAfThreadBase::mutex() held
-size_t EffectChain::removeEffect_l(const sp<IAfEffectModule>& effect,
+size_t EffectChain::removeEffect(const sp<IAfEffectModule>& effect,
bool release)
{
audio_utils::lock_guard _l(mutex());
@@ -2534,6 +2537,7 @@
// setDevices_l() must be called with IAfThreadBase::mutex() held
void EffectChain::setDevices_l(const AudioDeviceTypeAddrVector &devices)
{
+ audio_utils::lock_guard _l(mutex());
size_t size = mEffects.size();
for (size_t i = 0; i < size; i++) {
mEffects[i]->setDevices(devices);
@@ -2543,6 +2547,7 @@
// setInputDevice_l() must be called with IAfThreadBase::mutex() held
void EffectChain::setInputDevice_l(const AudioDeviceTypeAddr &device)
{
+ audio_utils::lock_guard _l(mutex());
size_t size = mEffects.size();
for (size_t i = 0; i < size; i++) {
mEffects[i]->setInputDevice(device);
@@ -2552,6 +2557,7 @@
// setMode_l() must be called with IAfThreadBase::mutex() held
void EffectChain::setMode_l(audio_mode_t mode)
{
+ audio_utils::lock_guard _l(mutex());
size_t size = mEffects.size();
for (size_t i = 0; i < size; i++) {
mEffects[i]->setMode(mode);
@@ -2561,6 +2567,7 @@
// setAudioSource_l() must be called with IAfThreadBase::mutex() held
void EffectChain::setAudioSource_l(audio_source_t source)
{
+ audio_utils::lock_guard _l(mutex());
size_t size = mEffects.size();
for (size_t i = 0; i < size; i++) {
mEffects[i]->setAudioSource(source);
@@ -2666,8 +2673,12 @@
}
}
-// containsHapticGeneratingEffect_l must be called with
-// IAfThreadBase::mutex() or EffectChain::mutex() held
+bool EffectChain::containsHapticGeneratingEffect()
+{
+ audio_utils::lock_guard _l(mutex());
+ return containsHapticGeneratingEffect_l();
+}
+// containsHapticGeneratingEffect_l must be called with EffectChain::mutex() held
bool EffectChain::containsHapticGeneratingEffect_l()
{
for (size_t i = 0; i < mEffects.size(); ++i) {
@@ -2808,7 +2819,7 @@
}
if (desc->mRefCount++ == 0) {
Vector< sp<IAfEffectModule> > effects;
- getSuspendEligibleEffects_l(effects);
+ getSuspendEligibleEffects(effects);
for (size_t i = 0; i < effects.size(); i++) {
setEffectSuspended_l(&effects[i]->desc().type, true);
}
@@ -2858,7 +2869,7 @@
return false;
}
-bool EffectChain::isEffectEligibleForSuspend_l(const effect_descriptor_t& desc)
+bool EffectChain::isEffectEligibleForSuspend(const effect_descriptor_t& desc)
{
// auxiliary effects and visualizer are never suspended on output mix
if ((mSessionId == AUDIO_SESSION_OUTPUT_MIX) &&
@@ -2871,12 +2882,13 @@
return true;
}
-void EffectChain::getSuspendEligibleEffects_l(
+void EffectChain::getSuspendEligibleEffects(
Vector< sp<IAfEffectModule> > &effects)
{
effects.clear();
+ audio_utils::lock_guard _l(mutex());
for (size_t i = 0; i < mEffects.size(); i++) {
- if (isEffectEligibleForSuspend_l(mEffects[i]->desc())) {
+ if (isEffectEligibleForSuspend(mEffects[i]->desc())) {
effects.add(mEffects[i]);
}
}
@@ -2897,7 +2909,7 @@
if (index < 0) {
return;
}
- if (!isEffectEligibleForSuspend_l(effect->desc())) {
+ if (!isEffectEligibleForSuspend(effect->desc())) {
return;
}
setEffectSuspended_l(&effect->desc().type, enabled);
@@ -2945,6 +2957,12 @@
void EffectChain::setThread(const sp<IAfThreadBase>& thread)
{
+ if (thread != nullptr) {
+ mStrategy = thread->getStrategyForStream(AUDIO_STREAM_MUSIC);
+ mMaxTailBuffers =
+ ((kProcessTailDurationMs * thread->sampleRate()) / 1000) /
+ thread->frameCount();
+ }
audio_utils::lock_guard _l(mutex());
mEffectCallback->setThread(thread);
}
@@ -3134,7 +3152,7 @@
uint32_t EffectChain::EffectCallback::sampleRate() const {
const sp<IAfThreadBase> t = thread().promote();
if (t == nullptr) {
- return 0;
+ return DEFAULT_OUTPUT_SAMPLE_RATE;
}
return t->sampleRate();
}
@@ -3142,6 +3160,7 @@
audio_channel_mask_t EffectChain::EffectCallback::inChannelMask(int id) const
NO_THREAD_SAFETY_ANALYSIS
// calling function 'hasAudioSession_l' requires holding mutex 'ThreadBase_Mutex' exclusively
+// calling function 'isFirstEffect_l' requires holding mutex 'EffectChain_Mutex' exclusively
{
const sp<IAfThreadBase> t = thread().promote();
if (t == nullptr) {
@@ -3154,7 +3173,7 @@
if (mThreadType == IAfThreadBase::SPATIALIZER) {
if (c->sessionId() == AUDIO_SESSION_OUTPUT_STAGE) {
- if (c->isFirstEffect(id)) {
+ if (c->isFirstEffect_l(id)) {
return t->mixerChannelMask();
} else {
return t->channelMask();
@@ -3222,7 +3241,8 @@
size_t EffectChain::EffectCallback::frameCount() const {
const sp<IAfThreadBase> t = thread().promote();
if (t == nullptr) {
- return 0;
+ // frameCount cannot be zero.
+ return 1;
}
return t->frameCount();
}