Re-implement HIDL effect processing using FMQ and IMemory
Result: no hwbinder calls due music processing.
Test: make, use Play Music with effects, check traces
Bug: 30222631
Change-Id: I06d0e94e603688874b31824427f3b0878b5f7c8e
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index d18ca47..7056dc9 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -48,6 +48,7 @@
#include <system/audio.h>
#include <system/audio_policy.h>
+#include <media/audiohal/EffectBufferHalInterface.h>
#include <media/audiohal/StreamHalInterface.h>
#include <media/AudioBufferProvider.h>
#include <media/ExtendedAudioBufferProvider.h>
diff --git a/services/audioflinger/BufferProviders.cpp b/services/audioflinger/BufferProviders.cpp
index ba5f7b6..7c8798c 100644
--- a/services/audioflinger/BufferProviders.cpp
+++ b/services/audioflinger/BufferProviders.cpp
@@ -19,6 +19,7 @@
#include <audio_utils/primitives.h>
#include <audio_utils/format.h>
+#include <media/audiohal/EffectBufferHalInterface.h>
#include <media/audiohal/EffectHalInterface.h>
#include <media/audiohal/EffectsFactoryHalInterface.h>
#include <media/AudioResamplerPublic.h>
@@ -179,17 +180,42 @@
EFFECT_CONFIG_FORMAT | EFFECT_CONFIG_ACC_MODE;
mDownmixConfig.outputCfg.mask = mDownmixConfig.inputCfg.mask;
+ status_t status;
+ status = EffectBufferHalInterface::mirror(
+ nullptr,
+ audio_bytes_per_sample(format) * audio_channel_count_from_out_mask(inputChannelMask),
+ &mInBuffer);
+ if (status != 0) {
+ ALOGE("DownmixerBufferProvider() error %d while creating input buffer", status);
+ mDownmixInterface.clear();
+ mEffectsFactory.clear();
+ return;
+ }
+ status = EffectBufferHalInterface::mirror(
+ nullptr,
+ audio_bytes_per_sample(format) * audio_channel_count_from_out_mask(outputChannelMask),
+ &mOutBuffer);
+ if (status != 0) {
+ ALOGE("DownmixerBufferProvider() error %d while creating output buffer", status);
+ mInBuffer.clear();
+ mDownmixInterface.clear();
+ mEffectsFactory.clear();
+ return;
+ }
+
int cmdStatus;
uint32_t replySize = sizeof(int);
// Configure downmixer
- status_t status = mDownmixInterface->command(
+ status = mDownmixInterface->command(
EFFECT_CMD_SET_CONFIG /*cmdCode*/, sizeof(effect_config_t) /*cmdSize*/,
&mDownmixConfig /*pCmdData*/,
&replySize, &cmdStatus /*pReplyData*/);
if (status != 0 || cmdStatus != 0) {
ALOGE("DownmixerBufferProvider() error %d cmdStatus %d while configuring downmixer",
status, cmdStatus);
+ mOutBuffer.clear();
+ mInBuffer.clear();
mDownmixInterface.clear();
mEffectsFactory.clear();
return;
@@ -203,6 +229,8 @@
if (status != 0 || cmdStatus != 0) {
ALOGE("DownmixerBufferProvider() error %d cmdStatus %d while enabling downmixer",
status, cmdStatus);
+ mOutBuffer.clear();
+ mInBuffer.clear();
mDownmixInterface.clear();
mEffectsFactory.clear();
return;
@@ -228,6 +256,8 @@
if (status != 0 || cmdStatus != 0) {
ALOGE("DownmixerBufferProvider() error %d cmdStatus %d while setting downmix type",
status, cmdStatus);
+ mOutBuffer.clear();
+ mInBuffer.clear();
mDownmixInterface.clear();
mEffectsFactory.clear();
return;
@@ -238,18 +268,26 @@
DownmixerBufferProvider::~DownmixerBufferProvider()
{
ALOGV("~DownmixerBufferProvider (%p)", this);
+ if (mDownmixInterface != 0) {
+ mDownmixInterface->close();
+ }
}
void DownmixerBufferProvider::copyFrames(void *dst, const void *src, size_t frames)
{
- mDownmixConfig.inputCfg.buffer.frameCount = frames;
- mDownmixConfig.inputCfg.buffer.raw = const_cast<void *>(src);
- mDownmixConfig.outputCfg.buffer.frameCount = frames;
- mDownmixConfig.outputCfg.buffer.raw = dst;
+ mInBuffer->setExternalData(const_cast<void*>(src));
+ mInBuffer->setFrameCount(frames);
+ mInBuffer->update();
+ mOutBuffer->setExternalData(dst);
+ mOutBuffer->setFrameCount(frames);
+ mOutBuffer->update();
// may be in-place if src == dst.
- status_t res = mDownmixInterface->process(
- &mDownmixConfig.inputCfg.buffer, &mDownmixConfig.outputCfg.buffer);
- ALOGE_IF(res != OK, "DownmixBufferProvider error %d", res);
+ status_t res = mDownmixInterface->process();
+ if (res == OK) {
+ mOutBuffer->commit();
+ } else {
+ ALOGE("DownmixBufferProvider error %d", res);
+ }
}
/* call once in a pthread_once handler. */
diff --git a/services/audioflinger/BufferProviders.h b/services/audioflinger/BufferProviders.h
index 2a857fe..4e3f89f 100644
--- a/services/audioflinger/BufferProviders.h
+++ b/services/audioflinger/BufferProviders.h
@@ -28,6 +28,7 @@
namespace android {
+class EffectBufferHalInterface;
class EffectHalInterface;
class EffectsFactoryHalInterface;
@@ -108,6 +109,8 @@
protected:
sp<EffectsFactoryHalInterface> mEffectsFactory;
sp<EffectHalInterface> mDownmixInterface;
+ sp<EffectBufferHalInterface> mInBuffer;
+ sp<EffectBufferHalInterface> mOutBuffer;
effect_config_t mDownmixConfig;
// effect descriptor for the downmixer used by the mixer
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 6c937a5..343ad25 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -188,6 +188,7 @@
// this object is released which can happen after next process is called.
if (mHandles.size() == 0 && !mPinned) {
mState = DESTROYED;
+ mEffectInterface->close();
}
return mHandles.size();
@@ -275,9 +276,7 @@
{
Mutex::Autolock _l(mLock);
- if (mState == DESTROYED || mEffectInterface == 0 ||
- mConfig.inputCfg.buffer.raw == NULL ||
- mConfig.outputCfg.buffer.raw == NULL) {
+ if (mState == DESTROYED || mEffectInterface == 0 || mInBuffer == 0 || mOutBuffer == 0) {
return;
}
@@ -291,7 +290,7 @@
int ret;
if (isProcessImplemented()) {
// do the actual processing in the effect engine
- ret = mEffectInterface->process(&mConfig.inputCfg.buffer, &mConfig.outputCfg.buffer);
+ ret = mEffectInterface->process();
} else {
if (mConfig.inputCfg.buffer.raw != mConfig.outputCfg.buffer.raw) {
size_t frameCnt = mConfig.inputCfg.buffer.frameCount * FCC_2; //always stereo here
@@ -409,6 +408,12 @@
mConfig.outputCfg.mask = EFFECT_CONFIG_ALL;
mConfig.inputCfg.buffer.frameCount = thread->frameCount();
mConfig.outputCfg.buffer.frameCount = mConfig.inputCfg.buffer.frameCount;
+ if (mInBuffer != 0) {
+ mInBuffer->setFrameCount(mConfig.inputCfg.buffer.frameCount);
+ }
+ if (mOutBuffer != 0) {
+ mOutBuffer->setFrameCount(mConfig.outputCfg.buffer.frameCount);
+ }
ALOGV("configure() %p thread %p buffer %p framecount %zu",
this, thread.get(), mConfig.inputCfg.buffer.raw, mConfig.inputCfg.buffer.frameCount);
@@ -568,6 +573,7 @@
if (mEffectInterface != 0) {
remove_effect_from_hal_l();
// release effect engine
+ mEffectInterface->close();
mEffectInterface.clear();
}
}
@@ -762,6 +768,28 @@
}
}
+void AudioFlinger::EffectModule::setInBuffer(const sp<EffectBufferHalInterface>& buffer) {
+ if (buffer != 0) {
+ mConfig.inputCfg.buffer.raw = buffer->audioBuffer()->raw;
+ buffer->setFrameCount(mConfig.inputCfg.buffer.frameCount);
+ } else {
+ mConfig.inputCfg.buffer.raw = NULL;
+ }
+ mInBuffer = buffer;
+ mEffectInterface->setInBuffer(buffer);
+}
+
+void AudioFlinger::EffectModule::setOutBuffer(const sp<EffectBufferHalInterface>& buffer) {
+ if (buffer != 0) {
+ mConfig.outputCfg.buffer.raw = buffer->audioBuffer()->raw;
+ buffer->setFrameCount(mConfig.outputCfg.buffer.frameCount);
+ } else {
+ mConfig.outputCfg.buffer.raw = NULL;
+ }
+ mOutBuffer = buffer;
+ mEffectInterface->setOutBuffer(buffer);
+}
+
status_t AudioFlinger::EffectModule::setVolume(uint32_t *left, uint32_t *right, bool controller)
{
Mutex::Autolock _l(mLock);
@@ -1482,7 +1510,7 @@
AudioFlinger::EffectChain::EffectChain(ThreadBase *thread,
audio_session_t sessionId)
: mThread(thread), mSessionId(sessionId), mActiveTrackCnt(0), mTrackCnt(0), mTailBufferCount(0),
- mOwnInBuffer(false), mVolumeCtrlIdx(-1), mLeftVolume(UINT_MAX), mRightVolume(UINT_MAX),
+ mVolumeCtrlIdx(-1), mLeftVolume(UINT_MAX), mRightVolume(UINT_MAX),
mNewLeftVolume(UINT_MAX), mNewRightVolume(UINT_MAX)
{
mStrategy = AudioSystem::getStrategyForStream(AUDIO_STREAM_MUSIC);
@@ -1495,9 +1523,6 @@
AudioFlinger::EffectChain::~EffectChain()
{
- if (mOwnInBuffer) {
- delete[] mInBuffer;
- }
}
// getEffectFromDesc_l() must be called with ThreadBase::mLock held
@@ -1562,7 +1587,8 @@
// (4 bytes frame size)
const size_t frameSize =
audio_bytes_per_sample(AUDIO_FORMAT_PCM_16_BIT) * min(FCC_2, thread->channelCount());
- memset(mInBuffer, 0, thread->frameCount() * frameSize);
+ memset(mInBuffer->audioBuffer()->raw, 0, thread->frameCount() * frameSize);
+ mInBuffer->commit();
}
// Must be called with EffectChain::mLock locked
@@ -1600,9 +1626,15 @@
size_t size = mEffects.size();
if (doProcess) {
+ // Only the input and output buffers of the chain can be external,
+ // and 'update' / 'commit' do nothing for allocated buffers, thus
+ // it's not needed to consider any other buffers here.
+ mInBuffer->update();
+ mOutBuffer->update();
for (size_t i = 0; i < size; i++) {
mEffects[i]->process();
}
+ mOutBuffer->commit();
}
bool doResetVolume = false;
for (size_t i = 0; i < size; i++) {
@@ -1662,9 +1694,11 @@
// accumulation stage. Saturation is done in EffectModule::process() before
// calling the process in effect engine
size_t numSamples = thread->frameCount();
- int32_t *buffer = new int32_t[numSamples];
- memset(buffer, 0, numSamples * sizeof(int32_t));
- effect->setInBuffer((int16_t *)buffer);
+ sp<EffectBufferHalInterface> halBuffer;
+ status_t result = EffectBufferHalInterface::allocate(
+ numSamples * sizeof(int32_t), &halBuffer);
+ if (result != OK) return result;
+ effect->setInBuffer(halBuffer);
// auxiliary effects output samples to chain input buffer for further processing
// by insert effects
effect->setOutBuffer(mInBuffer);
@@ -1775,9 +1809,7 @@
mEffects[i]->release_l();
}
- if (type == EFFECT_FLAG_TYPE_AUXILIARY) {
- delete[] effect->inBuffer();
- } else {
+ if (type != EFFECT_FLAG_TYPE_AUXILIARY) {
if (i == size - 1 && i != 0) {
mEffects[i - 1]->setOutBuffer(mOutBuffer);
mEffects[i - 1]->configure();
@@ -1922,8 +1954,8 @@
result.append("\tIn buffer Out buffer Active tracks:\n");
snprintf(buffer, SIZE, "\t%p %p %d\n",
- mInBuffer,
- mOutBuffer,
+ mInBuffer->audioBuffer(),
+ mOutBuffer->audioBuffer(),
mActiveTrackCnt);
result.append(buffer);
write(fd, result.string(), result.size());
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index dc29ce0..0755c52 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -86,10 +86,14 @@
bool isEnabled() const;
bool isProcessEnabled() const;
- void setInBuffer(int16_t *buffer) { mConfig.inputCfg.buffer.s16 = buffer; }
- int16_t *inBuffer() { return mConfig.inputCfg.buffer.s16; }
- void setOutBuffer(int16_t *buffer) { mConfig.outputCfg.buffer.s16 = buffer; }
- int16_t *outBuffer() { return mConfig.outputCfg.buffer.s16; }
+ void setInBuffer(const sp<EffectBufferHalInterface>& buffer);
+ int16_t *inBuffer() const {
+ return mInBuffer != 0 ? reinterpret_cast<int16_t*>(mInBuffer->ptr()) : NULL;
+ }
+ void setOutBuffer(const sp<EffectBufferHalInterface>& buffer);
+ int16_t *outBuffer() const {
+ return mOutBuffer != 0 ? reinterpret_cast<int16_t*>(mOutBuffer->ptr()) : NULL;
+ }
void setChain(const wp<EffectChain>& chain) { mChain = chain; }
void setThread(const wp<ThreadBase>& thread) { mThread = thread; }
const wp<ThreadBase>& thread() { return mThread; }
@@ -153,6 +157,8 @@
const effect_descriptor_t mDescriptor;// effect descriptor received from effect engine
effect_config_t mConfig; // input and output audio configuration
sp<EffectHalInterface> mEffectInterface; // Effect module HAL
+ sp<EffectBufferHalInterface> mInBuffer; // Buffers for interacting with HAL
+ sp<EffectBufferHalInterface> mOutBuffer;
status_t mStatus; // initialization status
effect_state mState; // current activation state
Vector<EffectHandle *> mHandles; // list of client handles
@@ -301,18 +307,17 @@
void setMode_l(audio_mode_t mode);
void setAudioSource_l(audio_source_t source);
- void setInBuffer(int16_t *buffer, bool ownsBuffer = false) {
+ void setInBuffer(const sp<EffectBufferHalInterface>& buffer) {
mInBuffer = buffer;
- mOwnInBuffer = ownsBuffer;
}
int16_t *inBuffer() const {
- return mInBuffer;
+ return mInBuffer != 0 ? reinterpret_cast<int16_t*>(mInBuffer->ptr()) : NULL;
}
- void setOutBuffer(int16_t *buffer) {
+ void setOutBuffer(const sp<EffectBufferHalInterface>& buffer) {
mOutBuffer = buffer;
}
int16_t *outBuffer() const {
- return mOutBuffer;
+ return mOutBuffer != 0 ? reinterpret_cast<int16_t*>(mOutBuffer->ptr()) : NULL;
}
void incTrackCnt() { android_atomic_inc(&mTrackCnt); }
@@ -394,8 +399,8 @@
mutable Mutex mLock; // mutex protecting effect list
Vector< sp<EffectModule> > mEffects; // list of effect modules
audio_session_t mSessionId; // audio session ID
- int16_t *mInBuffer; // chain input buffer
- int16_t *mOutBuffer; // chain output buffer
+ sp<EffectBufferHalInterface> mInBuffer; // chain input buffer
+ sp<EffectBufferHalInterface> mOutBuffer; // chain output buffer
// 'volatile' here means these are accessed with atomic operations instead of mutex
volatile int32_t mActiveTrackCnt; // number of active tracks connected
@@ -403,7 +408,6 @@
int32_t mTailBufferCount; // current effect tail buffer count
int32_t mMaxTailBuffers; // maximum effect tail buffers
- bool mOwnInBuffer; // true if the chain owns its input buffer
int mVolumeCtrlIdx; // index of insert effect having control over volume
uint32_t mLeftVolume; // previous volume on left channel
uint32_t mRightVolume; // previous volume on right channel
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index abfbf0f..424d2e5 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -2759,9 +2759,14 @@
status_t AudioFlinger::PlaybackThread::addEffectChain_l(const sp<EffectChain>& chain)
{
audio_session_t session = chain->sessionId();
- int16_t* buffer = reinterpret_cast<int16_t*>(mEffectBufferEnabled
- ? mEffectBuffer : mSinkBuffer);
- bool ownsBuffer = false;
+ sp<EffectBufferHalInterface> halInBuffer, halOutBuffer;
+ status_t result = EffectBufferHalInterface::mirror(
+ mEffectBufferEnabled ? mEffectBuffer : mSinkBuffer,
+ mEffectBufferEnabled ? mEffectBufferSize : mSinkBufferSize,
+ &halInBuffer);
+ if (result != OK) return result;
+ halOutBuffer = halInBuffer;
+ int16_t *buffer = reinterpret_cast<int16_t*>(halInBuffer->externalData());
ALOGV("addEffectChain_l() %p on thread %p for session %d", chain.get(), this, session);
if (session > AUDIO_SESSION_OUTPUT_MIX) {
@@ -2769,10 +2774,13 @@
// the sink buffer as input
if (mType != DIRECT) {
size_t numSamples = mNormalFrameCount * mChannelCount;
- buffer = new int16_t[numSamples];
- memset(buffer, 0, numSamples * sizeof(int16_t));
- ALOGV("addEffectChain_l() creating new input buffer %p session %d", buffer, session);
- ownsBuffer = true;
+ status_t result = EffectBufferHalInterface::allocate(
+ numSamples * sizeof(int16_t),
+ &halInBuffer);
+ if (result != OK) return result;
+ buffer = halInBuffer->audioBuffer()->s16;
+ ALOGV("addEffectChain_l() creating new input buffer %p session %d",
+ buffer, session);
}
// Attach all tracks with same session ID to this chain.
@@ -2795,9 +2803,8 @@
}
}
chain->setThread(this);
- chain->setInBuffer(buffer, ownsBuffer);
- chain->setOutBuffer(reinterpret_cast<int16_t*>(mEffectBufferEnabled
- ? mEffectBuffer : mSinkBuffer));
+ chain->setInBuffer(halInBuffer);
+ chain->setOutBuffer(halOutBuffer);
// Effect chain for session AUDIO_SESSION_OUTPUT_STAGE is inserted at end of effect
// chains list in order to be processed last as it contains output stage effects.
// Effect chain for session AUDIO_SESSION_OUTPUT_MIX is inserted before