summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--media/libeffects/proxy/EffectProxy.cpp59
-rw-r--r--media/libeffects/visualizer/EffectVisualizer.cpp4
-rw-r--r--services/audioflinger/AudioFlinger.cpp89
-rw-r--r--services/audioflinger/AudioFlinger.h6
-rw-r--r--services/audioflinger/Effects.cpp49
-rw-r--r--services/audioflinger/Effects.h9
-rw-r--r--services/audioflinger/Threads.cpp30
-rw-r--r--services/audioflinger/Tracks.cpp10
8 files changed, 186 insertions, 70 deletions
diff --git a/media/libeffects/proxy/EffectProxy.cpp b/media/libeffects/proxy/EffectProxy.cpp
index 77c6e89..41640da 100644
--- a/media/libeffects/proxy/EffectProxy.cpp
+++ b/media/libeffects/proxy/EffectProxy.cpp
@@ -48,6 +48,21 @@ static const effect_descriptor_t *const gDescriptors[] =
&gProxyDescriptor,
};
+static inline bool isGetterCmd(uint32_t cmdCode)
+{
+ switch (cmdCode) {
+ case EFFECT_CMD_GET_PARAM:
+ case EFFECT_CMD_GET_CONFIG:
+ case EFFECT_CMD_GET_CONFIG_REVERSE:
+ case EFFECT_CMD_GET_FEATURE_SUPPORTED_CONFIGS:
+ case EFFECT_CMD_GET_FEATURE_CONFIG:
+ return true;
+ default:
+ return false;
+ }
+}
+
+
int EffectProxyCreate(const effect_uuid_t *uuid,
int32_t sessionId,
int32_t ioId,
@@ -155,7 +170,6 @@ int Effect_process(effect_handle_t self,
int index = pContext->index;
// if the index refers to HW , do not do anything. Just return.
if (index == SUB_FX_HOST) {
- ALOGV("Calling CoreProcess");
ret = (*pContext->eHandle[index])->process(pContext->eHandle[index],
inBuffer, outBuffer);
}
@@ -172,7 +186,7 @@ int Effect_command(effect_handle_t self,
void *pReplyData) {
EffectContext *pContext = (EffectContext *) self;
- int status;
+ int status = 0;
if (pContext == NULL) {
ALOGV("Effect_command() Proxy context is NULL");
return -EINVAL;
@@ -237,23 +251,46 @@ int Effect_command(effect_handle_t self,
ALOGV("Effect_command: effect index is neither offload nor host");
return -EINVAL;
}
- ALOGV("Effect_command: pContext->eHandle[%d]: %p",
- index, pContext->eHandle[index]);
- if (pContext->eHandle[SUB_FX_HOST])
- (*pContext->eHandle[SUB_FX_HOST])->command(
+
+ // Getter commands are only sent to the active sub effect.
+ uint32_t hostReplySize = replySize != NULL ? *replySize : 0;
+ bool hostReplied = false;
+ int hostStatus = 0;
+ uint32_t offloadReplySize = replySize != NULL ? *replySize : 0;
+ bool offloadReplied = false;
+ int offloadStatus = 0;
+
+ if (pContext->eHandle[SUB_FX_HOST] && (!isGetterCmd(cmdCode) || index == SUB_FX_HOST)) {
+ hostStatus = (*pContext->eHandle[SUB_FX_HOST])->command(
pContext->eHandle[SUB_FX_HOST], cmdCode, cmdSize,
- pCmdData, replySize, pReplyData);
- if (pContext->eHandle[SUB_FX_OFFLOAD]) {
+ pCmdData, replySize != NULL ? &hostReplySize : NULL, pReplyData);
+ hostReplied = true;
+ }
+ if (pContext->eHandle[SUB_FX_OFFLOAD] && (!isGetterCmd(cmdCode) || index == SUB_FX_OFFLOAD)) {
// In case of SET CMD, when the offload stream is unavailable,
// we will store the effect param values in the DSP effect wrapper.
// When the offload effects get enabled, we send these values to the
// DSP during Effect_config.
// So,we send the params to DSP wrapper also
- (*pContext->eHandle[SUB_FX_OFFLOAD])->command(
+ offloadStatus = (*pContext->eHandle[SUB_FX_OFFLOAD])->command(
pContext->eHandle[SUB_FX_OFFLOAD], cmdCode, cmdSize,
- pCmdData, replySize, pReplyData);
+ pCmdData, replySize != NULL ? &offloadReplySize : NULL, pReplyData);
+ offloadReplied = true;
}
- return 0;
+ // By convention the offloaded implementation reply is returned if command is processed by both
+ // host and offloaded sub effects
+ if (offloadReplied){
+ status = offloadStatus;
+ if (replySize) {
+ *replySize = offloadReplySize;
+ }
+ } else if (hostReplied) {
+ status = hostStatus;
+ if (replySize) {
+ *replySize = hostReplySize;
+ }
+ }
+ return status;
} /* end Effect_command */
diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp
index e7eccf1..96935e3 100644
--- a/media/libeffects/visualizer/EffectVisualizer.cpp
+++ b/media/libeffects/visualizer/EffectVisualizer.cpp
@@ -61,7 +61,7 @@ struct VisualizerContext {
uint32_t mCaptureSize;
uint32_t mScalingMode;
uint8_t mState;
- uint8_t mLastCaptureIdx;
+ uint32_t mLastCaptureIdx;
uint32_t mLatency;
struct timespec mBufferUpdateTime;
uint8_t mCaptureBuf[CAPTURE_BUF_SIZE];
@@ -499,7 +499,7 @@ int Visualizer_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
memcpy(pReplyData,
pContext->mCaptureBuf + CAPTURE_BUF_SIZE + capturePoint,
size);
- pReplyData += size;
+ pReplyData = (char *)pReplyData + size;
captureSize -= size;
capturePoint = 0;
}
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 626b5c2..8fbac42 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -98,7 +98,6 @@ size_t AudioFlinger::mTeeSinkOutputFrames = kTeeSinkOutputFramesDefault;
size_t AudioFlinger::mTeeSinkTrackFrames = kTeeSinkTrackFramesDefault;
#endif
-//TODO: remove when effect offload is implemented
// In order to avoid invalidating offloaded tracks each time a Visualizer is turned on and off
// we define a minimum time during which a global effect is considered enabled.
static const nsecs_t kMinGlobalEffectEnabletimeNs = seconds(7200);
@@ -2084,20 +2083,6 @@ sp<IEffect> AudioFlinger::createEffect(
goto Exit;
}
- if (io == 0) {
- if (sessionId == AUDIO_SESSION_OUTPUT_STAGE) {
- // output must be specified by AudioPolicyManager when using session
- // AUDIO_SESSION_OUTPUT_STAGE
- lStatus = BAD_VALUE;
- goto Exit;
- } else if (sessionId == AUDIO_SESSION_OUTPUT_MIX) {
- // if the output returned by getOutputForEffect() is removed before we lock the
- // mutex below, the call to checkPlaybackThread_l(io) below will detect it
- // and we will exit safely
- io = AudioSystem::getOutputForEffect(&desc);
- }
- }
-
{
Mutex::Autolock _l(mLock);
@@ -2181,20 +2166,35 @@ sp<IEffect> AudioFlinger::createEffect(
// because of code checking output when entering the function.
// Note: io is never 0 when creating an effect on an input
if (io == 0) {
- // look for the thread where the specified audio session is present
- for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
- if (mPlaybackThreads.valueAt(i)->hasAudioSession(sessionId) != 0) {
- io = mPlaybackThreads.keyAt(i);
- break;
- }
+ if (sessionId == AUDIO_SESSION_OUTPUT_STAGE) {
+ // output must be specified by AudioPolicyManager when using session
+ // AUDIO_SESSION_OUTPUT_STAGE
+ lStatus = BAD_VALUE;
+ goto Exit;
+ }
+ if (sessionId == AUDIO_SESSION_OUTPUT_MIX) {
+ // if the output returned by getOutputForEffect() is removed before we lock the
+ // mutex below, the call to checkPlaybackThread_l(io) below will detect it
+ // and we will exit safely
+ io = AudioSystem::getOutputForEffect(&desc);
+ ALOGV("createEffect got output %d", io);
}
if (io == 0) {
- for (size_t i = 0; i < mRecordThreads.size(); i++) {
- if (mRecordThreads.valueAt(i)->hasAudioSession(sessionId) != 0) {
- io = mRecordThreads.keyAt(i);
+ // look for the thread where the specified audio session is present
+ for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
+ if (mPlaybackThreads.valueAt(i)->hasAudioSession(sessionId) != 0) {
+ io = mPlaybackThreads.keyAt(i);
break;
}
}
+ if (io == 0) {
+ for (size_t i = 0; i < mRecordThreads.size(); i++) {
+ if (mRecordThreads.valueAt(i)->hasAudioSession(sessionId) != 0) {
+ io = mRecordThreads.keyAt(i);
+ break;
+ }
+ }
+ }
}
// If no output thread contains the requested session ID, default to
// first output. The effect chain will be moved to the correct output
@@ -2254,9 +2254,7 @@ status_t AudioFlinger::moveEffects(int sessionId, audio_io_handle_t srcOutput,
Mutex::Autolock _dl(dstThread->mLock);
Mutex::Autolock _sl(srcThread->mLock);
- moveEffectChain_l(sessionId, srcThread, dstThread, false);
-
- return NO_ERROR;
+ return moveEffectChain_l(sessionId, srcThread, dstThread, false);
}
// moveEffectChain_l must be called with both srcThread and dstThread mLocks held
@@ -2283,13 +2281,18 @@ status_t AudioFlinger::moveEffectChain_l(int sessionId,
// transfer all effects one by one so that new effect chain is created on new thread with
// correct buffer sizes and audio parameters and effect engines reconfigured accordingly
- audio_io_handle_t dstOutput = dstThread->id();
sp<EffectChain> dstChain;
uint32_t strategy = 0; // prevent compiler warning
sp<EffectModule> effect = chain->getEffectFromId_l(0);
+ Vector< sp<EffectModule> > removed;
+ status_t status = NO_ERROR;
while (effect != 0) {
srcThread->removeEffect_l(effect);
- dstThread->addEffect_l(effect);
+ removed.add(effect);
+ status = dstThread->addEffect_l(effect);
+ if (status != NO_ERROR) {
+ break;
+ }
// removeEffect_l() has stopped the effect if it was active so it must be restarted
if (effect->state() == EffectModule::ACTIVE ||
effect->state() == EffectModule::STOPPING) {
@@ -2301,15 +2304,15 @@ status_t AudioFlinger::moveEffectChain_l(int sessionId,
dstChain = effect->chain().promote();
if (dstChain == 0) {
ALOGW("moveEffectChain_l() cannot get chain from effect %p", effect.get());
- srcThread->addEffect_l(effect);
- return NO_INIT;
+ status = NO_INIT;
+ break;
}
strategy = dstChain->strategy();
}
if (reRegister) {
AudioSystem::unregisterEffect(effect->id());
AudioSystem::registerEffect(&effect->desc(),
- dstOutput,
+ dstThread->id(),
strategy,
sessionId,
effect->id());
@@ -2317,10 +2320,24 @@ status_t AudioFlinger::moveEffectChain_l(int sessionId,
effect = chain->getEffectFromId_l(0);
}
- return NO_ERROR;
+ if (status != NO_ERROR) {
+ for (size_t i = 0; i < removed.size(); i++) {
+ srcThread->addEffect_l(removed[i]);
+ if (dstChain != 0 && reRegister) {
+ AudioSystem::unregisterEffect(removed[i]->id());
+ AudioSystem::registerEffect(&removed[i]->desc(),
+ srcThread->id(),
+ strategy,
+ sessionId,
+ removed[i]->id());
+ }
+ }
+ }
+
+ return status;
}
-bool AudioFlinger::isGlobalEffectEnabled_l()
+bool AudioFlinger::isNonOffloadableGlobalEffectEnabled_l()
{
if (mGlobalEffectEnableTime != 0 &&
((systemTime() - mGlobalEffectEnableTime) < kMinGlobalEffectEnabletimeNs)) {
@@ -2330,14 +2347,14 @@ bool AudioFlinger::isGlobalEffectEnabled_l()
for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
sp<EffectChain> ec =
mPlaybackThreads.valueAt(i)->getEffectChain_l(AUDIO_SESSION_OUTPUT_MIX);
- if (ec != 0 && ec->isEnabled()) {
+ if (ec != 0 && ec->isNonOffloadableEnabled()) {
return true;
}
}
return false;
}
-void AudioFlinger::onGlobalEffectEnable()
+void AudioFlinger::onNonOffloadableGlobalEffectEnable()
{
Mutex::Autolock _l(mLock);
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 0992308..b41d480 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -466,9 +466,8 @@ private:
void removeClient_l(pid_t pid);
void removeNotificationClient(pid_t pid);
- //TODO: remove when effect offload is implemented
- bool isGlobalEffectEnabled_l();
- void onGlobalEffectEnable();
+ bool isNonOffloadableGlobalEffectEnabled_l();
+ void onNonOffloadableGlobalEffectEnable();
class AudioHwDevice {
public:
@@ -645,7 +644,6 @@ public:
private:
bool mIsLowRamDevice;
bool mIsDeviceTypeKnown;
- //TODO: remove when effect offload is implemented
nsecs_t mGlobalEffectEnableTime; // when a global effect was last enabled
};
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 86671a9..0ca2107 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -764,6 +764,46 @@ bool AudioFlinger::EffectModule::purgeHandles()
return enabled;
}
+status_t AudioFlinger::EffectModule::setOffloaded(bool offloaded, audio_io_handle_t io)
+{
+ Mutex::Autolock _l(mLock);
+ if (mStatus != NO_ERROR) {
+ return mStatus;
+ }
+ status_t status = NO_ERROR;
+ if ((mDescriptor.flags & EFFECT_FLAG_OFFLOAD_SUPPORTED) != 0) {
+ status_t cmdStatus;
+ uint32_t size = sizeof(status_t);
+ effect_offload_param_t cmd;
+
+ cmd.isOffload = offloaded;
+ cmd.ioHandle = io;
+ status = (*mEffectInterface)->command(mEffectInterface,
+ EFFECT_CMD_OFFLOAD,
+ sizeof(effect_offload_param_t),
+ &cmd,
+ &size,
+ &cmdStatus);
+ if (status == NO_ERROR) {
+ status = cmdStatus;
+ }
+ mOffloaded = (status == NO_ERROR) ? offloaded : false;
+ } else {
+ if (offloaded) {
+ status = INVALID_OPERATION;
+ }
+ mOffloaded = false;
+ }
+ ALOGV("setOffloaded() offloaded %d io %d status %d", offloaded, io, status);
+ return status;
+}
+
+bool AudioFlinger::EffectModule::isOffloaded() const
+{
+ Mutex::Autolock _l(mLock);
+ return mOffloaded;
+}
+
void AudioFlinger::EffectModule::dump(int fd, const Vector<String16>& args)
{
const size_t SIZE = 256;
@@ -932,14 +972,13 @@ status_t AudioFlinger::EffectHandle::enable()
}
mEnabled = false;
} else {
- //TODO: remove when effect offload is implemented
- if (thread != 0) {
+ if (thread != 0 && !mEffect->isOffloadable()) {
if ((thread->type() == ThreadBase::OFFLOAD)) {
PlaybackThread *t = (PlaybackThread *)thread.get();
t->invalidateTracks(AUDIO_STREAM_MUSIC);
}
if (mEffect->sessionId() == AUDIO_SESSION_OUTPUT_MIX) {
- thread->mAudioFlinger->onGlobalEffectEnable();
+ thread->mAudioFlinger->onNonOffloadableGlobalEffectEnable();
}
}
}
@@ -1728,12 +1767,12 @@ void AudioFlinger::EffectChain::checkSuspendOnEffectEnabled(const sp<EffectModul
}
}
-bool AudioFlinger::EffectChain::isEnabled()
+bool AudioFlinger::EffectChain::isNonOffloadableEnabled()
{
Mutex::Autolock _l(mLock);
size_t size = mEffects.size();
for (size_t i = 0; i < size; i++) {
- if (mEffects[i]->isEnabled()) {
+ if (mEffects[i]->isEnabled() && !mEffects[i]->isOffloadable()) {
return true;
}
}
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index bac50f2..c35cff0 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -111,6 +111,10 @@ public:
bool purgeHandles();
void lock() { mLock.lock(); }
void unlock() { mLock.unlock(); }
+ bool isOffloadable() const
+ { return (mDescriptor.flags & EFFECT_FLAG_OFFLOAD_SUPPORTED) != 0; }
+ status_t setOffloaded(bool offloaded, audio_io_handle_t io);
+ bool isOffloaded() const;
void dump(int fd, const Vector<String16>& args);
@@ -144,6 +148,7 @@ mutable Mutex mLock; // mutex for process, commands and handl
// sending disable command.
uint32_t mDisableWaitCnt; // current process() calls count during disable period.
bool mSuspended; // effect is suspended: temporarily disabled by framework
+ bool mOffloaded; // effect is currently offloaded to the audio DSP
};
// The EffectHandle class implements the IEffect interface. It provides resources
@@ -303,8 +308,8 @@ public:
void clearInputBuffer();
- // At least one effect in the chain is enabled
- bool isEnabled();
+ // At least one non offloadable effect in the chain is enabled
+ bool isNonOffloadableEnabled();
void dump(int fd, const Vector<String16>& args);
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 4234965..7d0ecac 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -702,14 +702,22 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::ThreadBase::createEffect_l(
goto Exit;
}
- // Do not allow effects with session ID 0 on direct output or duplicating threads
- // TODO: add rule for hw accelerated effects on direct outputs with non PCM format
- if (sessionId == AUDIO_SESSION_OUTPUT_MIX && mType != MIXER) {
- ALOGW("createEffect_l() Cannot add auxiliary effect %s to session %d",
- desc->name, sessionId);
- lStatus = BAD_VALUE;
- goto Exit;
+ // Allow global effects only on offloaded and mixer threads
+ if (sessionId == AUDIO_SESSION_OUTPUT_MIX) {
+ switch (mType) {
+ case MIXER:
+ case OFFLOAD:
+ break;
+ case DIRECT:
+ case DUPLICATING:
+ case RECORD:
+ default:
+ ALOGW("createEffect_l() Cannot add global effect %s on thread %s", desc->name, mName);
+ lStatus = BAD_VALUE;
+ goto Exit;
+ }
}
+
// Only Pre processor effects are allowed on input threads and only on input threads
if ((mType == RECORD) != ((desc->flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC)) {
ALOGW("createEffect_l() effect %s (flags %08x) created on wrong thread type %d",
@@ -752,6 +760,8 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::ThreadBase::createEffect_l(
if (lStatus != NO_ERROR) {
goto Exit;
}
+ effect->setOffloaded(mType == OFFLOAD, mId);
+
lStatus = chain->addEffect_l(effect);
if (lStatus != NO_ERROR) {
goto Exit;
@@ -813,6 +823,10 @@ status_t AudioFlinger::ThreadBase::addEffect_l(const sp<EffectModule>& effect)
sp<EffectChain> chain = getEffectChain_l(sessionId);
bool chainCreated = false;
+ ALOGD_IF((mType == OFFLOAD) && !effect->isOffloadable(),
+ "addEffect_l() on offloaded thread %p: effect %s does not support offload flags %x",
+ this, effect->desc().name, effect->desc().flags);
+
if (chain == 0) {
// create a new chain for this session
ALOGV("addEffect_l() new effect chain for session %d", sessionId);
@@ -829,6 +843,8 @@ status_t AudioFlinger::ThreadBase::addEffect_l(const sp<EffectModule>& effect)
return BAD_VALUE;
}
+ effect->setOffloaded(mType == OFFLOAD, mId);
+
status_t status = chain->addEffect_l(effect);
if (status != NO_ERROR) {
if (chainCreated) {
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 3b1874e..57aad1e 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -553,12 +553,12 @@ status_t AudioFlinger::PlaybackThread::Track::start(AudioSystem::sync_event_t ev
sp<ThreadBase> thread = mThread.promote();
if (thread != 0) {
- //TODO: remove when effect offload is implemented
if (isOffloaded()) {
Mutex::Autolock _laf(thread->mAudioFlinger->mLock);
Mutex::Autolock _lth(thread->mLock);
sp<EffectChain> ec = thread->getEffectChain_l(mSessionId);
- if (thread->mAudioFlinger->isGlobalEffectEnabled_l() || (ec != 0 && ec->isEnabled())) {
+ if (thread->mAudioFlinger->isNonOffloadableGlobalEffectEnabled_l() ||
+ (ec != 0 && ec->isNonOffloadableEnabled())) {
invalidate();
return PERMISSION_DENIED;
}
@@ -797,7 +797,11 @@ status_t AudioFlinger::PlaybackThread::Track::attachAuxEffect(int EffectId)
return INVALID_OPERATION;
}
srcThread->removeEffect_l(effect);
- playbackThread->addEffect_l(effect);
+ status = playbackThread->addEffect_l(effect);
+ if (status != NO_ERROR) {
+ srcThread->addEffect_l(effect);
+ return INVALID_OPERATION;
+ }
// removeEffect_l() has stopped the effect if it was active so it must be restarted
if (effect->state() == EffectModule::ACTIVE ||
effect->state() == EffectModule::STOPPING) {