Effects: Add atomic_wp<T>, update setThread.
atomic_wp<T> is used to allow concurrent read and write to the wp<>.
We use this to fix EffectCallback::setThread to resolve multithreaded
access to the wp<T>.
Note that setThread is used for EffectChain migration between
PlaybackThreads; we also need to refine higher level transactional
locking to ensure enable/disable of effect is done consistently
during migration.
Test: basic audio works
Test: atest media_synchronization_tests
Test: AudioEffectTest AudioPreProcessingTest BassBoostTest
Test: EnvReverbTest EqualizerTest LoudnessEnhancerTest
Test: PresetReverbTest VirtualizerTest VisualizerTest
Bug: 161341295
Change-Id: If80ee4373859c832d6fd10fec0385d69064f50c6
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 1c6f57c..8b96355 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -73,6 +73,7 @@
#include <media/ExtendedAudioBufferProvider.h>
#include <media/VolumeShaper.h>
#include <mediautils/ServiceUtilities.h>
+#include <mediautils/Synchronization.h>
#include <audio_utils/clock.h>
#include <audio_utils/FdToString.h>
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 3ab7737..f5a8552 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -2816,7 +2816,7 @@
status_t AudioFlinger::EffectChain::EffectCallback::addEffectToHal(
sp<EffectHalInterface> effect) {
status_t result = NO_INIT;
- sp<ThreadBase> t = mThread.promote();
+ sp<ThreadBase> t = thread().promote();
if (t == nullptr) {
return result;
}
@@ -2832,7 +2832,7 @@
status_t AudioFlinger::EffectChain::EffectCallback::removeEffectFromHal(
sp<EffectHalInterface> effect) {
status_t result = NO_INIT;
- sp<ThreadBase> t = mThread.promote();
+ sp<ThreadBase> t = thread().promote();
if (t == nullptr) {
return result;
}
@@ -2846,7 +2846,7 @@
}
audio_io_handle_t AudioFlinger::EffectChain::EffectCallback::io() const {
- sp<ThreadBase> t = mThread.promote();
+ sp<ThreadBase> t = thread().promote();
if (t == nullptr) {
return AUDIO_IO_HANDLE_NONE;
}
@@ -2854,7 +2854,7 @@
}
bool AudioFlinger::EffectChain::EffectCallback::isOutput() const {
- sp<ThreadBase> t = mThread.promote();
+ sp<ThreadBase> t = thread().promote();
if (t == nullptr) {
return true;
}
@@ -2862,7 +2862,7 @@
}
bool AudioFlinger::EffectChain::EffectCallback::isOffload() const {
- sp<ThreadBase> t = mThread.promote();
+ sp<ThreadBase> t = thread().promote();
if (t == nullptr) {
return false;
}
@@ -2870,7 +2870,7 @@
}
bool AudioFlinger::EffectChain::EffectCallback::isOffloadOrDirect() const {
- sp<ThreadBase> t = mThread.promote();
+ sp<ThreadBase> t = thread().promote();
if (t == nullptr) {
return false;
}
@@ -2878,7 +2878,7 @@
}
bool AudioFlinger::EffectChain::EffectCallback::isOffloadOrMmap() const {
- sp<ThreadBase> t = mThread.promote();
+ sp<ThreadBase> t = thread().promote();
if (t == nullptr) {
return false;
}
@@ -2886,7 +2886,7 @@
}
uint32_t AudioFlinger::EffectChain::EffectCallback::sampleRate() const {
- sp<ThreadBase> t = mThread.promote();
+ sp<ThreadBase> t = thread().promote();
if (t == nullptr) {
return 0;
}
@@ -2894,7 +2894,7 @@
}
audio_channel_mask_t AudioFlinger::EffectChain::EffectCallback::channelMask() const {
- sp<ThreadBase> t = mThread.promote();
+ sp<ThreadBase> t = thread().promote();
if (t == nullptr) {
return AUDIO_CHANNEL_NONE;
}
@@ -2902,7 +2902,7 @@
}
uint32_t AudioFlinger::EffectChain::EffectCallback::channelCount() const {
- sp<ThreadBase> t = mThread.promote();
+ sp<ThreadBase> t = thread().promote();
if (t == nullptr) {
return 0;
}
@@ -2910,7 +2910,7 @@
}
audio_channel_mask_t AudioFlinger::EffectChain::EffectCallback::hapticChannelMask() const {
- sp<ThreadBase> t = mThread.promote();
+ sp<ThreadBase> t = thread().promote();
if (t == nullptr) {
return AUDIO_CHANNEL_NONE;
}
@@ -2918,7 +2918,7 @@
}
size_t AudioFlinger::EffectChain::EffectCallback::frameCount() const {
- sp<ThreadBase> t = mThread.promote();
+ sp<ThreadBase> t = thread().promote();
if (t == nullptr) {
return 0;
}
@@ -2926,7 +2926,7 @@
}
uint32_t AudioFlinger::EffectChain::EffectCallback::latency() const {
- sp<ThreadBase> t = mThread.promote();
+ sp<ThreadBase> t = thread().promote();
if (t == nullptr) {
return 0;
}
@@ -2934,7 +2934,7 @@
}
void AudioFlinger::EffectChain::EffectCallback::setVolumeForOutput(float left, float right) const {
- sp<ThreadBase> t = mThread.promote();
+ sp<ThreadBase> t = thread().promote();
if (t == nullptr) {
return;
}
@@ -2943,13 +2943,13 @@
void AudioFlinger::EffectChain::EffectCallback::checkSuspendOnEffectEnabled(
const sp<EffectBase>& effect, bool enabled, bool threadLocked) {
- sp<ThreadBase> t = mThread.promote();
+ sp<ThreadBase> t = thread().promote();
if (t == nullptr) {
return;
}
t->checkSuspendOnEffectEnabled(enabled, effect->sessionId(), threadLocked);
- sp<EffectChain> c = mChain.promote();
+ sp<EffectChain> c = chain().promote();
if (c == nullptr) {
return;
}
@@ -2958,7 +2958,7 @@
}
void AudioFlinger::EffectChain::EffectCallback::onEffectEnable(const sp<EffectBase>& effect) {
- sp<ThreadBase> t = mThread.promote();
+ sp<ThreadBase> t = thread().promote();
if (t == nullptr) {
return;
}
@@ -2969,7 +2969,7 @@
void AudioFlinger::EffectChain::EffectCallback::onEffectDisable(const sp<EffectBase>& effect) {
checkSuspendOnEffectEnabled(effect, false, false /*threadLocked*/);
- sp<ThreadBase> t = mThread.promote();
+ sp<ThreadBase> t = thread().promote();
if (t == nullptr) {
return;
}
@@ -2978,7 +2978,7 @@
bool AudioFlinger::EffectChain::EffectCallback::disconnectEffectHandle(EffectHandle *handle,
bool unpinIfLast) {
- sp<ThreadBase> t = mThread.promote();
+ sp<ThreadBase> t = thread().promote();
if (t == nullptr) {
return false;
}
@@ -2987,7 +2987,7 @@
}
void AudioFlinger::EffectChain::EffectCallback::resetVolume() {
- sp<EffectChain> c = mChain.promote();
+ sp<EffectChain> c = chain().promote();
if (c == nullptr) {
return;
}
@@ -2996,7 +2996,7 @@
}
uint32_t AudioFlinger::EffectChain::EffectCallback::strategy() const {
- sp<EffectChain> c = mChain.promote();
+ sp<EffectChain> c = chain().promote();
if (c == nullptr) {
return PRODUCT_STRATEGY_NONE;
}
@@ -3004,7 +3004,7 @@
}
int32_t AudioFlinger::EffectChain::EffectCallback::activeTrackCnt() const {
- sp<EffectChain> c = mChain.promote();
+ sp<EffectChain> c = chain().promote();
if (c == nullptr) {
return 0;
}
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index 89321f9..476330c 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -512,6 +512,12 @@
private:
+ // For transaction consistency, please consider holding the EffectChain lock before
+ // calling the EffectChain::EffectCallback methods, excepting
+ // createEffectHal and allocateHalBuffer.
+ //
+ // This prevents migration of the EffectChain to another PlaybackThread
+ // for the purposes of the EffectCallback.
class EffectCallback : public EffectCallbackInterface {
public:
// Note: ctors taking a weak pointer to their owner must not promote it
@@ -556,10 +562,8 @@
wp<EffectChain> chain() const override { return mChain; }
- wp<ThreadBase> thread() { return mThread; }
+ wp<ThreadBase> thread() const { return mThread.load(); }
- // TODO(b/161341295) secure this against concurrent access to mThread
- // by other callers.
void setThread(const wp<ThreadBase>& thread) {
mThread = thread;
sp<ThreadBase> p = thread.promote();
@@ -568,7 +572,7 @@
private:
const wp<EffectChain> mChain;
- wp<ThreadBase> mThread; // TODO(b/161341295) protect against concurrent access
+ mediautils::atomic_wp<ThreadBase> mThread;
wp<AudioFlinger> mAudioFlinger; // this could be const with some rearrangement.
};