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
diff --git a/media/libeffects/Android.mk b/media/libeffects/Android.mk
index ff21454..b5f1d42 100644
--- a/media/libeffects/Android.mk
+++ b/media/libeffects/Android.mk
@@ -1,5 +1,8 @@
LOCAL_PATH:= $(call my-dir)
+#
+TEST_EFFECT_LIBRARIES := true
+
# Effect factory library
include $(CLEAR_VARS)
@@ -25,7 +28,8 @@
include $(BUILD_SHARED_LIBRARY)
-# Default Reverb library
+ifeq ($(TEST_EFFECT_LIBRARIES),true)
+# Test Reverb library
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
@@ -54,7 +58,7 @@
include $(BUILD_SHARED_LIBRARY)
-# Default Equalizer library
+# Test Equalizer library
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
@@ -87,4 +91,6 @@
LOCAL_PRELINK_MODULE := false
-include $(BUILD_SHARED_LIBRARY)
\ No newline at end of file
+include $(BUILD_SHARED_LIBRARY)
+
+endif
diff --git a/media/libeffects/AudioCoefInterpolator.cpp b/media/libeffects/AudioCoefInterpolator.cpp
index 05898c9..039ab9f 100644
--- a/media/libeffects/AudioCoefInterpolator.cpp
+++ b/media/libeffects/AudioCoefInterpolator.cpp
@@ -46,7 +46,7 @@
while (dim-- > 0) {
if (UNLIKELY(intCoord[dim] < 0)) {
fracCoord[dim] = 0;
- } else if (UNLIKELY(intCoord[dim] >= mInDims[dim] - 1)) {
+ } else if (UNLIKELY(intCoord[dim] >= (int)mInDims[dim] - 1)) {
fracCoord[dim] = 0;
index += mInDimOffsets[dim] * (mInDims[dim] - 1);
} else {
diff --git a/media/libeffects/AudioCommon.h b/media/libeffects/AudioCommon.h
index 12d2193..444f93a 100644
--- a/media/libeffects/AudioCommon.h
+++ b/media/libeffects/AudioCommon.h
@@ -1,4 +1,4 @@
-/* //device/include/server/AudioFlinger/AudioCommon.h
+/*
**
** Copyright 2009, The Android Open Source Project
**
diff --git a/media/libeffects/AudioFormatAdapter.h b/media/libeffects/AudioFormatAdapter.h
index 8aa5e65..d93ebe9 100644
--- a/media/libeffects/AudioFormatAdapter.h
+++ b/media/libeffects/AudioFormatAdapter.h
@@ -75,7 +75,7 @@
while (numSamples > 0) {
uint32_t numSamplesIter = min(numSamples, mMaxSamplesPerCall);
uint32_t nSamplesChannels = numSamplesIter * mNumChannels;
- if (mPcmFormat == PCM_FORMAT_S7_24) {
+ if (mPcmFormat == SAMPLE_FORMAT_PCM_S7_24) {
if (mBehavior == EFFECT_BUFFER_ACCESS_WRITE) {
mpProcessor->process(
reinterpret_cast<const audio_sample_t *> (pIn),
@@ -125,7 +125,7 @@
// sample.
// numSamples The number of single-channel samples to process.
void ConvertInput(const void *& pIn, uint32_t numSamples) {
- if (mPcmFormat == PCM_FORMAT_S15) {
+ if (mPcmFormat == SAMPLE_FORMAT_PCM_S15) {
const int16_t * pIn16 = reinterpret_cast<const int16_t *>(pIn);
audio_sample_t * pOut = mBuffer;
while (numSamples-- > 0) {
@@ -143,7 +143,7 @@
// When function exist will point to the next output sample.
// numSamples The number of single-channel samples to process.
void ConvertOutput(void *& pOut, uint32_t numSamples) {
- if (mPcmFormat == PCM_FORMAT_S15) {
+ if (mPcmFormat == SAMPLE_FORMAT_PCM_S15) {
const audio_sample_t * pIn = mBuffer;
int16_t * pOut16 = reinterpret_cast<int16_t *>(pOut);
if (mBehavior == EFFECT_BUFFER_ACCESS_WRITE) {
diff --git a/media/libeffects/AudioShelvingFilter.cpp b/media/libeffects/AudioShelvingFilter.cpp
index d8abbd2..b8650ba 100644
--- a/media/libeffects/AudioShelvingFilter.cpp
+++ b/media/libeffects/AudioShelvingFilter.cpp
@@ -50,8 +50,8 @@
AudioShelvingFilter::AudioShelvingFilter(ShelfType type, int nChannels,
int sampleRate)
- : mBiquad(nChannels, sampleRate)
- , mType(type) {
+ : mType(type),
+ mBiquad(nChannels, sampleRate) {
configure(nChannels, sampleRate);
}
diff --git a/media/libeffects/EffectEqualizer.cpp b/media/libeffects/EffectEqualizer.cpp
index e39e595..d19c6b9 100644
--- a/media/libeffects/EffectEqualizer.cpp
+++ b/media/libeffects/EffectEqualizer.cpp
@@ -39,10 +39,11 @@
{0xe25aa840, 0x543b, 0x11df, 0x98a5, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // uuid
EFFECT_API_VERSION,
(EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_LAST),
+ 0, // TODO
+ 1,
"Graphic Equalizer",
"Google Inc.",
};
-static int gEffectIndex;
/////////////////// BEGIN EQ PRESETS ///////////////////////////////////////////
const int kNumBands = 5;
@@ -101,7 +102,6 @@
AudioEqualizer * pEqualizer;
};
-
//--- local function prototypes
int Equalizer_init(EqualizerContext *pContext);
@@ -116,22 +116,23 @@
extern "C" int EffectQueryNumberEffects(uint32_t *pNumEffects) {
*pNumEffects = 1;
- gEffectIndex = 0;
return 0;
} /* end EffectQueryNumberEffects */
-extern "C" int EffectQueryNext(effect_descriptor_t *pDescriptor) {
+extern "C" int EffectQueryEffect(uint32_t index, effect_descriptor_t *pDescriptor) {
if (pDescriptor == NULL) {
return -EINVAL;
}
- if (gEffectIndex++ > 0) {
- return -ENOENT;
+ if (index > 0) {
+ return -EINVAL;
}
memcpy(pDescriptor, &gEqualizerDescriptor, sizeof(effect_descriptor_t));
return 0;
} /* end EffectQueryNext */
extern "C" int EffectCreate(effect_uuid_t *uuid,
+ int32_t sessionId,
+ int32_t ioId,
effect_interface_t *pInterface) {
int ret;
int i;
@@ -160,7 +161,7 @@
*pInterface = (effect_interface_t)pContext;
- LOGV("EffectLibCreateEffect %p", pContext);
+ LOGV("EffectLibCreateEffect %p, size %d", pContext, AudioEqualizer::GetInstanceSize(kNumBands)+sizeof(EqualizerContext));
return 0;
@@ -219,8 +220,8 @@
CHECK_ARG((pConfig->inputCfg.channels == CHANNEL_MONO) || (pConfig->inputCfg.channels == CHANNEL_STEREO));
CHECK_ARG(pConfig->outputCfg.accessMode == EFFECT_BUFFER_ACCESS_WRITE
|| pConfig->outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE);
- CHECK_ARG(pConfig->inputCfg.format == PCM_FORMAT_S7_24
- || pConfig->inputCfg.format == PCM_FORMAT_S15);
+ CHECK_ARG(pConfig->inputCfg.format == SAMPLE_FORMAT_PCM_S7_24
+ || pConfig->inputCfg.format == SAMPLE_FORMAT_PCM_S15);
int channelCount;
if (pConfig->inputCfg.channels == CHANNEL_MONO) {
@@ -230,6 +231,8 @@
}
CHECK_ARG(channelCount <= AudioBiquadFilter::MAX_CHANNELS);
+ memcpy(&pContext->config, pConfig, sizeof(effect_config_t));
+
pContext->pEqualizer->configure(channelCount,
pConfig->inputCfg.samplingRate);
@@ -268,7 +271,7 @@
pContext->config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
pContext->config.inputCfg.channels = CHANNEL_STEREO;
- pContext->config.inputCfg.format = PCM_FORMAT_S15;
+ pContext->config.inputCfg.format = SAMPLE_FORMAT_PCM_S15;
pContext->config.inputCfg.samplingRate = 44100;
pContext->config.inputCfg.bufferProvider.getBuffer = NULL;
pContext->config.inputCfg.bufferProvider.releaseBuffer = NULL;
@@ -276,7 +279,7 @@
pContext->config.inputCfg.mask = EFFECT_CONFIG_ALL;
pContext->config.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE;
pContext->config.outputCfg.channels = CHANNEL_STEREO;
- pContext->config.outputCfg.format = PCM_FORMAT_S15;
+ pContext->config.outputCfg.format = SAMPLE_FORMAT_PCM_S15;
pContext->config.outputCfg.samplingRate = 44100;
pContext->config.outputCfg.bufferProvider.getBuffer = NULL;
pContext->config.outputCfg.bufferProvider.releaseBuffer = NULL;
@@ -526,6 +529,7 @@
}
pContext->adapter.process(inBuffer->raw, outBuffer->raw, outBuffer->frameCount);
+
return 0;
} // end Equalizer_process
@@ -589,6 +593,17 @@
*(int *)pReplyData = android::Equalizer_setParameter(pEqualizer, (int32_t *)p->data,
p->data + p->psize);
} break;
+ case EFFECT_CMD_ENABLE:
+ case EFFECT_CMD_DISABLE:
+ if (pReplyData == NULL || *replySize != sizeof(int)) {
+ return -EINVAL;
+ }
+ *(int *)pReplyData = 0;
+ break;
+ case EFFECT_CMD_SET_DEVICE:
+ case EFFECT_CMD_SET_VOLUME:
+ case EFFECT_CMD_SET_AUDIO_MODE:
+ break;
default:
LOGW("Equalizer_command invalid command %d",cmdCode);
return -EINVAL;
diff --git a/media/libeffects/EffectReverb.c b/media/libeffects/EffectReverb.c
index 202f50b..ada252c 100644
--- a/media/libeffects/EffectReverb.c
+++ b/media/libeffects/EffectReverb.c
@@ -24,8 +24,6 @@
#include "EffectReverb.h"
#include "EffectsMath.h"
-static int gEffectIndex;
-
// effect_interface_t interface implementation for reverb effect
const struct effect_interface_s gReverbInterface = {
Reverb_Process,
@@ -37,7 +35,10 @@
{0xc2e5d5f0, 0x94bd, 0x4763, 0x9cac, {0x4e, 0x23, 0x4d, 0x06, 0x83, 0x9e}},
{0x1f0ae2e0, 0x4ef7, 0x11df, 0xbc09, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
EFFECT_API_VERSION,
- EFFECT_FLAG_TYPE_AUXILIARY,
+ // flags other than EFFECT_FLAG_TYPE_AUXILIARY set for test purpose
+ EFFECT_FLAG_TYPE_AUXILIARY | EFFECT_FLAG_DEVICE_IND | EFFECT_FLAG_AUDIO_MODE_IND,
+ 0, // TODO
+ 33,
"Aux Environmental Reverb",
"Google Inc."
};
@@ -48,6 +49,8 @@
{0xaa476040, 0x6342, 0x11df, 0x91a4, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
EFFECT_API_VERSION,
EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST,
+ 0, // TODO
+ 33,
"Insert Environmental reverb",
"Google Inc."
};
@@ -58,6 +61,8 @@
{0x63909320, 0x53a6, 0x11df, 0xbdbd, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
EFFECT_API_VERSION,
EFFECT_FLAG_TYPE_AUXILIARY,
+ 0, // TODO
+ 33,
"Aux Preset Reverb",
"Google Inc."
};
@@ -68,6 +73,8 @@
{0xd93dc6a0, 0x6342, 0x11df, 0xb128, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
EFFECT_API_VERSION,
EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST,
+ 0, // TODO
+ 33,
"Insert Preset Reverb",
"Google Inc."
};
@@ -77,8 +84,7 @@
&gAuxEnvReverbDescriptor,
&gInsertEnvReverbDescriptor,
&gAuxPresetReverbDescriptor,
- &gInsertPresetReverbDescriptor,
- NULL
+ &gInsertPresetReverbDescriptor
};
/*----------------------------------------------------------------------------
@@ -88,25 +94,25 @@
/*--- Effect Library Interface Implementation ---*/
int EffectQueryNumberEffects(uint32_t *pNumEffects) {
- *pNumEffects = sizeof(gDescriptors) / sizeof(const effect_descriptor_t *)
- - 1;
- gEffectIndex = 0;
+ *pNumEffects = sizeof(gDescriptors) / sizeof(const effect_descriptor_t *);
return 0;
}
-int EffectQueryNext(effect_descriptor_t *pDescriptor) {
+int EffectQueryEffect(uint32_t index, effect_descriptor_t *pDescriptor) {
if (pDescriptor == NULL) {
return -EINVAL;
}
- if (gDescriptors[gEffectIndex] == NULL) {
- return -ENOENT;
+ if (index >= sizeof(gDescriptors) / sizeof(const effect_descriptor_t *)) {
+ return -EINVAL;
}
- memcpy(pDescriptor, gDescriptors[gEffectIndex++],
+ memcpy(pDescriptor, gDescriptors[index],
sizeof(effect_descriptor_t));
return 0;
}
int EffectCreate(effect_uuid_t *uuid,
+ int32_t sessionId,
+ int32_t ioId,
effect_interface_t *pInterface) {
int ret;
int i;
@@ -152,7 +158,7 @@
*pInterface = (effect_interface_t) module;
- LOGV("EffectLibCreateEffect %p", module);
+ LOGV("EffectLibCreateEffect %p ,size %d", module, sizeof(reverb_module_t));
return 0;
}
@@ -191,8 +197,23 @@
//if bypassed or the preset forces the signal to be completely dry
if (pReverb->m_bBypass) {
- if (inBuffer->raw != outBuffer->raw && !pReverb->m_Aux) {
- memcpy(outBuffer->raw, inBuffer->raw, outBuffer->frameCount * NUM_OUTPUT_CHANNELS * sizeof(int16_t));
+ if (inBuffer->raw != outBuffer->raw) {
+ int16_t smp;
+ pSrc = inBuffer->s16;
+ pDst = outBuffer->s16;
+ size_t count = inBuffer->frameCount;
+ if (pRvbModule->config.inputCfg.channels == pRvbModule->config.outputCfg.channels) {
+ count *= 2;
+ while (count--) {
+ *pDst++ = *pSrc++;
+ }
+ } else {
+ while (count--) {
+ smp = *pSrc++;
+ *pDst++ = smp;
+ *pDst++ = smp;
+ }
+ }
}
return 0;
}
@@ -226,10 +247,11 @@
numSamples -= processedSamples;
if (pReverb->m_Aux) {
- pDst += processedSamples;
+ pSrc += processedSamples;
} else {
pSrc += processedSamples * NUM_OUTPUT_CHANNELS;
}
+ pDst += processedSamples * NUM_OUTPUT_CHANNELS;
}
return 0;
@@ -292,6 +314,35 @@
*(int *)pReplyData = Reverb_setParameter(pReverb, *(int32_t *)cmd->data,
cmd->vsize, cmd->data + sizeof(int32_t));
break;
+ case EFFECT_CMD_ENABLE:
+ case EFFECT_CMD_DISABLE:
+ if (pReplyData == NULL || *replySize != sizeof(int)) {
+ return -EINVAL;
+ }
+ *(int *)pReplyData = 0;
+ break;
+ case EFFECT_CMD_SET_DEVICE:
+ if (pCmdData == NULL || cmdSize != (int)sizeof(uint32_t)) {
+ return -EINVAL;
+ }
+ LOGV("Reverb_Command EFFECT_CMD_SET_DEVICE: 0x%08x", *(uint32_t *)pCmdData);
+ break;
+ case EFFECT_CMD_SET_VOLUME: {
+ // audio output is always stereo => 2 channel volumes
+ if (pCmdData == NULL || cmdSize != (int)sizeof(uint32_t) * 2) {
+ return -EINVAL;
+ }
+ float left = (float)(*(uint32_t *)pCmdData) / (1 << 24);
+ float right = (float)(*((uint32_t *)pCmdData + 1)) / (1 << 24);
+ LOGV("Reverb_Command EFFECT_CMD_SET_VOLUME: left %f, right %f ", left, right);
+ break;
+ }
+ case EFFECT_CMD_SET_AUDIO_MODE:
+ if (pCmdData == NULL || cmdSize != (int)sizeof(uint32_t)) {
+ return -EINVAL;
+ }
+ LOGV("Reverb_Command EFFECT_CMD_SET_AUDIO_MODE: %d", *(uint32_t *)pCmdData);
+ break;
default:
LOGW("Reverb_Command invalid command %d",cmdCode);
return -EINVAL;
@@ -339,7 +390,7 @@
} else {
pRvbModule->config.inputCfg.channels = CHANNEL_STEREO;
}
- pRvbModule->config.inputCfg.format = PCM_FORMAT_S15;
+ pRvbModule->config.inputCfg.format = SAMPLE_FORMAT_PCM_S15;
pRvbModule->config.inputCfg.bufferProvider.getBuffer = NULL;
pRvbModule->config.inputCfg.bufferProvider.releaseBuffer = NULL;
pRvbModule->config.inputCfg.bufferProvider.cookie = NULL;
@@ -347,7 +398,7 @@
pRvbModule->config.inputCfg.mask = EFFECT_CONFIG_ALL;
pRvbModule->config.outputCfg.samplingRate = 44100;
pRvbModule->config.outputCfg.channels = CHANNEL_STEREO;
- pRvbModule->config.outputCfg.format = PCM_FORMAT_S15;
+ pRvbModule->config.outputCfg.format = SAMPLE_FORMAT_PCM_S15;
pRvbModule->config.outputCfg.bufferProvider.getBuffer = NULL;
pRvbModule->config.outputCfg.bufferProvider.releaseBuffer = NULL;
pRvbModule->config.outputCfg.bufferProvider.cookie = NULL;
@@ -391,8 +442,8 @@
if (pConfig->inputCfg.samplingRate
!= pConfig->outputCfg.samplingRate
|| pConfig->outputCfg.channels != OUTPUT_CHANNELS
- || pConfig->inputCfg.format != PCM_FORMAT_S15
- || pConfig->outputCfg.format != PCM_FORMAT_S15) {
+ || pConfig->inputCfg.format != SAMPLE_FORMAT_PCM_S15
+ || pConfig->outputCfg.format != SAMPLE_FORMAT_PCM_S15) {
LOGV("Reverb_Configure invalid config");
return -EINVAL;
}
@@ -1033,6 +1084,7 @@
// Convert milliseconds to => m_nRvbLpfFwd (function of m_nRvbLpfFbk)
// convert ms to samples
value32 = (value32 * pReverb->m_nSamplingRate) / 1000;
+
// calculate valid decay time range as a function of current reverb delay and
// max feed back gain. Min value <=> -40dB in one pass, Max value <=> feedback gain = -1 dB
// Calculate attenuation for each round in late reverb given a total attenuation of -6000 millibels.
@@ -1834,7 +1886,6 @@
//gsReverbObject.m_nXfadeInterval = pPreset->m_nXfadeInterval;
pReverb->m_nXfadeCounter = pReverb->m_nXfadeInterval + 1; // force update on first iteration
-
pReverb->m_nCurrentRoom = pReverb->m_nNextRoom;
return 0;
diff --git a/media/libeffects/EffectReverb.h b/media/libeffects/EffectReverb.h
index 578e09e..f5aadfa 100644
--- a/media/libeffects/EffectReverb.h
+++ b/media/libeffects/EffectReverb.h
@@ -293,8 +293,8 @@
*------------------------------------
*/
int EffectQueryNumberEffects(uint32_t *pNumEffects);
-int EffectQueryNext(effect_descriptor_t *pDescriptor);
-int EffectCreate(effect_uuid_t *effectUID, effect_interface_t *pInterface);
+int EffectQueryEffect(uint32_t index, effect_descriptor_t *pDescriptor);
+int EffectCreate(effect_uuid_t *effectUID, int32_t sessionId, int32_t ioId, effect_interface_t *pInterface);
int EffectRelease(effect_interface_t interface);
static int Reverb_Process(effect_interface_t self, audio_buffer_t *inBuffer, audio_buffer_t *outBuffer);
diff --git a/media/libeffects/EffectsFactory.c b/media/libeffects/EffectsFactory.c
index 6800765..edd6184 100644
--- a/media/libeffects/EffectsFactory.c
+++ b/media/libeffects/EffectsFactory.c
@@ -26,11 +26,16 @@
static list_elem_t *gEffectList; // list of effect_entry_t: all currently created effects
static list_elem_t *gLibraryList; // list of lib_entry_t: all currently loaded libraries
static pthread_mutex_t gLibLock = PTHREAD_MUTEX_INITIALIZER; // controls access to gLibraryList
+static uint32_t gNumEffects; // total number number of effects
static list_elem_t *gCurLib; // current library in enumeration process
static list_elem_t *gCurEffect; // current effect in enumeration process
+static uint32_t gCurEffectIdx; // current effect index in enumeration process
static const char * const gEffectLibPath = "/system/lib/soundfx"; // path to built-in effect libraries
static int gInitDone; // true is global initialization has been preformed
+static int gNextLibId; // used by loadLibrary() to allocate unique library handles
+static int gCanQueryEffect; // indicates that call to EffectQueryEffect() is valid, i.e. that the list of effects
+ // was not modified since last call to EffectQueryNumberEffects()
/////////////////////////////////////////////////
// Local functions prototypes
@@ -39,7 +44,8 @@
static int init();
static int loadLibrary(const char *libPath, int *handle);
static int unloadLibrary(int handle);
-static uint32_t numEffectModules();
+static void resetEffectEnumeration();
+static uint32_t updateNumEffects();
static int findEffect(effect_uuid_t *uuid, lib_entry_t **lib, effect_descriptor_t **desc);
static void dumpEffectDescriptor(effect_descriptor_t *desc, char *str, size_t len);
@@ -107,38 +113,53 @@
}
pthread_mutex_lock(&gLibLock);
- *pNumEffects = numEffectModules();
+ *pNumEffects = gNumEffects;
+ gCanQueryEffect = 1;
pthread_mutex_unlock(&gLibLock);
LOGV("EffectQueryNumberEffects(): %d", *pNumEffects);
return ret;
}
-int EffectQueryNext(effect_descriptor_t *pDescriptor)
+int EffectQueryEffect(uint32_t index, effect_descriptor_t *pDescriptor)
{
int ret = init();
if (ret < 0) {
return ret;
}
- if (pDescriptor == NULL) {
+ if (pDescriptor == NULL ||
+ index >= gNumEffects) {
return -EINVAL;
}
+ if (gCanQueryEffect == 0) {
+ return -ENOSYS;
+ }
pthread_mutex_lock(&gLibLock);
ret = -ENOENT;
+ if (index < gCurEffectIdx) {
+ resetEffectEnumeration();
+ }
while (gCurLib) {
if (gCurEffect) {
- memcpy(pDescriptor, gCurEffect->object, sizeof(effect_descriptor_t));
- gCurEffect = gCurEffect->next;
- ret = 0;
- break;
+ if (index == gCurEffectIdx) {
+ memcpy(pDescriptor, gCurEffect->object, sizeof(effect_descriptor_t));
+ ret = 0;
+ break;
+ } else {
+ gCurEffect = gCurEffect->next;
+ gCurEffectIdx++;
+ }
} else {
gCurLib = gCurLib->next;
gCurEffect = ((lib_entry_t *)gCurLib->object)->effects;
}
}
+
+#if (LOG_NDEBUG == 0)
char str[256];
dumpEffectDescriptor(pDescriptor, str, 256);
- LOGV("EffectQueryNext() desc:%s", str);
+ LOGV("EffectQueryEffect() desc:%s", str);
+#endif
pthread_mutex_unlock(&gLibLock);
return ret;
}
@@ -164,7 +185,7 @@
return ret;
}
-int EffectCreate(effect_uuid_t *uuid, effect_interface_t *pInterface)
+int EffectCreate(effect_uuid_t *uuid, int32_t sessionId, int32_t ioId, effect_interface_t *pInterface)
{
list_elem_t *e = gLibraryList;
lib_entry_t *l = NULL;
@@ -198,9 +219,9 @@
}
// create effect in library
- ret = l->createFx(uuid, &itfe);
- if (ret < 0) {
- LOGW("EffectCreate() library %s: could not create fx %s", l->path, d->name);
+ ret = l->createFx(uuid, sessionId, ioId, &itfe);
+ if (ret != 0) {
+ LOGW("EffectCreate() library %s: could not create fx %s, error %d", l->path, d->name, ret);
goto exit;
}
@@ -282,7 +303,10 @@
if (libPath == NULL) {
return -EINVAL;
}
- return loadLibrary(libPath, handle);
+
+ ret = loadLibrary(libPath, handle);
+ updateNumEffects();
+ return ret;
}
int EffectUnloadLibrary(int handle)
@@ -292,7 +316,9 @@
return ret;
}
- return unloadLibrary(handle);
+ ret = unloadLibrary(handle);
+ updateNumEffects();
+ return ret;
}
int EffectIsNullUuid(effect_uuid_t *uuid)
@@ -339,7 +365,7 @@
}
}
closedir(dir);
-
+ updateNumEffects();
gInitDone = 1;
LOGV("init() done");
return 0;
@@ -350,7 +376,7 @@
{
void *hdl;
effect_QueryNumberEffects_t queryNumFx;
- effect_QueryNextEffect_t queryFx;
+ effect_QueryEffect_t queryFx;
effect_CreateEffect_t createFx;
effect_ReleaseEffect_t releaseFx;
uint32_t numFx;
@@ -378,9 +404,9 @@
ret = -ENODEV;
goto error;
}
- queryFx = (effect_QueryNextEffect_t)dlsym(hdl, "EffectQueryNext");
+ queryFx = (effect_QueryEffect_t)dlsym(hdl, "EffectQueryEffect");
if (queryFx == NULL) {
- LOGW("could not get EffectQueryNext from lib %s", libPath);
+ LOGW("could not get EffectQueryEffect from lib %s", libPath);
ret = -ENODEV;
goto error;
}
@@ -409,7 +435,7 @@
ret = -ENOMEM;
goto error;
}
- ret = queryFx(d);
+ ret = queryFx(fx, d);
if (ret == 0) {
#if (LOG_NDEBUG==0)
char s[256];
@@ -434,8 +460,12 @@
LOGW("Error querying effect # %d on lib %s", fx, libPath);
}
}
+
+ pthread_mutex_lock(&gLibLock);
+
// add entry for library in gLibraryList
l = malloc(sizeof(lib_entry_t));
+ l->id = ++gNextLibId;
l->handle = hdl;
strncpy(l->path, libPath, PATH_MAX);
l->createFx = createFx;
@@ -444,14 +474,13 @@
pthread_mutex_init(&l->lock, NULL);
e = malloc(sizeof(list_elem_t));
- pthread_mutex_lock(&gLibLock);
e->next = gLibraryList;
e->object = l;
gLibraryList = e;
pthread_mutex_unlock(&gLibLock);
LOGV("loadLibrary() linked library %p", l);
- *handle = (int)hdl;
+ *handle = l->id;
return 0;
@@ -480,7 +509,7 @@
el2 = NULL;
while (el1) {
l = (lib_entry_t *)el1->object;
- if (handle == (int)l->handle) {
+ if (handle == l->id) {
if (el2) {
el2->next = el1->next;
} else {
@@ -508,6 +537,7 @@
// disable all effects from this library
pthread_mutex_lock(&l->lock);
+
el1 = gEffectList;
while (el1) {
fx = (effect_entry_t *)el1->object;
@@ -523,17 +553,23 @@
return 0;
}
+void resetEffectEnumeration()
+{
+ gCurLib = gLibraryList;
+ gCurEffect = NULL;
+ if (gCurLib) {
+ gCurEffect = ((lib_entry_t *)gCurLib->object)->effects;
+ }
+ gCurEffectIdx = 0;
+}
-
-uint32_t numEffectModules() {
- list_elem_t *e = gLibraryList;
+uint32_t updateNumEffects() {
+ list_elem_t *e;
uint32_t cnt = 0;
- // Reset pointers for EffectQueryNext()
- gCurLib = e;
- if (e) {
- gCurEffect = ((lib_entry_t *)e->object)->effects;
- }
+ resetEffectEnumeration();
+
+ e = gLibraryList;
while (e) {
lib_entry_t *l = (lib_entry_t *)e->object;
list_elem_t *efx = l->effects;
@@ -543,6 +579,8 @@
}
e = e->next;
}
+ gNumEffects = cnt;
+ gCanQueryEffect = 0;
return cnt;
}
diff --git a/media/libeffects/EffectsFactory.h b/media/libeffects/EffectsFactory.h
index 17ad3f0..8f543ca 100644
--- a/media/libeffects/EffectsFactory.h
+++ b/media/libeffects/EffectsFactory.h
@@ -20,7 +20,7 @@
#include <cutils/log.h>
#include <pthread.h>
#include <dirent.h>
-#include <media/EffectFactoryApi.h>
+#include <media/EffectsFactoryApi.h>
#if __cplusplus
@@ -35,6 +35,7 @@
typedef struct lib_entry_s {
char path[PATH_MAX];
void *handle;
+ int id;
effect_CreateEffect_t createFx;
effect_ReleaseEffect_t releaseFx;
list_elem_t *effects; //list of effect_descriptor_t