summaryrefslogtreecommitdiffstats
path: root/libs
diff options
context:
space:
mode:
authorEric Laurent <elaurent@google.com>2010-06-23 17:38:20 -0700
committerEric Laurent <elaurent@google.com>2010-06-25 11:59:35 -0700
commit9bf80f02f7e1f4cf96bb548f9e0d4ff38dd52392 (patch)
tree83ef6399deab590f5e0fc616cf374a4648894fc4 /libs
parentcc61ac50a8703ce63ef9851ebf36d3efa33a2e25 (diff)
downloadframeworks_native-9bf80f02f7e1f4cf96bb548f9e0d4ff38dd52392.zip
frameworks_native-9bf80f02f7e1f4cf96bb548f9e0d4ff38dd52392.tar.gz
frameworks_native-9bf80f02f7e1f4cf96bb548f9e0d4ff38dd52392.tar.bz2
Various fixes and improvements in audio effects implementation
Effect API: - Use different definitions for audio device, channels, formats... in AudioSystem and EffectApi: Removed media/AudioCommon.h file created for initial version of EffectApi - Indicate audio session and output ID to effect library when calling EffectCreate(). Session ID can be useful to optimize the implementation of effect chains in the same audio session. Output ID can be used for effects implemented in audio hardware. - Renamed EffectQueryNext() function to EffectQueryEffect() and changed operating mode: now an index is passed for the queried effect instead of implicitly querying the next one. - Added CPU load and memory usage indication in effects descriptor - Added flags and commands to indicate changes in audio mode (ring tone, in call...) to effect engine - Added flag to indicate hardware accelerated effect implementation. - Renamed EffectFactoryApi.h to EffectsFactoryApi.h for consistency with EffectsFactory.c/h Effect libraries: - Reflected changes in Effect API - Several fixes in reverb implementation - Added build option TEST_EFFECT_LIBRARIES in makefile to prepare integration of actual effect library. - Replaced pointer by integer identifier for library handle returned by effects factory Audio effect framework: - Added support for audio session -1 in preparation of output stage effects configuration. - Reflected changes in Effect API - Removed volume ramp up/down when effect is inserted/removed: this has to be taken care of by effect engines. - Added some overflow verification on indexes used for deferred parameter updates via shared memory - Added hardcoded CPU and memory limit check when creating a new effect instance Change-Id: I43fee5182ee201384ea3479af6d0acb95092901d
Diffstat (limited to 'libs')
-rw-r--r--libs/audioflinger/AudioFlinger.cpp435
-rw-r--r--libs/audioflinger/AudioFlinger.h30
2 files changed, 301 insertions, 164 deletions
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index 1860793..48c04a6 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -51,7 +51,7 @@
#include "lifevibes.h"
#endif
-#include <media/EffectFactoryApi.h>
+#include <media/EffectsFactoryApi.h>
// ----------------------------------------------------------------------------
// the sim build doesn't have gettid
@@ -126,7 +126,8 @@ static bool settingsAllowed() {
AudioFlinger::AudioFlinger()
: BnAudioFlinger(),
- mAudioHardware(0), mMasterVolume(1.0f), mMasterMute(false), mNextUniqueId(1)
+ mAudioHardware(0), mMasterVolume(1.0f), mMasterMute(false), mNextUniqueId(1),
+ mTotalEffectsCpuLoad(0), mTotalEffectsMemory(0)
{
mHardwareStatus = AUDIO_HW_IDLE;
@@ -135,8 +136,8 @@ AudioFlinger::AudioFlinger()
mHardwareStatus = AUDIO_HW_INIT;
if (mAudioHardware->initCheck() == NO_ERROR) {
// open 16-bit output stream for s/w mixer
-
- setMode(AudioSystem::MODE_NORMAL);
+ mMode = AudioSystem::MODE_NORMAL;
+ setMode(mMode);
setMasterVolume(1.0f);
setMasterMute(false);
@@ -431,6 +432,8 @@ status_t AudioFlinger::setMasterVolume(float value)
status_t AudioFlinger::setMode(int mode)
{
+ status_t ret;
+
// check calling permissions
if (!settingsAllowed()) {
return PERMISSION_DENIED;
@@ -440,15 +443,23 @@ status_t AudioFlinger::setMode(int mode)
return BAD_VALUE;
}
- AutoMutex lock(mHardwareLock);
- mHardwareStatus = AUDIO_HW_SET_MODE;
- status_t ret = mAudioHardware->setMode(mode);
-#ifdef LVMX
+ { // scope for the lock
+ AutoMutex lock(mHardwareLock);
+ mHardwareStatus = AUDIO_HW_SET_MODE;
+ ret = mAudioHardware->setMode(mode);
+ mHardwareStatus = AUDIO_HW_IDLE;
+ }
+
if (NO_ERROR == ret) {
+ Mutex::Autolock _l(mLock);
+ mMode = mode;
+ for (uint32_t i = 0; i < mPlaybackThreads.size(); i++)
+ mPlaybackThreads.valueAt(i)->setMode(mode);
+#ifdef LVMX
LifeVibes::setMode(mode);
- }
#endif
- mHardwareStatus = AUDIO_HW_IDLE;
+ }
+
return ret;
}
@@ -1385,6 +1396,15 @@ sp<AudioFlinger::EffectChain> AudioFlinger::PlaybackThread::getEffectChain_l(int
return chain;
}
+void AudioFlinger::PlaybackThread::setMode(uint32_t mode)
+{
+ Mutex::Autolock _l(mLock);
+ size_t size = mEffectChains.size();
+ for (size_t i = 0; i < size; i++) {
+ mEffectChains[i]->setMode(mode);
+ }
+}
+
// ----------------------------------------------------------------------------
AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device)
@@ -1803,9 +1823,9 @@ void AudioFlinger::MixerThread::invalidateTracks(int streamType)
t->mCblk->flags |= CBLK_INVALID_ON;
t->mCblk->cv.signal();
t->mCblk->lock.unlock();
- }
- }
}
+ }
+}
// getTrackName_l() must be called with ThreadBase::mLock held
@@ -4466,10 +4486,10 @@ status_t AudioFlinger::queryNumberEffects(uint32_t *numEffects)
return EffectQueryNumberEffects(numEffects);
}
-status_t AudioFlinger::queryNextEffect(effect_descriptor_t *descriptor)
+status_t AudioFlinger::queryEffect(uint32_t index, effect_descriptor_t *descriptor)
{
Mutex::Autolock _l(mLock);
- return EffectQueryNext(descriptor);
+ return EffectQueryEffect(index, descriptor);
}
status_t AudioFlinger::getEffectDescriptor(effect_uuid_t *pUuid, effect_descriptor_t *descriptor)
@@ -4529,10 +4549,10 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid,
LOGW("createEffect() error %d from EffectQueryNumberEffects", lStatus);
goto Exit;
}
- for (; numEffects > 0; numEffects--) {
- lStatus = EffectQueryNext(&desc);
+ for (uint32_t i = 0; i < numEffects; i++) {
+ lStatus = EffectQueryEffect(i, &desc);
if (lStatus < 0) {
- LOGW("createEffect() error %d from EffectQueryNext", lStatus);
+ LOGW("createEffect() error %d from EffectQueryEffect", lStatus);
continue;
}
if (memcmp(&desc.type, &pDesc->type, sizeof(effect_uuid_t)) == 0) {
@@ -4567,6 +4587,13 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid,
goto Exit;
}
+ // Session -1 is reserved for output stage effects that can only be created
+ // by audio policy manager (running in same process)
+ if (sessionId == -1 && getpid() != IPCThreadState::self()->getCallingPid()) {
+ lStatus = INVALID_OPERATION;
+ goto Exit;
+ }
+
// return effect descriptor
memcpy(pDesc, &desc, sizeof(effect_descriptor_t));
@@ -4574,7 +4601,7 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid,
// output threads.
// TODO: allow attachment of effect to inputs
if (output == 0) {
- if (sessionId == 0) {
+ if (sessionId <= 0) {
// default to first output
// TODO: define criteria to choose output when not specified. Or
// receive output from audio policy manager
@@ -4621,6 +4648,33 @@ Exit:
return handle;
}
+status_t AudioFlinger::registerEffectResource_l(effect_descriptor_t *desc) {
+ if (mTotalEffectsCpuLoad + desc->cpuLoad > MAX_EFFECTS_CPU_LOAD) {
+ LOGW("registerEffectResource() CPU Load limit exceeded for Fx %s, CPU %f MIPS",
+ desc->name, (float)desc->cpuLoad/10);
+ return INVALID_OPERATION;
+ }
+ if (mTotalEffectsMemory + desc->memoryUsage > MAX_EFFECTS_MEMORY) {
+ LOGW("registerEffectResource() memory limit exceeded for Fx %s, Memory %d KB",
+ desc->name, desc->memoryUsage);
+ return INVALID_OPERATION;
+ }
+ mTotalEffectsCpuLoad += desc->cpuLoad;
+ mTotalEffectsMemory += desc->memoryUsage;
+ LOGV("registerEffectResource_l() effect %s, CPU %d, memory %d",
+ desc->name, desc->cpuLoad, desc->memoryUsage);
+ LOGV(" total CPU %d, total memory %d", mTotalEffectsCpuLoad, mTotalEffectsMemory);
+ return NO_ERROR;
+}
+
+void AudioFlinger::unregisterEffectResource_l(effect_descriptor_t *desc) {
+ mTotalEffectsCpuLoad -= desc->cpuLoad;
+ mTotalEffectsMemory -= desc->memoryUsage;
+ LOGV("unregisterEffectResource_l() effect %s, CPU %d, memory %d",
+ desc->name, desc->cpuLoad, desc->memoryUsage);
+ LOGV(" total CPU %d, total memory %d", mTotalEffectsCpuLoad, mTotalEffectsMemory);
+}
+
// PlaybackThread::createEffect_l() must be called with AudioFlinger::mLock held
sp<AudioFlinger::EffectHandle> AudioFlinger::PlaybackThread::createEffect_l(
const sp<AudioFlinger::Client>& client,
@@ -4638,6 +4692,7 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::PlaybackThread::createEffect_l(
sp<Track> track;
sp<EffectChain> chain;
bool effectCreated = false;
+ bool effectRegistered = false;
if (mOutput == 0) {
LOGW("createEffect_l() Audio driver not initialized.");
@@ -4680,20 +4735,26 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::PlaybackThread::createEffect_l(
LOGV("createEffect_l() got effect %p on chain %p", effect == 0 ? 0 : effect.get(), chain.get());
if (effect == 0) {
+ // Check CPU and memory usage
+ lStatus = mAudioFlinger->registerEffectResource_l(desc);
+ if (lStatus != NO_ERROR) {
+ goto Exit;
+ }
+ effectRegistered = true;
// create a new effect module if none present in the chain
- effectCreated = true;
effect = new EffectModule(this, chain, desc, mAudioFlinger->nextUniqueId(), sessionId);
lStatus = effect->status();
if (lStatus != NO_ERROR) {
goto Exit;
}
- //TODO: handle CPU load and memory usage here
lStatus = chain->addEffect(effect);
if (lStatus != NO_ERROR) {
goto Exit;
}
+ effectCreated = true;
effect->setDevice(mDevice);
+ effect->setMode(mAudioFlinger->getMode());
}
// create effect handle and connect it to effect module
handle = new EffectHandle(effect, client, effectClient, priority);
@@ -4705,11 +4766,14 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::PlaybackThread::createEffect_l(
Exit:
if (lStatus != NO_ERROR && lStatus != ALREADY_EXISTS) {
- if (chain != 0 && effectCreated) {
+ if (effectCreated) {
if (chain->removeEffect(effect) == 0) {
removeEffectChain_l(chain);
}
}
+ if (effectRegistered) {
+ mAudioFlinger->unregisterEffectResource_l(desc);
+ }
handle.clear();
}
@@ -4719,21 +4783,37 @@ Exit:
return handle;
}
+void AudioFlinger::PlaybackThread::disconnectEffect(const sp< EffectModule>& effect,
+ const wp<EffectHandle>& handle) {
+ effect_descriptor_t desc = effect->desc();
+ Mutex::Autolock _l(mLock);
+ // delete the effect module if removing last handle on it
+ if (effect->removeHandle(handle) == 0) {
+ if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
+ detachAuxEffect_l(effect->id());
+ }
+ sp<EffectChain> chain = effect->chain().promote();
+ if (chain != 0) {
+ // remove effect chain if remove last effect
+ if (chain->removeEffect(effect) == 0) {
+ removeEffectChain_l(chain);
+ }
+ }
+ mLock.unlock();
+ mAudioFlinger->mLock.lock();
+ mAudioFlinger->unregisterEffectResource_l(&desc);
+ mAudioFlinger->mLock.unlock();
+ }
+}
+
status_t AudioFlinger::PlaybackThread::addEffectChain_l(const sp<EffectChain>& chain)
{
int session = chain->sessionId();
int16_t *buffer = mMixBuffer;
+ bool ownsBuffer = false;
LOGV("addEffectChain_l() %p on thread %p for session %d", chain.get(), this, session);
- if (session == 0) {
- chain->setInBuffer(buffer, false);
- chain->setOutBuffer(buffer);
- // Effect chain for session 0 is inserted at end of effect chains list
- // to be processed last as it contains output mix effects to apply after
- // all track specific effects
- mEffectChains.add(chain);
- } else {
- bool ownsBuffer = false;
+ if (session > 0) {
// Only one effect chain can be present in direct output thread and it uses
// the mix buffer as input
if (mType != DIRECT) {
@@ -4743,33 +4823,43 @@ status_t AudioFlinger::PlaybackThread::addEffectChain_l(const sp<EffectChain>& c
LOGV("addEffectChain_l() creating new input buffer %p session %d", buffer, session);
ownsBuffer = true;
}
- chain->setInBuffer(buffer, ownsBuffer);
- chain->setOutBuffer(mMixBuffer);
- // Effect chain for session other than 0 is inserted at beginning of effect
- // chains list to be processed before output mix effects. Relative order between
- // sessions other than 0 is not important
- mEffectChains.insertAt(chain, 0);
- }
- // Attach all tracks with same session ID to this chain.
- for (size_t i = 0; i < mTracks.size(); ++i) {
- sp<Track> track = mTracks[i];
- if (session == track->sessionId()) {
- LOGV("addEffectChain_l() track->setMainBuffer track %p buffer %p", track.get(), buffer);
- track->setMainBuffer(buffer);
+ // Attach all tracks with same session ID to this chain.
+ for (size_t i = 0; i < mTracks.size(); ++i) {
+ sp<Track> track = mTracks[i];
+ if (session == track->sessionId()) {
+ LOGV("addEffectChain_l() track->setMainBuffer track %p buffer %p", track.get(), buffer);
+ track->setMainBuffer(buffer);
+ }
}
- }
- // indicate all active tracks in the chain
- for (size_t i = 0 ; i < mActiveTracks.size() ; ++i) {
- sp<Track> track = mActiveTracks[i].promote();
- if (track == 0) continue;
- if (session == track->sessionId()) {
- LOGV("addEffectChain_l() activating track %p on session %d", track.get(), session);
- chain->startTrack();
+ // indicate all active tracks in the chain
+ for (size_t i = 0 ; i < mActiveTracks.size() ; ++i) {
+ sp<Track> track = mActiveTracks[i].promote();
+ if (track == 0) continue;
+ if (session == track->sessionId()) {
+ LOGV("addEffectChain_l() activating track %p on session %d", track.get(), session);
+ chain->startTrack();
+ }
}
}
+ chain->setInBuffer(buffer, ownsBuffer);
+ chain->setOutBuffer(mMixBuffer);
+ // Effect chain for session -1 is inserted at end of effect chains list
+ // in order to be processed last as it contains output stage effects
+ // Effect chain for session 0 is inserted before session -1 to be processed
+ // after track specific effects and before output stage
+ // Effect chain for session other than 0 is inserted at beginning of effect
+ // chains list to be processed before output mix effects. Relative order between
+ // sessions other than 0 is not important
+ size_t size = mEffectChains.size();
+ size_t i = 0;
+ for (i = 0; i < size; i++) {
+ if (mEffectChains[i]->sessionId() < session) break;
+ }
+ mEffectChains.insertAt(chain, i);
+
return NO_ERROR;
}
@@ -4884,7 +4974,8 @@ AudioFlinger::EffectModule::EffectModule(const wp<ThreadBase>& wThread,
memcpy(&mDescriptor, desc, sizeof(effect_descriptor_t));
// create effect engine from effect factory
- mStatus = EffectCreate(&desc->uuid, &mEffectInterface);
+ mStatus = EffectCreate(&desc->uuid, sessionId, p->id(), &mEffectInterface);
+
if (mStatus != NO_ERROR) {
return;
}
@@ -4969,22 +5060,11 @@ void AudioFlinger::EffectModule::disconnect(const wp<EffectHandle>& handle)
// keep a strong reference on this EffectModule to avoid calling the
// destructor before we exit
sp<EffectModule> keep(this);
- sp<ThreadBase> thread = mThread.promote();
- if (thread != 0) {
- Mutex::Autolock _l(thread->mLock);
- // delete the effect module if removing last handle on it
- if (removeHandle(handle) == 0) {
+ {
+ sp<ThreadBase> thread = mThread.promote();
+ if (thread != 0) {
PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
- if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
- playbackThread->detachAuxEffect_l(mId);
- }
- sp<EffectChain> chain = mChain.promote();
- if (chain != 0) {
- // remove effect chain if remove last effect
- if (chain->removeEffect(keep) == 0) {
- playbackThread->removeEffectChain_l(chain);
- }
- }
+ playbackThread->disconnectEffect(keep, handle);
}
}
}
@@ -5007,88 +5087,25 @@ void AudioFlinger::EffectModule::process()
// TODO: handle effects with buffer provider
if (mState != ACTIVE) {
- uint32_t count = mConfig.inputCfg.buffer.frameCount;
- int32_t amp = 32767L << 16;
- int32_t step = amp / count;
- int16_t *pIn = mConfig.inputCfg.buffer.s16;
- int16_t *pOut = mConfig.outputCfg.buffer.s16;
- int inChannels;
- int outChannels;
-
- if (mConfig.inputCfg.channels == CHANNEL_MONO) {
- inChannels = 1;
- } else {
- inChannels = 2;
- }
- if (mConfig.outputCfg.channels == CHANNEL_MONO) {
- outChannels = 1;
- } else {
- outChannels = 2;
- }
-
switch (mState) {
case RESET:
reset();
+ mState = STARTING;
// clear auxiliary effect input buffer for next accumulation
if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
memset(mConfig.inputCfg.buffer.raw, 0, mConfig.inputCfg.buffer.frameCount*sizeof(int32_t));
}
- step = -step;
- mState = STARTING;
- break;
+ return;
case STARTING:
start();
- amp = 0;
- pOut = mConfig.inputCfg.buffer.s16;
- outChannels = inChannels;
mState = ACTIVE;
break;
case STOPPING:
- step = -step;
- pOut = mConfig.inputCfg.buffer.s16;
- outChannels = inChannels;
mState = STOPPED;
break;
case STOPPED:
stop();
- amp = 0;
mState = IDLE;
- break;
- }
-
- // ramp volume down or up before activating or deactivating the effect
- if (inChannels == 1) {
- if (outChannels == 1) {
- while (count--) {
- *pOut++ = (int16_t)(((int32_t)*pIn++ * (amp >> 16)) >> 15);
- amp += step;
- }
- } else {
- while (count--) {
- int32_t smp = (int16_t)(((int32_t)*pIn++ * (amp >> 16)) >> 15);
- *pOut++ = smp;
- *pOut++ = smp;
- amp += step;
- }
- }
- } else {
- if (outChannels == 1) {
- while (count--) {
- int32_t smp = (((int32_t)*pIn * (amp >> 16)) >> 16) +
- (((int32_t)*(pIn + 1) * (amp >> 16)) >> 16);
- pIn += 2;
- *pOut++ = (int16_t)smp;
- amp += step;
- }
- } else {
- while (count--) {
- *pOut++ = (int16_t)((int32_t)*pIn++ * (amp >> 16)) >> 15;
- *pOut++ = (int16_t)((int32_t)*pIn++ * (amp >> 16)) >> 15;
- amp += step;
- }
- }
- }
- if (mState == STARTING || mState == IDLE) {
return;
}
}
@@ -5148,8 +5165,8 @@ status_t AudioFlinger::EffectModule::configure()
mConfig.inputCfg.channels = channels;
}
mConfig.outputCfg.channels = channels;
- mConfig.inputCfg.format = PCM_FORMAT_S15;
- mConfig.outputCfg.format = PCM_FORMAT_S15;
+ mConfig.inputCfg.format = SAMPLE_FORMAT_PCM_S15;
+ mConfig.outputCfg.format = SAMPLE_FORMAT_PCM_S15;
mConfig.inputCfg.samplingRate = thread->sampleRate();
mConfig.outputCfg.samplingRate = mConfig.inputCfg.samplingRate;
mConfig.inputCfg.bufferProvider.cookie = NULL;
@@ -5160,7 +5177,7 @@ status_t AudioFlinger::EffectModule::configure()
mConfig.outputCfg.bufferProvider.releaseBuffer = NULL;
mConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
// Insert effect:
- // - in session 0, always overwrites output buffer: input buffer == output buffer
+ // - in session 0 or -1, always overwrites output buffer: input buffer == output buffer
// - in other sessions:
// last effect in the chain accumulates in output buffer: input buffer != output buffer
// other effect: overwrites output buffer: input buffer == output buffer
@@ -5331,7 +5348,12 @@ status_t AudioFlinger::EffectModule::setVolume(uint32_t *left, uint32_t *right,
status_t AudioFlinger::EffectModule::setDevice(uint32_t device)
{
status_t status = NO_ERROR;
- if ((mDescriptor.flags & EFFECT_FLAG_DEVICE_MASK) == EFFECT_FLAG_DEVICE_MASK) {
+ if ((mDescriptor.flags & EFFECT_FLAG_DEVICE_MASK) == EFFECT_FLAG_DEVICE_IND) {
+ // convert device bit field from AudioSystem to EffectApi format.
+ device = deviceAudioSystemToEffectApi(device);
+ if (device == 0) {
+ return BAD_VALUE;
+ }
status_t cmdStatus;
int size = sizeof(status_t);
status = (*mEffectInterface)->command(mEffectInterface, EFFECT_CMD_SET_DEVICE, sizeof(uint32_t), &device, &size, &cmdStatus);
@@ -5342,6 +5364,70 @@ status_t AudioFlinger::EffectModule::setDevice(uint32_t device)
return status;
}
+status_t AudioFlinger::EffectModule::setMode(uint32_t mode)
+{
+ status_t status = NO_ERROR;
+ if ((mDescriptor.flags & EFFECT_FLAG_AUDIO_MODE_MASK) == EFFECT_FLAG_AUDIO_MODE_IND) {
+ // convert audio mode from AudioSystem to EffectApi format.
+ int effectMode = modeAudioSystemToEffectApi(mode);
+ if (effectMode < 0) {
+ return BAD_VALUE;
+ }
+ status_t cmdStatus;
+ int size = sizeof(status_t);
+ status = (*mEffectInterface)->command(mEffectInterface, EFFECT_CMD_SET_AUDIO_MODE, sizeof(int), &effectMode, &size, &cmdStatus);
+ if (status == NO_ERROR) {
+ status = cmdStatus;
+ }
+ }
+ return status;
+}
+
+// update this table when AudioSystem::audio_devices or audio_device_e (in EffectApi.h) are modified
+const uint32_t AudioFlinger::EffectModule::sDeviceConvTable[] = {
+ DEVICE_EARPIECE, // AudioSystem::DEVICE_OUT_EARPIECE
+ DEVICE_SPEAKER, // AudioSystem::DEVICE_OUT_SPEAKER
+ DEVICE_WIRED_HEADSET, // case AudioSystem::DEVICE_OUT_WIRED_HEADSET
+ DEVICE_WIRED_HEADPHONE, // AudioSystem::DEVICE_OUT_WIRED_HEADPHONE
+ DEVICE_BLUETOOTH_SCO, // AudioSystem::DEVICE_OUT_BLUETOOTH_SCO
+ DEVICE_BLUETOOTH_SCO_HEADSET, // AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET
+ DEVICE_BLUETOOTH_SCO_CARKIT, // AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT
+ DEVICE_BLUETOOTH_A2DP, // AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP
+ DEVICE_BLUETOOTH_A2DP_HEADPHONES, // AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES
+ DEVICE_BLUETOOTH_A2DP_SPEAKER, // AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER
+ DEVICE_AUX_DIGITAL // AudioSystem::DEVICE_OUT_AUX_DIGITAL
+};
+
+uint32_t AudioFlinger::EffectModule::deviceAudioSystemToEffectApi(uint32_t device)
+{
+ uint32_t deviceOut = 0;
+ while (device) {
+ const uint32_t i = 31 - __builtin_clz(device);
+ device &= ~(1 << i);
+ if (i >= sizeof(sDeviceConvTable)/sizeof(uint32_t)) {
+ LOGE("device convertion error for AudioSystem device 0x%08x", device);
+ return 0;
+ }
+ deviceOut |= (uint32_t)sDeviceConvTable[i];
+ }
+ return deviceOut;
+}
+
+// update this table when AudioSystem::audio_mode or audio_mode_e (in EffectApi.h) are modified
+const uint32_t AudioFlinger::EffectModule::sModeConvTable[] = {
+ AUDIO_MODE_NORMAL, // AudioSystem::MODE_NORMAL
+ AUDIO_MODE_RINGTONE, // AudioSystem::MODE_RINGTONE
+ AUDIO_MODE_IN_CALL // AudioSystem::MODE_IN_CALL
+};
+
+int AudioFlinger::EffectModule::modeAudioSystemToEffectApi(uint32_t mode)
+{
+ int modeOut = -1;
+ if (mode < sizeof(sModeConvTable) / sizeof(uint32_t)) {
+ modeOut = (int)sModeConvTable[mode];
+ }
+ return modeOut;
+}
status_t AudioFlinger::EffectModule::dump(int fd, const Vector<String16>& args)
{
@@ -5525,7 +5611,16 @@ status_t AudioFlinger::EffectHandle::command(int cmdCode, int cmdSize, void *pCm
int rsize = sizeof(int);
int *p = (int *)(mBuffer + mCblk->serverIndex);
int size = *p++;
+ if (((uint8_t *)p + size) > mBuffer + mCblk->clientIndex) {
+ LOGW("command(): invalid parameter block size");
+ break;
+ }
effect_param_t *param = (effect_param_t *)p;
+ if (param->psize == 0 || param->vsize == 0) {
+ LOGW("command(): null parameter or value size");
+ mCblk->serverIndex += size;
+ continue;
+ }
int psize = sizeof(effect_param_t) + ((param->psize - 1) / sizeof(int) + 1) * sizeof(int) + param->vsize;
status_t ret = mEffect->command(EFFECT_CMD_SET_PARAM, psize, p, &rsize, &reply);
if (ret == NO_ERROR) {
@@ -5659,7 +5754,7 @@ void AudioFlinger::EffectChain::process_l()
}
// if no track is active, input buffer must be cleared here as the mixer process
// will not do it
- if (mSessionId != 0 && activeTracks() == 0) {
+ if (mSessionId > 0 && activeTracks() == 0) {
sp<ThreadBase> thread = mThread.promote();
if (thread != 0) {
size_t numSamples = thread->frameCount() * thread->channelCount();
@@ -5697,15 +5792,16 @@ status_t AudioFlinger::EffectChain::addEffect(sp<EffectModule>& effect)
} else {
// Insert effects are inserted at the end of mEffects vector as they are processed
// after track and auxiliary effects.
- // Insert effect order:
- // if EFFECT_FLAG_INSERT_FIRST or EFFECT_FLAG_INSERT_EXCLUSIVE insert as first insert effect
+ // Insert effect order as a function of indicated preference:
+ // if EFFECT_FLAG_INSERT_EXCLUSIVE, insert in first position or reject if
+ // another effect is present
+ // else if EFFECT_FLAG_INSERT_FIRST, insert in first position or after the
+ // last effect claiming first position
+ // else if EFFECT_FLAG_INSERT_LAST, insert in last position or before the
+ // first effect claiming last position
// else if EFFECT_FLAG_INSERT_ANY insert after first or before last
- // else insert as last insert effect
- // Reject insertion if:
- // - EFFECT_FLAG_INSERT_EXCLUSIVE and another effect is present
- // - an effect with EFFECT_FLAG_INSERT_EXCLUSIVE is present
- // - EFFECT_FLAG_INSERT_FIRST or EFFECT_FLAG_INSERT_LAST and an effect with same
- // preference is present
+ // Reject insertion if an effect with EFFECT_FLAG_INSERT_EXCLUSIVE is
+ // already present
int size = (int)mEffects.size();
int idx_insert = size;
@@ -5719,35 +5815,40 @@ status_t AudioFlinger::EffectChain::addEffect(sp<EffectModule>& effect)
if (iMode == EFFECT_FLAG_TYPE_INSERT) {
// check invalid effect chaining combinations
if (insertPref == EFFECT_FLAG_INSERT_EXCLUSIVE ||
- iPref == EFFECT_FLAG_INSERT_EXCLUSIVE ||
- (insertPref != EFFECT_FLAG_INSERT_ANY
- && insertPref == iPref)) {
+ iPref == EFFECT_FLAG_INSERT_EXCLUSIVE) {
+ LOGW("addEffect() could not insert effect %s: exclusive conflict with %s", desc.name, d.name);
return INVALID_OPERATION;
}
- // remember position of first insert effect
+ // remember position of first insert effect and by default
+ // select this as insert position for new effect
if (idx_insert == size) {
idx_insert = i;
}
- // remember position of insert effect claiming
- // first place
+ // remember position of last insert effect claiming
+ // first position
if (iPref == EFFECT_FLAG_INSERT_FIRST) {
idx_insert_first = i;
}
- // remember position of insert effect claiming
- // last place
- if (iPref == EFFECT_FLAG_INSERT_LAST) {
+ // remember position of first insert effect claiming
+ // last position
+ if (iPref == EFFECT_FLAG_INSERT_LAST &&
+ idx_insert_last == -1) {
idx_insert_last = i;
}
}
}
- // modify idx_insert from first place if needed
- if (idx_insert_first != -1) {
- idx_insert = idx_insert_first + 1;
- } else if (idx_insert_last != -1) {
- idx_insert = idx_insert_last;
- } else if (insertPref == EFFECT_FLAG_INSERT_LAST) {
- idx_insert = size;
+ // modify idx_insert from first position if needed
+ if (insertPref == EFFECT_FLAG_INSERT_LAST) {
+ if (idx_insert_last != -1) {
+ idx_insert = idx_insert_last;
+ } else {
+ idx_insert = size;
+ }
+ } else {
+ if (idx_insert_first != -1) {
+ idx_insert = idx_insert_first + 1;
+ }
}
// always read samples from chain input buffer
@@ -5764,14 +5865,14 @@ status_t AudioFlinger::EffectChain::addEffect(sp<EffectModule>& effect)
} else {
effect->setOutBuffer(mInBuffer);
}
- status_t status = mEffects.insertAt(effect, idx_insert);
+ mEffects.insertAt(effect, idx_insert);
// Always give volume control to last effect in chain with volume control capability
if (((desc.flags & EFFECT_FLAG_VOLUME_MASK) & EFFECT_FLAG_VOLUME_CTRL) &&
mVolumeCtrlIdx < idx_insert) {
mVolumeCtrlIdx = idx_insert;
}
- LOGV("addEffect() effect %p, added in chain %p at rank %d status %d", effect.get(), this, idx_insert, status);
+ LOGV("addEffect() effect %p, added in chain %p at rank %d", effect.get(), this, idx_insert);
}
effect->configure();
return NO_ERROR;
@@ -5823,6 +5924,14 @@ void AudioFlinger::EffectChain::setDevice(uint32_t device)
}
}
+void AudioFlinger::EffectChain::setMode(uint32_t mode)
+{
+ size_t size = mEffects.size();
+ for (size_t i = 0; i < size; i++) {
+ mEffects[i]->setMode(mode);
+ }
+}
+
bool AudioFlinger::EffectChain::setVolume(uint32_t *left, uint32_t *right)
{
uint32_t newLeft = *left;
diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h
index e543334..42dca4c 100644
--- a/libs/audioflinger/AudioFlinger.h
+++ b/libs/audioflinger/AudioFlinger.h
@@ -149,7 +149,7 @@ public:
virtual status_t queryNumberEffects(uint32_t *numEffects);
- virtual status_t queryNextEffect(effect_descriptor_t *descriptor);
+ virtual status_t queryEffect(uint32_t index, effect_descriptor_t *descriptor);
virtual status_t getEffectDescriptor(effect_uuid_t *pUuid, effect_descriptor_t *descriptor);
@@ -163,6 +163,9 @@ public:
int *id,
int *enabled);
+ status_t registerEffectResource_l(effect_descriptor_t *desc);
+ void unregisterEffectResource_l(effect_descriptor_t *desc);
+
enum hardware_call_state {
AUDIO_HW_IDLE = 0,
AUDIO_HW_INIT,
@@ -200,6 +203,8 @@ public:
Parcel* reply,
uint32_t flags);
+ uint32_t getMode() { return mMode; }
+
private:
AudioFlinger();
virtual ~AudioFlinger();
@@ -601,6 +606,8 @@ private:
effect_descriptor_t *desc,
int *enabled,
status_t *status);
+ void disconnectEffect(const sp< EffectModule>& effect,
+ const wp<EffectHandle>& handle);
bool hasAudioSession(int sessionId);
sp<EffectChain> getEffectChain(int sessionId);
@@ -614,6 +621,7 @@ private:
void detachAuxEffect_l(int effectId);
status_t attachAuxEffect(const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId);
status_t attachAuxEffect_l(const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId);
+ void setMode(uint32_t mode);
struct stream_type_t {
stream_type_t()
@@ -930,9 +938,11 @@ private:
size_t removeHandle (const wp<EffectHandle>& handle);
effect_descriptor_t& desc() { return mDescriptor; }
+ wp<EffectChain>& chain() { return mChain; }
status_t setDevice(uint32_t device);
status_t setVolume(uint32_t *left, uint32_t *right, bool controller);
+ status_t setMode(uint32_t mode);
status_t dump(int fd, const Vector<String16>& args);
@@ -944,6 +954,14 @@ private:
status_t start();
status_t stop();
+ // update this table when AudioSystem::audio_devices or audio_device_e (in EffectApi.h) are modified
+ static const uint32_t sDeviceConvTable[];
+ static uint32_t deviceAudioSystemToEffectApi(uint32_t device);
+
+ // update this table when AudioSystem::audio_mode or audio_mode_e (in EffectApi.h) are modified
+ static const uint32_t sModeConvTable[];
+ static int modeAudioSystemToEffectApi(uint32_t mode);
+
Mutex mLock; // mutex for process, commands and handles list protection
wp<ThreadBase> mThread; // parent thread
wp<EffectChain> mChain; // parent effect chain
@@ -1042,6 +1060,8 @@ private:
sp<EffectModule> getVolumeController();
bool setVolume(uint32_t *left, uint32_t *right);
void setDevice(uint32_t device);
+ void setMode(uint32_t mode);
+
void setInBuffer(int16_t *buffer, bool ownsBuffer = false) {
mInBuffer = buffer;
@@ -1104,6 +1124,14 @@ private:
#ifdef LVMX
int mLifeVibesClientPid;
#endif
+ uint32_t mMode;
+
+ // Maximum CPU load allocated to audio effects in 0.1 MIPS (ARMv5TE, 0 WS memory) units
+ static const uint32_t MAX_EFFECTS_CPU_LOAD = 1000;
+ // Maximum memory allocated to audio effects in KB
+ static const uint32_t MAX_EFFECTS_MEMORY = 512;
+ uint32_t mTotalEffectsCpuLoad; // current CPU load used by effects
+ uint32_t mTotalEffectsMemory; // current memory used by effects
};
// ----------------------------------------------------------------------------