From 1bb85d27f09cb01b7e43e08600229258edf16e60 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Thu, 25 Oct 2012 11:02:50 -0700 Subject: Switch to new fx library API Change-Id: I6603aef5e3821a8f911e3f33ef8565d04bd1e2e5 --- media/libeffects/downmix/EffectDownmix.c | 21 ------------ media/libeffects/downmix/EffectDownmix.h | 3 -- .../libeffects/lvm/wrapper/Bundle/EffectBundle.cpp | 38 ---------------------- .../libeffects/lvm/wrapper/Reverb/EffectReverb.cpp | 26 --------------- media/libeffects/preprocessing/PreProcessing.cpp | 26 --------------- media/libeffects/testlibs/EffectEqualizer.cpp | 19 ----------- media/libeffects/testlibs/EffectReverb.c | 19 ----------- media/libeffects/testlibs/EffectReverb.h | 3 -- media/libeffects/visualizer/EffectVisualizer.cpp | 19 ----------- 9 files changed, 174 deletions(-) (limited to 'media/libeffects') diff --git a/media/libeffects/downmix/EffectDownmix.c b/media/libeffects/downmix/EffectDownmix.c index 5bf052a..aa2134c 100644 --- a/media/libeffects/downmix/EffectDownmix.c +++ b/media/libeffects/downmix/EffectDownmix.c @@ -63,8 +63,6 @@ audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = { version : EFFECT_LIBRARY_API_VERSION, name : "Downmix Library", implementor : "The Android Open Source Project", - query_num_effects : DownmixLib_QueryNumberEffects, - query_effect : DownmixLib_QueryEffect, create_effect : DownmixLib_Create, release_effect : DownmixLib_Release, get_descriptor : DownmixLib_GetDescriptor, @@ -159,25 +157,6 @@ void Downmix_testIndexComputation(uint32_t mask) { /*--- Effect Library Interface Implementation ---*/ -int32_t DownmixLib_QueryNumberEffects(uint32_t *pNumEffects) { - ALOGV("DownmixLib_QueryNumberEffects()"); - *pNumEffects = kNbEffects; - return 0; -} - -int32_t DownmixLib_QueryEffect(uint32_t index, effect_descriptor_t *pDescriptor) { - ALOGV("DownmixLib_QueryEffect() index=%d", index); - if (pDescriptor == NULL) { - return -EINVAL; - } - if (index >= (uint32_t)kNbEffects) { - return -EINVAL; - } - memcpy(pDescriptor, gDescriptors[index], sizeof(effect_descriptor_t)); - return 0; -} - - int32_t DownmixLib_Create(const effect_uuid_t *uuid, int32_t sessionId, int32_t ioId, diff --git a/media/libeffects/downmix/EffectDownmix.h b/media/libeffects/downmix/EffectDownmix.h index be3ca3f..cb6b957 100644 --- a/media/libeffects/downmix/EffectDownmix.h +++ b/media/libeffects/downmix/EffectDownmix.h @@ -65,9 +65,6 @@ const uint32_t kUnsupported = * Effect API *------------------------------------ */ -int32_t DownmixLib_QueryNumberEffects(uint32_t *pNumEffects); -int32_t DownmixLib_QueryEffect(uint32_t index, - effect_descriptor_t *pDescriptor); int32_t DownmixLib_Create(const effect_uuid_t *uuid, int32_t sessionId, int32_t ioId, diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp index d706c2d..3ea3e18 100644 --- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp +++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp @@ -158,42 +158,6 @@ int Volume_getParameter (EffectContext *pContext, int Effect_setEnabled(EffectContext *pContext, bool enabled); /* Effect Library Interface Implementation */ -extern "C" int EffectQueryNumberEffects(uint32_t *pNumEffects){ - ALOGV("\n\tEffectQueryNumberEffects start"); - *pNumEffects = 4; - ALOGV("\tEffectQueryNumberEffects creating %d effects", *pNumEffects); - ALOGV("\tEffectQueryNumberEffects end\n"); - return 0; -} /* end EffectQueryNumberEffects */ - -extern "C" int EffectQueryEffect(uint32_t index, effect_descriptor_t *pDescriptor){ - ALOGV("\n\tEffectQueryEffect start"); - ALOGV("\tEffectQueryEffect processing index %d", index); - - if (pDescriptor == NULL){ - ALOGV("\tLVM_ERROR : EffectQueryEffect was passed NULL pointer"); - return -EINVAL; - } - if (index > 3){ - ALOGV("\tLVM_ERROR : EffectQueryEffect index out of range %d", index); - return -ENOENT; - } - if(index == LVM_BASS_BOOST){ - ALOGV("\tEffectQueryEffect processing LVM_BASS_BOOST"); - *pDescriptor = gBassBoostDescriptor; - }else if(index == LVM_VIRTUALIZER){ - ALOGV("\tEffectQueryEffect processing LVM_VIRTUALIZER"); - *pDescriptor = gVirtualizerDescriptor; - } else if(index == LVM_EQUALIZER){ - ALOGV("\tEffectQueryEffect processing LVM_EQUALIZER"); - *pDescriptor = gEqualizerDescriptor; - } else if(index == LVM_VOLUME){ - ALOGV("\tEffectQueryEffect processing LVM_VOLUME"); - *pDescriptor = gVolumeDescriptor; - } - ALOGV("\tEffectQueryEffect end\n"); - return 0; -} /* end EffectQueryEffect */ extern "C" int EffectCreate(const effect_uuid_t *uuid, int32_t sessionId, @@ -3304,8 +3268,6 @@ audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = { version : EFFECT_LIBRARY_API_VERSION, name : "Effect Bundle Library", implementor : "NXP Software Ltd.", - query_num_effects : android::EffectQueryNumberEffects, - query_effect : android::EffectQueryEffect, create_effect : android::EffectCreate, release_effect : android::EffectRelease, get_descriptor : android::EffectGetDescriptor, diff --git a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp index 941d651..1a2f9dc 100755 --- a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp +++ b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp @@ -186,30 +186,6 @@ int Reverb_getParameter (ReverbContext *pContext, int Reverb_LoadPreset (ReverbContext *pContext); /* Effect Library Interface Implementation */ -extern "C" int EffectQueryNumberEffects(uint32_t *pNumEffects){ - ALOGV("\n\tEffectQueryNumberEffects start"); - *pNumEffects = sizeof(gDescriptors) / sizeof(const effect_descriptor_t *); - ALOGV("\tEffectQueryNumberEffects creating %d effects", *pNumEffects); - ALOGV("\tEffectQueryNumberEffects end\n"); - return 0; -} /* end EffectQueryNumberEffects */ - -extern "C" int EffectQueryEffect(uint32_t index, - effect_descriptor_t *pDescriptor){ - ALOGV("\n\tEffectQueryEffect start"); - ALOGV("\tEffectQueryEffect processing index %d", index); - if (pDescriptor == NULL){ - ALOGV("\tLVM_ERROR : EffectQueryEffect was passed NULL pointer"); - return -EINVAL; - } - if (index >= sizeof(gDescriptors) / sizeof(const effect_descriptor_t *)) { - ALOGV("\tLVM_ERROR : EffectQueryEffect index out of range %d", index); - return -ENOENT; - } - *pDescriptor = *gDescriptors[index]; - ALOGV("\tEffectQueryEffect end\n"); - return 0; -} /* end EffectQueryEffect */ extern "C" int EffectCreate(const effect_uuid_t *uuid, int32_t sessionId, @@ -2175,8 +2151,6 @@ audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = { version : EFFECT_LIBRARY_API_VERSION, name : "Reverb Library", implementor : "NXP Software Ltd.", - query_num_effects : android::EffectQueryNumberEffects, - query_effect : android::EffectQueryEffect, create_effect : android::EffectCreate, release_effect : android::EffectRelease, get_descriptor : android::EffectGetDescriptor, diff --git a/media/libeffects/preprocessing/PreProcessing.cpp b/media/libeffects/preprocessing/PreProcessing.cpp index 597866a..58dc413 100755 --- a/media/libeffects/preprocessing/PreProcessing.cpp +++ b/media/libeffects/preprocessing/PreProcessing.cpp @@ -1818,30 +1818,6 @@ const struct effect_interface_s sEffectInterfaceReverse = { // Effect Library Interface Implementation //------------------------------------------------------------------------------ -int PreProcessingLib_QueryNumberEffects(uint32_t *pNumEffects) -{ - if (PreProc_Init() != 0) { - return sInitStatus; - } - if (pNumEffects == NULL) { - return -EINVAL; - } - *pNumEffects = PREPROC_NUM_EFFECTS; - return sInitStatus; -} - -int PreProcessingLib_QueryEffect(uint32_t index, effect_descriptor_t *pDescriptor) -{ - if (PreProc_Init() != 0) { - return sInitStatus; - } - if (index >= PREPROC_NUM_EFFECTS) { - return -EINVAL; - } - *pDescriptor = *sDescriptors[index]; - return 0; -} - int PreProcessingLib_Create(const effect_uuid_t *uuid, int32_t sessionId, int32_t ioId, @@ -1918,8 +1894,6 @@ audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = { version : EFFECT_LIBRARY_API_VERSION, name : "Audio Preprocessing Library", implementor : "The Android Open Source Project", - query_num_effects : PreProcessingLib_QueryNumberEffects, - query_effect : PreProcessingLib_QueryEffect, create_effect : PreProcessingLib_Create, release_effect : PreProcessingLib_Release, get_descriptor : PreProcessingLib_GetDescriptor diff --git a/media/libeffects/testlibs/EffectEqualizer.cpp b/media/libeffects/testlibs/EffectEqualizer.cpp index 90ebe1f..c35453b 100644 --- a/media/libeffects/testlibs/EffectEqualizer.cpp +++ b/media/libeffects/testlibs/EffectEqualizer.cpp @@ -123,23 +123,6 @@ int Equalizer_setParameter(AudioEqualizer * pEqualizer, int32_t *pParam, void *p //--- Effect Library Interface Implementation // -extern "C" int EffectQueryNumberEffects(uint32_t *pNumEffects) { - *pNumEffects = 1; - return 0; -} /* end EffectQueryNumberEffects */ - -extern "C" int EffectQueryEffect(uint32_t index, - effect_descriptor_t *pDescriptor) { - if (pDescriptor == NULL) { - return -EINVAL; - } - if (index > 0) { - return -EINVAL; - } - *pDescriptor = gEqualizerDescriptor; - return 0; -} /* end EffectQueryNext */ - extern "C" int EffectCreate(const effect_uuid_t *uuid, int32_t sessionId, int32_t ioId, @@ -771,8 +754,6 @@ audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = { version : EFFECT_LIBRARY_API_VERSION, name : "Test Equalizer Library", implementor : "The Android Open Source Project", - query_num_effects : android::EffectQueryNumberEffects, - query_effect : android::EffectQueryEffect, create_effect : android::EffectCreate, release_effect : android::EffectRelease, get_descriptor : android::EffectGetDescriptor, diff --git a/media/libeffects/testlibs/EffectReverb.c b/media/libeffects/testlibs/EffectReverb.c index a87a834..c37f392 100644 --- a/media/libeffects/testlibs/EffectReverb.c +++ b/media/libeffects/testlibs/EffectReverb.c @@ -94,23 +94,6 @@ static const effect_descriptor_t * const gDescriptors[] = { /*--- Effect Library Interface Implementation ---*/ -int EffectQueryNumberEffects(uint32_t *pNumEffects) { - *pNumEffects = sizeof(gDescriptors) / sizeof(const effect_descriptor_t *); - return 0; -} - -int EffectQueryEffect(uint32_t index, effect_descriptor_t *pDescriptor) { - if (pDescriptor == NULL) { - return -EINVAL; - } - if (index >= sizeof(gDescriptors) / sizeof(const effect_descriptor_t *)) { - return -EINVAL; - } - memcpy(pDescriptor, gDescriptors[index], - sizeof(effect_descriptor_t)); - return 0; -} - int EffectCreate(const effect_uuid_t *uuid, int32_t sessionId, int32_t ioId, @@ -2222,8 +2205,6 @@ audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = { .version = EFFECT_LIBRARY_API_VERSION, .name = "Test Equalizer Library", .implementor = "The Android Open Source Project", - .query_num_effects = EffectQueryNumberEffects, - .query_effect = EffectQueryEffect, .create_effect = EffectCreate, .release_effect = EffectRelease, .get_descriptor = EffectGetDescriptor, diff --git a/media/libeffects/testlibs/EffectReverb.h b/media/libeffects/testlibs/EffectReverb.h index 1fb14a7..e5248fe 100644 --- a/media/libeffects/testlibs/EffectReverb.h +++ b/media/libeffects/testlibs/EffectReverb.h @@ -300,9 +300,6 @@ typedef struct reverb_module_s { * Effect API *------------------------------------ */ -int EffectQueryNumberEffects(uint32_t *pNumEffects); -int EffectQueryEffect(uint32_t index, - effect_descriptor_t *pDescriptor); int EffectCreate(const effect_uuid_t *effectUID, int32_t sessionId, int32_t ioId, diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp index 44baf93..dc1937e 100644 --- a/media/libeffects/visualizer/EffectVisualizer.cpp +++ b/media/libeffects/visualizer/EffectVisualizer.cpp @@ -177,23 +177,6 @@ int Visualizer_init(VisualizerContext *pContext) //--- Effect Library Interface Implementation // -int VisualizerLib_QueryNumberEffects(uint32_t *pNumEffects) { - *pNumEffects = 1; - return 0; -} - -int VisualizerLib_QueryEffect(uint32_t index, - effect_descriptor_t *pDescriptor) { - if (pDescriptor == NULL) { - return -EINVAL; - } - if (index > 0) { - return -EINVAL; - } - *pDescriptor = gVisualizerDescriptor; - return 0; -} - int VisualizerLib_Create(const effect_uuid_t *uuid, int32_t sessionId, int32_t ioId, @@ -580,8 +563,6 @@ audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = { version : EFFECT_LIBRARY_API_VERSION, name : "Visualizer Library", implementor : "The Android Open Source Project", - query_num_effects : VisualizerLib_QueryNumberEffects, - query_effect : VisualizerLib_QueryEffect, create_effect : VisualizerLib_Create, release_effect : VisualizerLib_Release, get_descriptor : VisualizerLib_GetDescriptor, -- cgit v1.1 From 655604a7c1ffadc04ec479e4f45345918f44b460 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Thu, 25 Oct 2012 16:05:57 -0700 Subject: Only export the symbols that need to be The effects libraries were exporting many more symbols than needed. This reduces the exported symbols to just the needed ones (basically just "AELI"), which happens to also save about 28KB. Change-Id: I115077e52e8dc845282e6f62a522908d26dd72d6 --- media/libeffects/downmix/Android.mk | 2 ++ media/libeffects/downmix/EffectDownmix.c | 2 ++ media/libeffects/lvm/lib/Android.mk | 9 +++++---- media/libeffects/lvm/wrapper/Android.mk | 11 +++++------ media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp | 2 ++ media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp | 2 ++ media/libeffects/preprocessing/Android.mk | 2 ++ media/libeffects/preprocessing/PreProcessing.cpp | 2 ++ media/libeffects/visualizer/Android.mk | 2 +- media/libeffects/visualizer/EffectVisualizer.cpp | 3 ++- 10 files changed, 25 insertions(+), 12 deletions(-) (limited to 'media/libeffects') diff --git a/media/libeffects/downmix/Android.mk b/media/libeffects/downmix/Android.mk index 95ca6fd..3052ad9 100644 --- a/media/libeffects/downmix/Android.mk +++ b/media/libeffects/downmix/Android.mk @@ -25,4 +25,6 @@ LOCAL_C_INCLUDES := \ LOCAL_PRELINK_MODULE := false +LOCAL_CFLAGS += -fvisibility=hidden + include $(BUILD_SHARED_LIBRARY) diff --git a/media/libeffects/downmix/EffectDownmix.c b/media/libeffects/downmix/EffectDownmix.c index aa2134c..f17a6e8 100644 --- a/media/libeffects/downmix/EffectDownmix.c +++ b/media/libeffects/downmix/EffectDownmix.c @@ -58,6 +58,8 @@ const struct effect_interface_s gDownmixInterface = { NULL /* no process_reverse function, no reference stream needed */ }; +// This is the only symbol that needs to be exported +__attribute__ ((visibility ("default"))) audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = { tag : AUDIO_EFFECT_LIBRARY_TAG, version : EFFECT_LIBRARY_API_VERSION, diff --git a/media/libeffects/lvm/lib/Android.mk b/media/libeffects/lvm/lib/Android.mk index f49267e..bb56c75 100644 --- a/media/libeffects/lvm/lib/Android.mk +++ b/media/libeffects/lvm/lib/Android.mk @@ -105,8 +105,6 @@ LOCAL_SRC_FILES:= \ LOCAL_MODULE:= libmusicbundle - - LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/Eq/lib \ $(LOCAL_PATH)/Eq/src \ @@ -121,8 +119,12 @@ LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/StereoWidening/src \ $(LOCAL_PATH)/StereoWidening/lib +LOCAL_CFLAGS += -fvisibility=hidden + include $(BUILD_STATIC_LIBRARY) + + # Reverb library include $(CLEAR_VARS) @@ -168,12 +170,11 @@ LOCAL_SRC_FILES:= \ LOCAL_MODULE:= libreverb - - LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/Reverb/lib \ $(LOCAL_PATH)/Reverb/src \ $(LOCAL_PATH)/Common/lib \ $(LOCAL_PATH)/Common/src +LOCAL_CFLAGS += -fvisibility=hidden include $(BUILD_STATIC_LIBRARY) diff --git a/media/libeffects/lvm/wrapper/Android.mk b/media/libeffects/lvm/wrapper/Android.mk index 4313424..f1af389 100644 --- a/media/libeffects/lvm/wrapper/Android.mk +++ b/media/libeffects/lvm/wrapper/Android.mk @@ -9,28 +9,27 @@ LOCAL_ARM_MODE := arm LOCAL_SRC_FILES:= \ Bundle/EffectBundle.cpp +LOCAL_CFLAGS += -fvisibility=hidden + LOCAL_MODULE:= libbundlewrapper LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/soundfx - - LOCAL_STATIC_LIBRARIES += libmusicbundle LOCAL_SHARED_LIBRARIES := \ libcutils \ libdl - LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/Bundle \ $(LOCAL_PATH)/../lib/Common/lib/ \ $(LOCAL_PATH)/../lib/Bundle/lib/ \ $(call include-path-for, audio-effects) - include $(BUILD_SHARED_LIBRARY) + # reverb wrapper include $(CLEAR_VARS) @@ -39,12 +38,12 @@ LOCAL_ARM_MODE := arm LOCAL_SRC_FILES:= \ Reverb/EffectReverb.cpp +LOCAL_CFLAGS += -fvisibility=hidden + LOCAL_MODULE:= libreverbwrapper LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/soundfx - - LOCAL_STATIC_LIBRARIES += libreverb LOCAL_SHARED_LIBRARIES := \ diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp index 3ea3e18..94b9acf 100644 --- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp +++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp @@ -3263,6 +3263,8 @@ const struct effect_interface_s gLvmEffectInterface = { NULL, }; /* end gLvmEffectInterface */ +// This is the only symbol that needs to be exported +__attribute__ ((visibility ("default"))) audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = { tag : AUDIO_EFFECT_LIBRARY_TAG, version : EFFECT_LIBRARY_API_VERSION, diff --git a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp index 1a2f9dc..87e2c85 100755 --- a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp +++ b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp @@ -2146,6 +2146,8 @@ const struct effect_interface_s gReverbInterface = { NULL, }; /* end gReverbInterface */ +// This is the only symbol that needs to be exported +__attribute__ ((visibility ("default"))) audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = { tag : AUDIO_EFFECT_LIBRARY_TAG, version : EFFECT_LIBRARY_API_VERSION, diff --git a/media/libeffects/preprocessing/Android.mk b/media/libeffects/preprocessing/Android.mk index c13b9d4..dfa1711 100755 --- a/media/libeffects/preprocessing/Android.mk +++ b/media/libeffects/preprocessing/Android.mk @@ -29,4 +29,6 @@ else LOCAL_SHARED_LIBRARIES += libdl endif +LOCAL_CFLAGS += -fvisibility=hidden + include $(BUILD_SHARED_LIBRARY) diff --git a/media/libeffects/preprocessing/PreProcessing.cpp b/media/libeffects/preprocessing/PreProcessing.cpp index 58dc413..25586e8 100755 --- a/media/libeffects/preprocessing/PreProcessing.cpp +++ b/media/libeffects/preprocessing/PreProcessing.cpp @@ -1889,6 +1889,8 @@ int PreProcessingLib_GetDescriptor(const effect_uuid_t *uuid, return 0; } +// This is the only symbol that needs to be exported +__attribute__ ((visibility ("default"))) audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = { tag : AUDIO_EFFECT_LIBRARY_TAG, version : EFFECT_LIBRARY_API_VERSION, diff --git a/media/libeffects/visualizer/Android.mk b/media/libeffects/visualizer/Android.mk index 76b5110..49cf4fa 100644 --- a/media/libeffects/visualizer/Android.mk +++ b/media/libeffects/visualizer/Android.mk @@ -6,7 +6,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ EffectVisualizer.cpp -LOCAL_CFLAGS+= -O2 +LOCAL_CFLAGS+= -O2 -fvisibility=hidden LOCAL_SHARED_LIBRARIES := \ libcutils \ diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp index dc1937e..e7eccf1 100644 --- a/media/libeffects/visualizer/EffectVisualizer.cpp +++ b/media/libeffects/visualizer/EffectVisualizer.cpp @@ -557,7 +557,8 @@ const struct effect_interface_s gVisualizerInterface = { NULL, }; - +// This is the only symbol that needs to be exported +__attribute__ ((visibility ("default"))) audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = { tag : AUDIO_EFFECT_LIBRARY_TAG, version : EFFECT_LIBRARY_API_VERSION, -- cgit v1.1 From ad4e408b8ea397caadbfee85e1e39515e7e08104 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Fri, 26 Oct 2012 14:28:05 -0700 Subject: Turn off executable bit on ordinary files Change-Id: I0abea25b58fb1d03975bed9cca40f826fcd4c5e4 --- media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp | 0 media/libeffects/preprocessing/Android.mk | 0 media/libeffects/preprocessing/PreProcessing.cpp | 0 3 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp mode change 100755 => 100644 media/libeffects/preprocessing/Android.mk mode change 100755 => 100644 media/libeffects/preprocessing/PreProcessing.cpp (limited to 'media/libeffects') diff --git a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp old mode 100755 new mode 100644 diff --git a/media/libeffects/preprocessing/Android.mk b/media/libeffects/preprocessing/Android.mk old mode 100755 new mode 100644 diff --git a/media/libeffects/preprocessing/PreProcessing.cpp b/media/libeffects/preprocessing/PreProcessing.cpp old mode 100755 new mode 100644 -- cgit v1.1 From 0003b9b56e77764c77fd4e4e1a5d6e44a55e5b8a Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Tue, 19 Mar 2013 09:57:29 -0700 Subject: Fix valgrind error The volume member of the BundledEffectContext class was not being initialized, resulting in uninitialized data being used for calculations and control flow. Change-Id: I84bf9fd478e5d0479e781323b21c7c03dea958c5 --- media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'media/libeffects') diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp index 94b9acf..54f8d9e 100644 --- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp +++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp @@ -224,6 +224,7 @@ extern "C" int EffectCreate(const effect_uuid_t *uuid, pContext->pBundledContext->NumberEffectsEnabled = 0; pContext->pBundledContext->NumberEffectsCalled = 0; pContext->pBundledContext->firstVolume = LVM_TRUE; + pContext->pBundledContext->volume = 0; #ifdef LVM_PCM char fileName[256]; -- cgit v1.1 From da0dc0af0effe9fbfb3ce3187c8472fca2baf3c6 Mon Sep 17 00:00:00 2001 From: Ying Wang Date: Tue, 9 Apr 2013 21:53:49 -0700 Subject: Add liblog Bug: 8580410 Change-Id: If493d87d60d71be664ad75b140c62acadb75b0d0 --- media/libeffects/downmix/Android.mk | 2 +- media/libeffects/factory/Android.mk | 2 +- media/libeffects/preprocessing/Android.mk | 3 ++- media/libeffects/visualizer/Android.mk | 1 + 4 files changed, 5 insertions(+), 3 deletions(-) (limited to 'media/libeffects') diff --git a/media/libeffects/downmix/Android.mk b/media/libeffects/downmix/Android.mk index 3052ad9..5d0a87c 100644 --- a/media/libeffects/downmix/Android.mk +++ b/media/libeffects/downmix/Android.mk @@ -7,7 +7,7 @@ LOCAL_SRC_FILES:= \ EffectDownmix.c LOCAL_SHARED_LIBRARIES := \ - libcutils + libcutils liblog LOCAL_MODULE:= libdownmix diff --git a/media/libeffects/factory/Android.mk b/media/libeffects/factory/Android.mk index 6e69151..60a6ce5 100644 --- a/media/libeffects/factory/Android.mk +++ b/media/libeffects/factory/Android.mk @@ -7,7 +7,7 @@ LOCAL_SRC_FILES:= \ EffectsFactory.c LOCAL_SHARED_LIBRARIES := \ - libcutils + libcutils liblog LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES) LOCAL_MODULE:= libeffects diff --git a/media/libeffects/preprocessing/Android.mk b/media/libeffects/preprocessing/Android.mk index dfa1711..c344352 100644 --- a/media/libeffects/preprocessing/Android.mk +++ b/media/libeffects/preprocessing/Android.mk @@ -21,7 +21,8 @@ LOCAL_C_INCLUDES += $(call include-path-for, speex) LOCAL_SHARED_LIBRARIES := \ libwebrtc_audio_preprocessing \ libspeexresampler \ - libutils + libutils \ + liblog ifeq ($(TARGET_SIMULATOR),true) LOCAL_LDLIBS += -ldl diff --git a/media/libeffects/visualizer/Android.mk b/media/libeffects/visualizer/Android.mk index 49cf4fa..e196eb2 100644 --- a/media/libeffects/visualizer/Android.mk +++ b/media/libeffects/visualizer/Android.mk @@ -10,6 +10,7 @@ LOCAL_CFLAGS+= -O2 -fvisibility=hidden LOCAL_SHARED_LIBRARIES := \ libcutils \ + liblog \ libdl LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/soundfx -- cgit v1.1 From c92d6b0d491df675c6728cd4ffb7217469cc9d72 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Wed, 1 May 2013 16:15:49 -0700 Subject: Fix reverb at 48kHz The LVM reverb wrapper had a test to only accept input sampling rate of 44.1 kHz. As the LVM reberb engine supports multiple sampling rate we can remove this test. The fix for issue 8512027 (commit 2a9c5cd4) caused a regression because the framework now checks the return code of the effect configure command and ignores subsequent commands in case of error. Bug: 8630044 Change-Id: I3146871f1ad8f7945a2e63ea763dd7b87368337d --- media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'media/libeffects') diff --git a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp index 87e2c85..8a96212 100644 --- a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp +++ b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp @@ -616,10 +616,6 @@ int Reverb_setConfig(ReverbContext *pContext, effect_config_t *pConfig){ || pConfig->outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE); CHECK_ARG(pConfig->inputCfg.format == AUDIO_FORMAT_PCM_16_BIT); - if(pConfig->inputCfg.samplingRate != 44100){ - return -EINVAL; - } - //ALOGV("\tReverb_setConfig calling memcpy"); pContext->config = *pConfig; @@ -648,7 +644,7 @@ int Reverb_setConfig(ReverbContext *pContext, effect_config_t *pConfig){ return -EINVAL; } - if(pContext->SampleRate != SampleRate){ + if (pContext->SampleRate != SampleRate) { LVREV_ControlParams_st ActiveParams; LVREV_ReturnStatus_en LvmStatus = LVREV_SUCCESS; @@ -662,11 +658,14 @@ int Reverb_setConfig(ReverbContext *pContext, effect_config_t *pConfig){ LVM_ERROR_CHECK(LvmStatus, "LVREV_GetControlParameters", "Reverb_setConfig") if(LvmStatus != LVREV_SUCCESS) return -EINVAL; + ActiveParams.SampleRate = SampleRate; + LvmStatus = LVREV_SetControlParameters(pContext->hInstance, &ActiveParams); LVM_ERROR_CHECK(LvmStatus, "LVREV_SetControlParameters", "Reverb_setConfig") + if(LvmStatus != LVREV_SUCCESS) return -EINVAL; //ALOGV("\tReverb_setConfig Succesfully called LVREV_SetControlParameters\n"); - + pContext->SampleRate = SampleRate; }else{ //ALOGV("\tReverb_setConfig keep sampling rate at %d", SampleRate); } @@ -818,6 +817,7 @@ int Reverb_init(ReverbContext *pContext){ /* General parameters */ params.OperatingMode = LVM_MODE_ON; params.SampleRate = LVM_FS_44100; + pContext->SampleRate = LVM_FS_44100; if(pContext->config.inputCfg.channels == AUDIO_CHANNEL_OUT_MONO){ params.SourceFormat = LVM_MONO; -- cgit v1.1 From b7f08d386f2bddb8f3c87858f9204754b7fdb857 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Tue, 18 Jun 2013 11:46:28 -0700 Subject: Clean up references to AUDIO_FORMAT_PCM_8_24_BIT Change-Id: I08771eb2664b7082561a40937218c7f4414e2cce --- media/libeffects/testlibs/AudioFormatAdapter.h | 1 + media/libeffects/testlibs/EffectEqualizer.cpp | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'media/libeffects') diff --git a/media/libeffects/testlibs/AudioFormatAdapter.h b/media/libeffects/testlibs/AudioFormatAdapter.h index 41f1810..dea2734 100644 --- a/media/libeffects/testlibs/AudioFormatAdapter.h +++ b/media/libeffects/testlibs/AudioFormatAdapter.h @@ -75,6 +75,7 @@ public: while (numSamples > 0) { uint32_t numSamplesIter = min(numSamples, mMaxSamplesPerCall); uint32_t nSamplesChannels = numSamplesIter * mNumChannels; + // This branch of "if" is untested if (mPcmFormat == AUDIO_FORMAT_PCM_8_24_BIT) { if (mBehavior == EFFECT_BUFFER_ACCESS_WRITE) { mpProcessor->process( diff --git a/media/libeffects/testlibs/EffectEqualizer.cpp b/media/libeffects/testlibs/EffectEqualizer.cpp index c35453b..8d00206 100644 --- a/media/libeffects/testlibs/EffectEqualizer.cpp +++ b/media/libeffects/testlibs/EffectEqualizer.cpp @@ -234,8 +234,7 @@ int Equalizer_setConfig(EqualizerContext *pContext, effect_config_t *pConfig) (pConfig->inputCfg.channels == AUDIO_CHANNEL_OUT_STEREO)); CHECK_ARG(pConfig->outputCfg.accessMode == EFFECT_BUFFER_ACCESS_WRITE || pConfig->outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE); - CHECK_ARG(pConfig->inputCfg.format == AUDIO_FORMAT_PCM_8_24_BIT - || pConfig->inputCfg.format == AUDIO_FORMAT_PCM_16_BIT); + CHECK_ARG(pConfig->inputCfg.format == AUDIO_FORMAT_PCM_16_BIT); int channelCount; if (pConfig->inputCfg.channels == AUDIO_CHANNEL_OUT_MONO) { -- cgit v1.1 From 284c17e73bbff51cb5b1adcee98386d47733757a Mon Sep 17 00:00:00 2001 From: jpadmana Date: Tue, 4 Jun 2013 16:08:29 +0530 Subject: Effects Factory changes for effects offload audio_effects.conf - commented changes to illustrate the addition of Proxy and sub effects to the conf file Added an effectFactoryApi - EffectGetSubEffects for querying the sub effect descriptors from the factory. This api is used by the Proxy to get the sub effects Added functions and data structures in factory code for loading the sub effects gSubEffectList - has the Proxies and their corresponding sub effects - addSubEffect() - reads a sub effect node and adds to the gSubEffectList - findSubEffect() - searches through the gSubEffectList to find a SubEffect Bug: 8174034. Change-Id: I25b0c62b2ad523a52337128b51469e628209ea3e Signed-off-by: jpadmana --- media/libeffects/data/audio_effects.conf | 39 ++++++ media/libeffects/factory/EffectsFactory.c | 218 +++++++++++++++++++++++++++++- media/libeffects/factory/EffectsFactory.h | 19 +++ 3 files changed, 274 insertions(+), 2 deletions(-) (limited to 'media/libeffects') diff --git a/media/libeffects/data/audio_effects.conf b/media/libeffects/data/audio_effects.conf index 93f27cb..aa48e4e 100644 --- a/media/libeffects/data/audio_effects.conf +++ b/media/libeffects/data/audio_effects.conf @@ -6,6 +6,23 @@ # } # } libraries { +# This is a proxy library that will be an abstraction for +# the HW and SW effects + + #proxy { + #path /system/lib/soundfx/libProxy.so + #} + +# This is the SW implementation library of the effect + #libSW { + #path /system/lib/soundfx/libswwrapper.so + #} + +# This is the HW implementation library for the effect + #libHW { + #path /system/lib/soundfx/libhwwrapper.so + #} + bundle { path /system/lib/soundfx/libbundlewrapper.so } @@ -43,6 +60,28 @@ libraries { # } effects { + +# additions for the proxy implementation +# Proxy implementation + #effectname { + #library proxy + #uuid xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + + # SW implemetation of the effect. Added as a node under the proxy to + # indicate this as a sub effect. + #libsw { + #library libSW + #uuid yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy + #} End of SW effect + + # HW implementation of the effect. Added as a node under the proxy to + # indicate this as a sub effect. + #libhw { + #library libHW + #uuid zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz + #}End of HW effect + #} End of effect proxy + bassboost { library bundle uuid 8631f300-72e2-11df-b57e-0002a5d5c51b diff --git a/media/libeffects/factory/EffectsFactory.c b/media/libeffects/factory/EffectsFactory.c index f158929..f8d6041 100644 --- a/media/libeffects/factory/EffectsFactory.c +++ b/media/libeffects/factory/EffectsFactory.c @@ -28,6 +28,9 @@ 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 +// list of effect_descriptor and list of sub effects : all currently loaded +// It does not contain effects without sub effects. +static list_sub_elem_t *gSubEffectList; 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 @@ -50,6 +53,8 @@ static int loadLibraries(cnode *root); static int loadLibrary(cnode *root, const char *name); static int loadEffects(cnode *root); static int loadEffect(cnode *node); +// To get and add the effect pointed by the passed node to the gSubEffectList +static int addSubEffect(cnode *root); static lib_entry_t *getLibrary(const char *path); static void resetEffectEnumeration(); static uint32_t updateNumEffects(); @@ -57,6 +62,10 @@ static int findEffect(const effect_uuid_t *type, const effect_uuid_t *uuid, lib_entry_t **lib, effect_descriptor_t **desc); +// To search a subeffect in the gSubEffectList +int findSubEffect(const effect_uuid_t *uuid, + lib_entry_t **lib, + effect_descriptor_t **desc); static void dumpEffectDescriptor(effect_descriptor_t *desc, char *str, size_t len); static int stringToUuid(const char *str, effect_uuid_t *uuid); static int uuidToString(const effect_uuid_t *uuid, char *str, size_t maxLen); @@ -287,7 +296,12 @@ int EffectCreate(const effect_uuid_t *uuid, int32_t sessionId, int32_t ioId, eff ret = findEffect(NULL, uuid, &l, &d); if (ret < 0){ - goto exit; + // Sub effects are not associated with the library->effects, + // so, findEffect will fail. Search for the effect in gSubEffectList. + ret = findSubEffect(uuid, &l, &d); + if (ret < 0 ) { + goto exit; + } } // create effect in library @@ -354,21 +368,27 @@ int EffectRelease(effect_handle_t handle) } if (e1 == NULL) { ret = -ENOENT; + pthread_mutex_unlock(&gLibLock); goto exit; } // release effect in library if (fx->lib == NULL) { ALOGW("EffectRelease() fx %p library already unloaded", handle); + pthread_mutex_unlock(&gLibLock); } else { pthread_mutex_lock(&fx->lib->lock); + // Releasing the gLibLock here as the list access is over as the + // effect is removed from the list. + // If the gLibLock is not released, we will have a deadlock situation + // since we call the sub effect release inside the EffectRelease of Proxy + pthread_mutex_unlock(&gLibLock); fx->lib->desc->release_effect(fx->subItfe); pthread_mutex_unlock(&fx->lib->lock); } free(fx); exit: - pthread_mutex_unlock(&gLibLock); return ret; } @@ -380,6 +400,49 @@ int EffectIsNullUuid(const effect_uuid_t *uuid) return 1; } +// Function to get the sub effect descriptors of the effect whose uuid +// is pointed by the first argument. It searches the gSubEffectList for the +// matching uuid and then copies the corresponding sub effect descriptors +// to the inout param +int EffectGetSubEffects(const effect_uuid_t *uuid, + effect_descriptor_t *pDescriptors, size_t size) +{ + ALOGV("EffectGetSubEffects() UUID: %08X-%04X-%04X-%04X-%02X%02X%02X%02X%02X" + "%02X\n",uuid->timeLow, uuid->timeMid, uuid->timeHiAndVersion, + uuid->clockSeq, uuid->node[0], uuid->node[1],uuid->node[2], + uuid->node[3],uuid->node[4],uuid->node[5]); + + // Check if the size of the desc buffer is large enough for 2 subeffects + if ((uuid == NULL) || (pDescriptors == NULL) || + (size < 2*sizeof(effect_descriptor_t))) { + ALOGW("NULL pointer or insufficient memory. Cannot query subeffects"); + return -EINVAL; + } + int ret = init(); + if (ret < 0) + return ret; + list_sub_elem_t *e = gSubEffectList; + sub_effect_entry_t *subeffect; + effect_descriptor_t *d; + int count = 0; + while (e != NULL) { + d = (effect_descriptor_t*)e->object; + if (memcmp(uuid, &d->uuid, sizeof(effect_uuid_t)) == 0) { + ALOGV("EffectGetSubEffects: effect found in the list"); + list_elem_t *subefx = e->sub_elem; + while (subefx != NULL) { + subeffect = (sub_effect_entry_t*)subefx->object; + d = (effect_descriptor_t*)(subeffect->object); + pDescriptors[count++] = *d; + subefx = subefx->next; + } + ALOGV("EffectGetSubEffects end - copied the sub effect descriptors"); + return count; + } + e = e->next; + } + return -ENOENT; +} ///////////////////////////////////////////////// // Local functions ///////////////////////////////////////////////// @@ -503,6 +566,65 @@ error: return -EINVAL; } +// This will find the library and UUID tags of the sub effect pointed by the +// node, gets the effect descriptor and lib_entry_t and adds the subeffect - +// sub_entry_t to the gSubEffectList +int addSubEffect(cnode *root) +{ + ALOGV("addSubEffect"); + cnode *node; + effect_uuid_t uuid; + effect_descriptor_t *d; + lib_entry_t *l; + list_elem_t *e; + node = config_find(root, LIBRARY_TAG); + if (node == NULL) { + return -EINVAL; + } + l = getLibrary(node->value); + if (l == NULL) { + ALOGW("addSubEffect() could not get library %s", node->value); + return -EINVAL; + } + node = config_find(root, UUID_TAG); + if (node == NULL) { + return -EINVAL; + } + if (stringToUuid(node->value, &uuid) != 0) { + ALOGW("addSubEffect() invalid uuid %s", node->value); + return -EINVAL; + } + d = malloc(sizeof(effect_descriptor_t)); + if (l->desc->get_descriptor(&uuid, d) != 0) { + char s[40]; + uuidToString(&uuid, s, 40); + ALOGW("Error querying effect %s on lib %s", s, l->name); + free(d); + return -EINVAL; + } +#if (LOG_NDEBUG==0) + char s[256]; + dumpEffectDescriptor(d, s, 256); + ALOGV("addSubEffect() read descriptor %p:%s",d, s); +#endif + if (EFFECT_API_VERSION_MAJOR(d->apiVersion) != + EFFECT_API_VERSION_MAJOR(EFFECT_CONTROL_API_VERSION)) { + ALOGW("Bad API version %08x on lib %s", d->apiVersion, l->name); + free(d); + return -EINVAL; + } + sub_effect_entry_t *sub_effect = malloc(sizeof(sub_effect_entry_t)); + sub_effect->object = d; + // lib_entry_t is stored since the sub effects are not linked to the library + sub_effect->lib = l; + e = malloc(sizeof(list_elem_t)); + e->object = sub_effect; + e->next = gSubEffectList->sub_elem; + gSubEffectList->sub_elem = e; + ALOGV("addSubEffect end"); + return 0; +} + int loadEffects(cnode *root) { cnode *node; @@ -571,9 +693,101 @@ int loadEffect(cnode *root) e->next = l->effects; l->effects = e; + // After the UUID node in the config_tree, if node->next is valid, + // that would be sub effect node. + // Find the sub effects and add them to the gSubEffectList + node = node->next; + int count = 2; + bool hwSubefx = false, swSubefx = false; + list_sub_elem_t *sube = NULL; + if (node != NULL) { + ALOGV("Adding the effect to gEffectSubList as there are sub effects"); + sube = malloc(sizeof(list_sub_elem_t)); + sube->object = d; + sube->sub_elem = NULL; + sube->next = gSubEffectList; + gSubEffectList = sube; + } + while (node != NULL && count) { + if (addSubEffect(node)) { + ALOGW("loadEffect() could not add subEffect %s", node->value); + // Change the gSubEffectList to point to older list; + gSubEffectList = sube->next; + free(sube->sub_elem);// Free an already added sub effect + sube->sub_elem = NULL; + free(sube); + return -ENOENT; + } + sub_effect_entry_t *subEntry = (sub_effect_entry_t*)gSubEffectList->sub_elem->object; + effect_descriptor_t *subEffectDesc = (effect_descriptor_t*)(subEntry->object); + // Since we return a dummy descriptor for the proxy during + // get_descriptor call,we replace it with the correspoding + // sw effect descriptor, but with Proxy UUID + // check for Sw desc + if (!((subEffectDesc->flags & EFFECT_FLAG_HW_ACC_MASK) == + EFFECT_FLAG_HW_ACC_TUNNEL)) { + swSubefx = true; + *d = *subEffectDesc; + d->uuid = uuid; + ALOGV("loadEffect() Changed the Proxy desc"); + } else + hwSubefx = true; + count--; + node = node->next; + } + // 1 HW and 1 SW sub effect found. Set the offload flag in the Proxy desc + if (hwSubefx && swSubefx) { + d->flags |= EFFECT_FLAG_OFFLOAD_SUPPORTED; + } return 0; } +// Searches the sub effect matching to the specified uuid +// in the gSubEffectList. It gets the lib_entry_t for +// the matched sub_effect . Used in EffectCreate of sub effects +int findSubEffect(const effect_uuid_t *uuid, + lib_entry_t **lib, + effect_descriptor_t **desc) +{ + list_sub_elem_t *e = gSubEffectList; + list_elem_t *subefx; + sub_effect_entry_t *effect; + lib_entry_t *l = NULL; + effect_descriptor_t *d = NULL; + int found = 0; + int ret = 0; + + if (uuid == NULL) + return -EINVAL; + + while (e != NULL && !found) { + subefx = (list_elem_t*)(e->sub_elem); + while (subefx != NULL) { + effect = (sub_effect_entry_t*)subefx->object; + l = (lib_entry_t *)effect->lib; + d = (effect_descriptor_t *)effect->object; + if (memcmp(&d->uuid, uuid, sizeof(effect_uuid_t)) == 0) { + ALOGV("uuid matched"); + found = 1; + break; + } + subefx = subefx->next; + } + e = e->next; + } + if (!found) { + ALOGV("findSubEffect() effect not found"); + ret = -ENOENT; + } else { + ALOGV("findSubEffect() found effect: %s in lib %s", d->name, l->name); + *lib = l; + if (desc != NULL) { + *desc = d; + } + } + return ret; +} + lib_entry_t *getLibrary(const char *name) { list_elem_t *e; diff --git a/media/libeffects/factory/EffectsFactory.h b/media/libeffects/factory/EffectsFactory.h index c1d4319..147ff18 100644 --- a/media/libeffects/factory/EffectsFactory.h +++ b/media/libeffects/factory/EffectsFactory.h @@ -32,6 +32,15 @@ typedef struct list_elem_s { struct list_elem_s *next; } list_elem_t; +// Structure used for storing effects with their sub effects. +// Used in creating gSubEffectList. Here, +// object holds the effect desc and the list sub_elem holds the sub effects +typedef struct list_sub_elem_s { + void *object; + list_elem_t *sub_elem; + struct list_sub_elem_s *next; +} list_sub_elem_t; + typedef struct lib_entry_s { audio_effect_library_t *desc; char *name; @@ -47,6 +56,16 @@ typedef struct effect_entry_s { lib_entry_t *lib; } effect_entry_t; +// Structure used to store the lib entry +// and the descriptor of the sub effects. +// The library entry is to be stored in case of +// sub effects as the sub effects are not linked +// to the library list - gLibraryList. +typedef struct sub_effect_entry_s { + lib_entry_t *lib; + void *object; +} sub_effect_entry_t; + #if __cplusplus } // extern "C" #endif -- cgit v1.1 From 60c60df7db278d2fa5c90b0fa14f99a61d50272b Mon Sep 17 00:00:00 2001 From: jpadmana Date: Tue, 4 Jun 2013 16:03:29 +0530 Subject: Effect Offload Proxy for effects offload Effect Proxy abstracts the sub effects to the upper layers. It has the following functionalities: - creation and release of sub effects - routing the effect commands and process to the appropriate sub effect Bug: 8174034. Change-Id: I22d8136636048e7fe8f8807cbc6e348ffa200a22 Signed-off-by: jpadmana --- media/libeffects/data/audio_effects.conf | 2 +- media/libeffects/proxy/Android.mk | 34 ++++ media/libeffects/proxy/EffectProxy.cpp | 298 +++++++++++++++++++++++++++++++ media/libeffects/proxy/EffectProxy.h | 75 ++++++++ 4 files changed, 408 insertions(+), 1 deletion(-) create mode 100644 media/libeffects/proxy/Android.mk create mode 100644 media/libeffects/proxy/EffectProxy.cpp create mode 100644 media/libeffects/proxy/EffectProxy.h (limited to 'media/libeffects') diff --git a/media/libeffects/data/audio_effects.conf b/media/libeffects/data/audio_effects.conf index aa48e4e..69a3c53 100644 --- a/media/libeffects/data/audio_effects.conf +++ b/media/libeffects/data/audio_effects.conf @@ -10,7 +10,7 @@ libraries { # the HW and SW effects #proxy { - #path /system/lib/soundfx/libProxy.so + #path /system/lib/soundfx/libeffectproxy.so #} # This is the SW implementation library of the effect diff --git a/media/libeffects/proxy/Android.mk b/media/libeffects/proxy/Android.mk new file mode 100644 index 0000000..01b3be1 --- /dev/null +++ b/media/libeffects/proxy/Android.mk @@ -0,0 +1,34 @@ +# Copyright 2013 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) +LOCAL_MODULE:= libeffectproxy +LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/soundfx +LOCAL_MODULE_TAGS := optional + + +LOCAL_SRC_FILES := \ + EffectProxy.cpp + +LOCAL_CFLAGS+= -fvisibility=hidden + +LOCAL_SHARED_LIBRARIES := liblog libcutils libutils libdl libeffects + +LOCAL_C_INCLUDES := \ + system/media/audio_effects/include \ + bionic/libc/include + +include $(BUILD_SHARED_LIBRARY) + diff --git a/media/libeffects/proxy/EffectProxy.cpp b/media/libeffects/proxy/EffectProxy.cpp new file mode 100644 index 0000000..77c6e89 --- /dev/null +++ b/media/libeffects/proxy/EffectProxy.cpp @@ -0,0 +1,298 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "EffectProxy" +//#define LOG_NDEBUG 0 + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace android { +// This is a dummy proxy descriptor just to return to Factory during the initial +// GetDescriptor call. Later in the factory, it is replaced with the +// SW sub effect descriptor +const effect_descriptor_t gProxyDescriptor = { + EFFECT_UUID_INITIALIZER, // type + EFFECT_UUID_INITIALIZER, // uuid + EFFECT_CONTROL_API_VERSION, //version of effect control API + (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_LAST | + EFFECT_FLAG_VOLUME_CTRL), // effect capability flags + 0, // CPU load + 1, // Data memory + "Proxy", //effect name + "AOSP", //implementor name +}; + + +static const effect_descriptor_t *const gDescriptors[] = +{ + &gProxyDescriptor, +}; + +int EffectProxyCreate(const effect_uuid_t *uuid, + int32_t sessionId, + int32_t ioId, + effect_handle_t *pHandle) { + + effect_descriptor_t* desc; + EffectContext* pContext; + if (pHandle == NULL || uuid == NULL) { + ALOGE("EffectProxyCreate() called with NULL pointer"); + return -EINVAL; + } + ALOGV("EffectProxyCreate start.."); + pContext = new EffectContext; + pContext->sessionId = sessionId; + pContext->ioId = ioId; + pContext->uuid = *uuid; + pContext->common_itfe = &gEffectInterface; + // The sub effects will be created in effect_command when the first command + // for the effect is received + pContext->eHandle[SUB_FX_HOST] = pContext->eHandle[SUB_FX_OFFLOAD] = NULL; + + // Get the HW and SW sub effect descriptors from the effects factory + desc = new effect_descriptor_t[SUB_FX_COUNT]; + pContext->desc = new effect_descriptor_t[SUB_FX_COUNT]; + int retValue = EffectGetSubEffects(uuid, desc, + sizeof(effect_descriptor_t) * SUB_FX_COUNT); + // EffectGetSubEffects returns the number of sub-effects copied. + if (retValue != SUB_FX_COUNT) { + ALOGE("EffectCreate() could not get the sub effects"); + delete desc; + delete pContext->desc; + return -EINVAL; + } + // Check which is the HW descriptor and copy the descriptors + // to the Context desc array + // Also check if there is only one HW and one SW descriptor. + // HW descriptor alone has the HW_TUNNEL flag. + if ((desc[0].flags & EFFECT_FLAG_HW_ACC_TUNNEL) && + !(desc[1].flags & EFFECT_FLAG_HW_ACC_TUNNEL)) { + pContext->desc[SUB_FX_OFFLOAD] = desc[0]; + pContext->desc[SUB_FX_HOST] = desc[1]; + } + else if ((desc[1].flags & EFFECT_FLAG_HW_ACC_TUNNEL) && + !(desc[0].flags & EFFECT_FLAG_HW_ACC_TUNNEL)) { + pContext->desc[SUB_FX_HOST] = desc[0]; + pContext->desc[SUB_FX_OFFLOAD] = desc[1]; + } + delete desc; +#if (LOG_NDEBUG == 0) + effect_uuid_t uuid_print = pContext->desc[SUB_FX_HOST].uuid; + ALOGV("EffectCreate() UUID of HOST: %08X-%04X-%04X-%04X-%02X%02X%02X%02X" + "%02X%02X\n",uuid_print.timeLow, uuid_print.timeMid, + uuid_print.timeHiAndVersion, uuid_print.clockSeq, uuid_print.node[0], + uuid_print.node[1], uuid_print.node[2], uuid_print.node[3], + uuid_print.node[4], uuid_print.node[5]); + ALOGV("EffectCreate() UUID of OFFLOAD: %08X-%04X-%04X-%04X-%02X%02X%02X%02X" + "%02X%02X\n", uuid_print.timeLow, uuid_print.timeMid, + uuid_print.timeHiAndVersion, uuid_print.clockSeq, uuid_print.node[0], + uuid_print.node[1], uuid_print.node[2], uuid_print.node[3], + uuid_print.node[4], uuid_print.node[5]); +#endif + *pHandle = (effect_handle_t)pContext; + ALOGV("EffectCreate end"); + return 0; +} //end EffectProxyCreate + +int EffectProxyRelease(effect_handle_t handle) { + EffectContext * pContext = (EffectContext *)handle; + if (pContext == NULL) { + ALOGV("ERROR : EffectRelease called with NULL pointer"); + return -EINVAL; + } + ALOGV("EffectRelease"); + delete pContext->desc; + if (pContext->eHandle[SUB_FX_HOST]) + EffectRelease(pContext->eHandle[SUB_FX_HOST]); + if (pContext->eHandle[SUB_FX_OFFLOAD]) + EffectRelease(pContext->eHandle[SUB_FX_OFFLOAD]); + delete pContext; + pContext = NULL; + return 0; +} /*end EffectProxyRelease */ + +int EffectProxyGetDescriptor(const effect_uuid_t *uuid, + effect_descriptor_t *pDescriptor) { + const effect_descriptor_t *desc = NULL; + + if (pDescriptor == NULL || uuid == NULL) { + ALOGV("EffectGetDescriptor() called with NULL pointer"); + return -EINVAL; + } + desc = &gProxyDescriptor; + *pDescriptor = *desc; + return 0; +} /* end EffectProxyGetDescriptor */ + +/* Effect Control Interface Implementation: Process */ +int Effect_process(effect_handle_t self, + audio_buffer_t *inBuffer, + audio_buffer_t *outBuffer) { + + EffectContext *pContext = (EffectContext *) self; + int ret = 0; + if (pContext != NULL) { + 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); + } + } + return ret; +} /* end Effect_process */ + +/* Effect Control Interface Implementation: Command */ +int Effect_command(effect_handle_t self, + uint32_t cmdCode, + uint32_t cmdSize, + void *pCmdData, + uint32_t *replySize, + void *pReplyData) { + + EffectContext *pContext = (EffectContext *) self; + int status; + if (pContext == NULL) { + ALOGV("Effect_command() Proxy context is NULL"); + return -EINVAL; + } + if (pContext->eHandle[SUB_FX_HOST] == NULL) { + ALOGV("Effect_command() Calling HOST EffectCreate"); + status = EffectCreate(&pContext->desc[SUB_FX_HOST].uuid, + pContext->sessionId, pContext->ioId, + &(pContext->eHandle[SUB_FX_HOST])); + if (status != NO_ERROR || (pContext->eHandle[SUB_FX_HOST] == NULL)) { + ALOGV("Effect_command() Error creating SW sub effect"); + return status; + } + } + if (pContext->eHandle[SUB_FX_OFFLOAD] == NULL) { + ALOGV("Effect_command() Calling OFFLOAD EffectCreate"); + status = EffectCreate(&pContext->desc[SUB_FX_OFFLOAD].uuid, + pContext->sessionId, pContext->ioId, + &(pContext->eHandle[SUB_FX_OFFLOAD])); + if (status != NO_ERROR || (pContext->eHandle[SUB_FX_OFFLOAD] == NULL)) { + ALOGV("Effect_command() Error creating HW effect"); + // Do not return error here as SW effect is created + // Return error if the CMD_OFFLOAD sends the index as OFFLOAD + } + pContext->index = SUB_FX_HOST; + } + // EFFECT_CMD_OFFLOAD used to (1) send whether the thread is offload or not + // (2) Send the ioHandle of the effectThread when the effect + // is moved from one type of thread to another. + // pCmdData points to a memory holding effect_offload_param_t structure + if (cmdCode == EFFECT_CMD_OFFLOAD) { + ALOGV("Effect_command() cmdCode = EFFECT_CMD_OFFLOAD"); + if (cmdSize == 0 || pCmdData == NULL) { + ALOGV("effectsOffload: Effect_command: CMD_OFFLOAD has no data"); + *(int*)pReplyData = FAILED_TRANSACTION; + return FAILED_TRANSACTION; + } + effect_offload_param_t* offloadParam = (effect_offload_param_t*)pCmdData; + // Assign the effect context index based on isOffload field of the structure + pContext->index = offloadParam->isOffload ? SUB_FX_OFFLOAD : SUB_FX_HOST; + // if the index is HW and the HW effect is unavailable, return error + // and reset the index to SW + if (pContext->eHandle[pContext->index] == NULL) { + ALOGV("Effect_command()CMD_OFFLOAD sub effect unavailable"); + *(int*)pReplyData = FAILED_TRANSACTION; + return FAILED_TRANSACTION; + } + pContext->ioId = offloadParam->ioHandle; + ALOGV("Effect_command()CMD_OFFLOAD index:%d io %d", pContext->index, pContext->ioId); + // Update the DSP wrapper with the new ioHandle. + // Pass the OFFLOAD command to the wrapper. + // The DSP wrapper needs to handle this CMD + if (pContext->eHandle[SUB_FX_OFFLOAD]) + status = (*pContext->eHandle[SUB_FX_OFFLOAD])->command( + pContext->eHandle[SUB_FX_OFFLOAD], cmdCode, cmdSize, + pCmdData, replySize, pReplyData); + return status; + } + + int index = pContext->index; + if (index != SUB_FX_HOST && index != SUB_FX_OFFLOAD) { + 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( + pContext->eHandle[SUB_FX_HOST], cmdCode, cmdSize, + pCmdData, replySize, pReplyData); + if (pContext->eHandle[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( + pContext->eHandle[SUB_FX_OFFLOAD], cmdCode, cmdSize, + pCmdData, replySize, pReplyData); + } + return 0; +} /* end Effect_command */ + + +/* Effect Control Interface Implementation: get_descriptor */ +int Effect_getDescriptor(effect_handle_t self, + effect_descriptor_t *pDescriptor) { + + EffectContext * pContext = (EffectContext *) self; + const effect_descriptor_t *desc; + + ALOGV("Effect_getDescriptor"); + if (pContext == NULL || pDescriptor == NULL) { + ALOGV("Effect_getDescriptor() invalid param"); + return -EINVAL; + } + if (pContext->desc == NULL) { + ALOGV("Effect_getDescriptor() could not get descriptor"); + return -EINVAL; + } + desc = &pContext->desc[SUB_FX_HOST]; + *pDescriptor = *desc; + pDescriptor->uuid = pContext->uuid; // Replace the uuid with the Proxy UUID + // Also set/clear the EFFECT_FLAG_OFFLOAD_SUPPORTED flag based on the sub effects availability + if (pContext->eHandle[SUB_FX_OFFLOAD] != NULL) + pDescriptor->flags |= EFFECT_FLAG_OFFLOAD_SUPPORTED; + else + pDescriptor->flags &= ~EFFECT_FLAG_OFFLOAD_SUPPORTED; + return 0; +} /* end Effect_getDescriptor */ + +} // namespace android + +__attribute__ ((visibility ("default"))) +audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = { + tag : AUDIO_EFFECT_LIBRARY_TAG, + version : EFFECT_LIBRARY_API_VERSION, + name : "Effect Proxy", + implementor : "AOSP", + create_effect : android::EffectProxyCreate, + release_effect : android::EffectProxyRelease, + get_descriptor : android::EffectProxyGetDescriptor, +}; diff --git a/media/libeffects/proxy/EffectProxy.h b/media/libeffects/proxy/EffectProxy.h new file mode 100644 index 0000000..8992f93 --- /dev/null +++ b/media/libeffects/proxy/EffectProxy.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +namespace android { +enum { + SUB_FX_HOST, // Index of HOST in the descriptor and handle arrays + // of the Proxy context + SUB_FX_OFFLOAD, // Index of OFFLOAD in the descriptor and handle arrays + // of the Proxy context + SUB_FX_COUNT // The number of sub effects for a Proxy(1 HW, 1 SW) +}; +#if __cplusplus +extern "C" { +#endif + +int EffectProxyCreate(const effect_uuid_t *uuid, + int32_t sessionId, + int32_t ioId, + effect_handle_t *pHandle); +int EffectProxyRelease(effect_handle_t handle); +int EffectProxyGetDescriptor(const effect_uuid_t *uuid, + effect_descriptor_t *pDescriptor); +/* Effect Control Interface Implementation: Process */ +int Effect_process(effect_handle_t self, + audio_buffer_t *inBuffer, + audio_buffer_t *outBuffer); + +/* Effect Control Interface Implementation: Command */ +int Effect_command(effect_handle_t self, + uint32_t cmdCode, + uint32_t cmdSize, + void *pCmdData, + uint32_t *replySize, + void *pReplyData); +int Effect_getDescriptor(effect_handle_t self, + effect_descriptor_t *pDescriptor); + +const struct effect_interface_s gEffectInterface = { + Effect_process, + Effect_command, + Effect_getDescriptor, + NULL, +}; + +struct EffectContext { + const struct effect_interface_s *common_itfe; // Holds the itfe of the Proxy + effect_descriptor_t* desc; // Points to the sub effect descriptors + effect_handle_t eHandle[SUB_FX_COUNT]; // The effect handles of the sub effects + int index; // The index that is currently active - HOST or OFFLOAD + int32_t sessionId; // The sessiond in which the effect is created. + // Stored in context to pass on to sub effect creation + int32_t ioId; // The ioId in which the effect is created. + // Stored in context to pass on to sub effect creation + effect_uuid_t uuid; // UUID of the Proxy +}; + +#if __cplusplus +} // extern "C" +#endif +} //namespace android -- cgit v1.1 From 6cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3c Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Tue, 10 Sep 2013 09:15:18 -0700 Subject: LoudnessEnhancer audio effect implementation Implementation based on DRC effect, controlled by a target gain. The target gain is used to amplify the signal at the input of the DRC, and to compute the knee of the DRC. Bug 8413913 Change-Id: I386d64793a9fa3f7218e053d6f0a99f6836c02bd --- media/libeffects/data/audio_effects.conf | 7 + media/libeffects/loudness/Android.mk | 27 ++ .../libeffects/loudness/EffectLoudnessEnhancer.cpp | 474 +++++++++++++++++++++ media/libeffects/loudness/MODULE_LICENSE_APACHE2 | 0 media/libeffects/loudness/NOTICE | 190 +++++++++ .../libeffects/loudness/common/core/basic_types.h | 114 +++++ .../libeffects/loudness/common/core/byte_swapper.h | 151 +++++++ media/libeffects/loudness/common/core/math.h | 89 ++++ media/libeffects/loudness/common/core/os.h | 29 ++ media/libeffects/loudness/common/core/types.h | 31 ++ media/libeffects/loudness/dsp/core/basic-inl.h | 48 +++ media/libeffects/loudness/dsp/core/basic.h | 48 +++ .../dsp/core/dynamic_range_compression-inl.h | 45 ++ .../dsp/core/dynamic_range_compression.cpp | 106 +++++ .../loudness/dsp/core/dynamic_range_compression.h | 116 +++++ media/libeffects/loudness/dsp/core/interpolation.h | 24 ++ .../loudness/dsp/core/interpolator_base-inl.h | 180 ++++++++ .../loudness/dsp/core/interpolator_base.h | 112 +++++ .../loudness/dsp/core/interpolator_linear.h | 81 ++++ 19 files changed, 1872 insertions(+) create mode 100644 media/libeffects/loudness/Android.mk create mode 100644 media/libeffects/loudness/EffectLoudnessEnhancer.cpp create mode 100644 media/libeffects/loudness/MODULE_LICENSE_APACHE2 create mode 100644 media/libeffects/loudness/NOTICE create mode 100644 media/libeffects/loudness/common/core/basic_types.h create mode 100644 media/libeffects/loudness/common/core/byte_swapper.h create mode 100644 media/libeffects/loudness/common/core/math.h create mode 100644 media/libeffects/loudness/common/core/os.h create mode 100644 media/libeffects/loudness/common/core/types.h create mode 100644 media/libeffects/loudness/dsp/core/basic-inl.h create mode 100644 media/libeffects/loudness/dsp/core/basic.h create mode 100644 media/libeffects/loudness/dsp/core/dynamic_range_compression-inl.h create mode 100644 media/libeffects/loudness/dsp/core/dynamic_range_compression.cpp create mode 100644 media/libeffects/loudness/dsp/core/dynamic_range_compression.h create mode 100644 media/libeffects/loudness/dsp/core/interpolation.h create mode 100644 media/libeffects/loudness/dsp/core/interpolator_base-inl.h create mode 100644 media/libeffects/loudness/dsp/core/interpolator_base.h create mode 100644 media/libeffects/loudness/dsp/core/interpolator_linear.h (limited to 'media/libeffects') diff --git a/media/libeffects/data/audio_effects.conf b/media/libeffects/data/audio_effects.conf index 69a3c53..c3c4b67 100644 --- a/media/libeffects/data/audio_effects.conf +++ b/media/libeffects/data/audio_effects.conf @@ -35,6 +35,9 @@ libraries { downmix { path /system/lib/soundfx/libdownmix.so } + loudness_enhancer { + path /system/lib/soundfx/libldnhncr.so + } } # Default pre-processing library. Add to audio_effect.conf "libraries" section if @@ -122,6 +125,10 @@ effects { library downmix uuid 93f04452-e4fe-41cc-91f9-e475b6d1d69f } + loudness_enhancer { + library loudness_enhancer + uuid fa415329-2034-4bea-b5dc-5b381c8d1e2c + } } # Default pre-processing effects. Add to audio_effect.conf "effects" section if diff --git a/media/libeffects/loudness/Android.mk b/media/libeffects/loudness/Android.mk new file mode 100644 index 0000000..dcb7b27 --- /dev/null +++ b/media/libeffects/loudness/Android.mk @@ -0,0 +1,27 @@ +LOCAL_PATH:= $(call my-dir) + +# LoudnessEnhancer library +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + EffectLoudnessEnhancer.cpp \ + dsp/core/dynamic_range_compression.cpp + +LOCAL_CFLAGS+= -O2 -fvisibility=hidden + +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + liblog \ + libstlport + +LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/soundfx +LOCAL_MODULE:= libldnhncr + +LOCAL_C_INCLUDES := \ + $(call include-path-for, audio-effects) \ + bionic \ + bionic/libstdc++/include \ + external/stlport/stlport + + +include $(BUILD_SHARED_LIBRARY) diff --git a/media/libeffects/loudness/EffectLoudnessEnhancer.cpp b/media/libeffects/loudness/EffectLoudnessEnhancer.cpp new file mode 100644 index 0000000..dfc25db --- /dev/null +++ b/media/libeffects/loudness/EffectLoudnessEnhancer.cpp @@ -0,0 +1,474 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "EffectLE" +//#define LOG_NDEBUG 0 +#include +#include +#include +#include +#include +#include +#include +#include +#include "dsp/core/dynamic_range_compression.h" + +extern "C" { + +// effect_handle_t interface implementation for LE effect +extern const struct effect_interface_s gLEInterface; + +// AOSP Loudness Enhancer UUID: fa415329-2034-4bea-b5dc-5b381c8d1e2c +const effect_descriptor_t gLEDescriptor = { + {0xfe3199be, 0xaed0, 0x413f, 0x87bb, {0x11, 0x26, 0x0e, 0xb6, 0x3c, 0xf1}}, // type + {0xfa415329, 0x2034, 0x4bea, 0xb5dc, {0x5b, 0x38, 0x1c, 0x8d, 0x1e, 0x2c}}, // uuid + EFFECT_CONTROL_API_VERSION, + (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST), + 0, // TODO + 1, + "Loudness Enhancer", + "The Android Open Source Project", +}; + +enum le_state_e { + LOUDNESS_ENHANCER_STATE_UNINITIALIZED, + LOUDNESS_ENHANCER_STATE_INITIALIZED, + LOUDNESS_ENHANCER_STATE_ACTIVE, +}; + +struct LoudnessEnhancerContext { + const struct effect_interface_s *mItfe; + effect_config_t mConfig; + uint8_t mState; + int32_t mTargetGainmB;// target gain in mB + // in this implementation, there is no coupling between the compression on the left and right + // channels + le_fx::AdaptiveDynamicRangeCompression* mCompressorL; + le_fx::AdaptiveDynamicRangeCompression* mCompressorR; +}; + +// +//--- Local functions (not directly used by effect interface) +// + +void LE_reset(LoudnessEnhancerContext *pContext) +{ + ALOGV(" > LE_reset(%p)", pContext); + + if ((pContext->mCompressorL != NULL) && (pContext->mCompressorR != NULL)) { + float targetAmp = pow(10, pContext->mTargetGainmB/2000.0f); // mB to linear amplification + ALOGV("LE_reset(): Target gain=%dmB <=> factor=%.2fX", pContext->mTargetGainmB, targetAmp); + pContext->mCompressorL->Initialize(targetAmp, pContext->mConfig.inputCfg.samplingRate); + pContext->mCompressorR->Initialize(targetAmp, pContext->mConfig.inputCfg.samplingRate); + } else { + ALOGE("LE_reset(%p): null compressors, can't apply target gain", pContext); + } +} + +static inline int16_t clamp16(int32_t sample) +{ + if ((sample>>15) ^ (sample>>31)) + sample = 0x7FFF ^ (sample>>31); + return sample; +} + +//---------------------------------------------------------------------------- +// LE_setConfig() +//---------------------------------------------------------------------------- +// Purpose: Set input and output audio configuration. +// +// Inputs: +// pContext: effect engine context +// pConfig: pointer to effect_config_t structure holding input and output +// configuration parameters +// +// Outputs: +// +//---------------------------------------------------------------------------- + +int LE_setConfig(LoudnessEnhancerContext *pContext, effect_config_t *pConfig) +{ + ALOGV("LE_setConfig(%p)", pContext); + + if (pConfig->inputCfg.samplingRate != pConfig->outputCfg.samplingRate) return -EINVAL; + if (pConfig->inputCfg.channels != pConfig->outputCfg.channels) return -EINVAL; + if (pConfig->inputCfg.format != pConfig->outputCfg.format) return -EINVAL; + if (pConfig->inputCfg.channels != AUDIO_CHANNEL_OUT_STEREO) return -EINVAL; + if (pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_WRITE && + pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_ACCUMULATE) return -EINVAL; + if (pConfig->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) return -EINVAL; + + pContext->mConfig = *pConfig; + + LE_reset(pContext); + + return 0; +} + + +//---------------------------------------------------------------------------- +// LE_getConfig() +//---------------------------------------------------------------------------- +// Purpose: Get input and output audio configuration. +// +// Inputs: +// pContext: effect engine context +// pConfig: pointer to effect_config_t structure holding input and output +// configuration parameters +// +// Outputs: +// +//---------------------------------------------------------------------------- + +void LE_getConfig(LoudnessEnhancerContext *pContext, effect_config_t *pConfig) +{ + *pConfig = pContext->mConfig; +} + + +//---------------------------------------------------------------------------- +// LE_init() +//---------------------------------------------------------------------------- +// Purpose: Initialize engine with default configuration. +// +// Inputs: +// pContext: effect engine context +// +// Outputs: +// +//---------------------------------------------------------------------------- + +int LE_init(LoudnessEnhancerContext *pContext) +{ + ALOGV("LE_init(%p)", pContext); + + pContext->mConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ; + pContext->mConfig.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO; + pContext->mConfig.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT; + pContext->mConfig.inputCfg.samplingRate = 44100; + pContext->mConfig.inputCfg.bufferProvider.getBuffer = NULL; + pContext->mConfig.inputCfg.bufferProvider.releaseBuffer = NULL; + pContext->mConfig.inputCfg.bufferProvider.cookie = NULL; + pContext->mConfig.inputCfg.mask = EFFECT_CONFIG_ALL; + pContext->mConfig.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE; + pContext->mConfig.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO; + pContext->mConfig.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT; + pContext->mConfig.outputCfg.samplingRate = 44100; + pContext->mConfig.outputCfg.bufferProvider.getBuffer = NULL; + pContext->mConfig.outputCfg.bufferProvider.releaseBuffer = NULL; + pContext->mConfig.outputCfg.bufferProvider.cookie = NULL; + pContext->mConfig.outputCfg.mask = EFFECT_CONFIG_ALL; + + pContext->mTargetGainmB = LOUDNESS_ENHANCER_DEFAULT_TARGET_GAIN_MB; + float targetAmp = pow(10, pContext->mTargetGainmB/2000.0f); // mB to linear amplification + ALOGV("LE_init(): Target gain=%dmB <=> factor=%.2fX", pContext->mTargetGainmB, targetAmp); + + if (pContext->mCompressorL == NULL) { + pContext->mCompressorL = new le_fx::AdaptiveDynamicRangeCompression(); + pContext->mCompressorL->Initialize(targetAmp, pContext->mConfig.inputCfg.samplingRate); + } + if (pContext->mCompressorR == NULL) { + pContext->mCompressorR = new le_fx::AdaptiveDynamicRangeCompression(); + pContext->mCompressorR->Initialize(targetAmp, pContext->mConfig.inputCfg.samplingRate); + } + + LE_setConfig(pContext, &pContext->mConfig); + + return 0; +} + +// +//--- Effect Library Interface Implementation +// + +int LELib_Create(const effect_uuid_t *uuid, + int32_t sessionId, + int32_t ioId, + effect_handle_t *pHandle) { + ALOGV("LELib_Create()"); + int ret; + int i; + + if (pHandle == NULL || uuid == NULL) { + return -EINVAL; + } + + if (memcmp(uuid, &gLEDescriptor.uuid, sizeof(effect_uuid_t)) != 0) { + return -EINVAL; + } + + LoudnessEnhancerContext *pContext = new LoudnessEnhancerContext; + + pContext->mItfe = &gLEInterface; + pContext->mState = LOUDNESS_ENHANCER_STATE_UNINITIALIZED; + + pContext->mCompressorL = NULL; + pContext->mCompressorR = NULL; + ret = LE_init(pContext); + if (ret < 0) { + ALOGW("LELib_Create() init failed"); + delete pContext; + return ret; + } + + *pHandle = (effect_handle_t)pContext; + + pContext->mState = LOUDNESS_ENHANCER_STATE_INITIALIZED; + + ALOGV(" LELib_Create context is %p", pContext); + + return 0; + +} + +int LELib_Release(effect_handle_t handle) { + LoudnessEnhancerContext * pContext = (LoudnessEnhancerContext *)handle; + + ALOGV("LELib_Release %p", handle); + if (pContext == NULL) { + return -EINVAL; + } + pContext->mState = LOUDNESS_ENHANCER_STATE_UNINITIALIZED; + if (pContext->mCompressorL != NULL) { + delete pContext->mCompressorL; + pContext->mCompressorL = NULL; + } + if (pContext->mCompressorR != NULL) { + delete pContext->mCompressorR; + pContext->mCompressorR = NULL; + } + delete pContext; + + return 0; +} + +int LELib_GetDescriptor(const effect_uuid_t *uuid, + effect_descriptor_t *pDescriptor) { + + if (pDescriptor == NULL || uuid == NULL){ + ALOGV("LELib_GetDescriptor() called with NULL pointer"); + return -EINVAL; + } + + if (memcmp(uuid, &gLEDescriptor.uuid, sizeof(effect_uuid_t)) == 0) { + *pDescriptor = gLEDescriptor; + return 0; + } + + return -EINVAL; +} /* end LELib_GetDescriptor */ + +// +//--- Effect Control Interface Implementation +// +int LE_process( + effect_handle_t self, audio_buffer_t *inBuffer, audio_buffer_t *outBuffer) +{ + LoudnessEnhancerContext * pContext = (LoudnessEnhancerContext *)self; + + if (pContext == NULL) { + return -EINVAL; + } + + if (inBuffer == NULL || inBuffer->raw == NULL || + outBuffer == NULL || outBuffer->raw == NULL || + inBuffer->frameCount != outBuffer->frameCount || + inBuffer->frameCount == 0) { + return -EINVAL; + } + + //ALOGV("LE about to process %d samples", inBuffer->frameCount); + uint16_t inIdx; + float inputAmp = pow(10, pContext->mTargetGainmB/2000.0f); + for (inIdx = 0 ; inIdx < inBuffer->frameCount ; inIdx++) { + inBuffer->s16[2*inIdx] = pContext->mCompressorL->Compress( + inputAmp * (float)inBuffer->s16[2*inIdx]); + inBuffer->s16[2*inIdx +1] = pContext->mCompressorR->Compress( + inputAmp * (float)inBuffer->s16[2*inIdx +1]); + } + + if (inBuffer->raw != outBuffer->raw) { + if (pContext->mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) { + for (size_t i = 0; i < outBuffer->frameCount*2; i++) { + outBuffer->s16[i] = clamp16(outBuffer->s16[i] + inBuffer->s16[i]); + } + } else { + memcpy(outBuffer->raw, inBuffer->raw, outBuffer->frameCount * 2 * sizeof(int16_t)); + } + } + if (pContext->mState != LOUDNESS_ENHANCER_STATE_ACTIVE) { + return -ENODATA; + } + return 0; +} + +int LE_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize, + void *pCmdData, uint32_t *replySize, void *pReplyData) { + + LoudnessEnhancerContext * pContext = (LoudnessEnhancerContext *)self; + int retsize; + + if (pContext == NULL || pContext->mState == LOUDNESS_ENHANCER_STATE_UNINITIALIZED) { + return -EINVAL; + } + +// ALOGV("LE_command command %d cmdSize %d",cmdCode, cmdSize); + switch (cmdCode) { + case EFFECT_CMD_INIT: + if (pReplyData == NULL || *replySize != sizeof(int)) { + return -EINVAL; + } + *(int *) pReplyData = LE_init(pContext); + break; + case EFFECT_CMD_SET_CONFIG: + if (pCmdData == NULL || cmdSize != sizeof(effect_config_t) + || pReplyData == NULL || *replySize != sizeof(int)) { + return -EINVAL; + } + *(int *) pReplyData = LE_setConfig(pContext, + (effect_config_t *) pCmdData); + break; + case EFFECT_CMD_GET_CONFIG: + if (pReplyData == NULL || + *replySize != sizeof(effect_config_t)) { + return -EINVAL; + } + LE_getConfig(pContext, (effect_config_t *)pReplyData); + break; + case EFFECT_CMD_RESET: + LE_reset(pContext); + break; + case EFFECT_CMD_ENABLE: + if (pReplyData == NULL || *replySize != sizeof(int)) { + return -EINVAL; + } + if (pContext->mState != LOUDNESS_ENHANCER_STATE_INITIALIZED) { + return -ENOSYS; + } + pContext->mState = LOUDNESS_ENHANCER_STATE_ACTIVE; + ALOGV("EFFECT_CMD_ENABLE() OK"); + *(int *)pReplyData = 0; + break; + case EFFECT_CMD_DISABLE: + if (pReplyData == NULL || *replySize != sizeof(int)) { + return -EINVAL; + } + if (pContext->mState != LOUDNESS_ENHANCER_STATE_ACTIVE) { + return -ENOSYS; + } + pContext->mState = LOUDNESS_ENHANCER_STATE_INITIALIZED; + ALOGV("EFFECT_CMD_DISABLE() OK"); + *(int *)pReplyData = 0; + break; + case EFFECT_CMD_GET_PARAM: { + if (pCmdData == NULL || + cmdSize != (int)(sizeof(effect_param_t) + sizeof(uint32_t)) || + pReplyData == NULL || + *replySize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint32_t))) { + return -EINVAL; + } + memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + sizeof(uint32_t)); + effect_param_t *p = (effect_param_t *)pReplyData; + p->status = 0; + *replySize = sizeof(effect_param_t) + sizeof(uint32_t); + if (p->psize != sizeof(uint32_t)) { + p->status = -EINVAL; + break; + } + switch (*(uint32_t *)p->data) { + case LOUDNESS_ENHANCER_PARAM_TARGET_GAIN_MB: + ALOGV("get target gain(mB) = %d", pContext->mTargetGainmB); + *((int32_t *)p->data + 1) = pContext->mTargetGainmB; + p->vsize = sizeof(int32_t); + *replySize += sizeof(int32_t); + break; + default: + p->status = -EINVAL; + } + } break; + case EFFECT_CMD_SET_PARAM: { + if (pCmdData == NULL || + cmdSize != (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint32_t)) || + pReplyData == NULL || *replySize != sizeof(int32_t)) { + return -EINVAL; + } + *(int32_t *)pReplyData = 0; + effect_param_t *p = (effect_param_t *)pCmdData; + if (p->psize != sizeof(uint32_t) || p->vsize != sizeof(uint32_t)) { + *(int32_t *)pReplyData = -EINVAL; + break; + } + switch (*(uint32_t *)p->data) { + case LOUDNESS_ENHANCER_PARAM_TARGET_GAIN_MB: + pContext->mTargetGainmB = *((int32_t *)p->data + 1); + ALOGV("set target gain(mB) = %d", pContext->mTargetGainmB); + LE_reset(pContext); // apply parameter update + break; + default: + *(int32_t *)pReplyData = -EINVAL; + } + } break; + case EFFECT_CMD_SET_DEVICE: + case EFFECT_CMD_SET_VOLUME: + case EFFECT_CMD_SET_AUDIO_MODE: + break; + + default: + ALOGW("LE_command invalid command %d",cmdCode); + return -EINVAL; + } + + return 0; +} + +/* Effect Control Interface Implementation: get_descriptor */ +int LE_getDescriptor(effect_handle_t self, + effect_descriptor_t *pDescriptor) +{ + LoudnessEnhancerContext * pContext = (LoudnessEnhancerContext *) self; + + if (pContext == NULL || pDescriptor == NULL) { + ALOGV("LE_getDescriptor() invalid param"); + return -EINVAL; + } + + *pDescriptor = gLEDescriptor; + + return 0; +} /* end LE_getDescriptor */ + +// effect_handle_t interface implementation for DRC effect +const struct effect_interface_s gLEInterface = { + LE_process, + LE_command, + LE_getDescriptor, + NULL, +}; + +// This is the only symbol that needs to be exported +__attribute__ ((visibility ("default"))) +audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = { + tag : AUDIO_EFFECT_LIBRARY_TAG, + version : EFFECT_LIBRARY_API_VERSION, + name : "Loudness Enhancer Library", + implementor : "The Android Open Source Project", + create_effect : LELib_Create, + release_effect : LELib_Release, + get_descriptor : LELib_GetDescriptor, +}; + +}; // extern "C" + diff --git a/media/libeffects/loudness/MODULE_LICENSE_APACHE2 b/media/libeffects/loudness/MODULE_LICENSE_APACHE2 new file mode 100644 index 0000000..e69de29 diff --git a/media/libeffects/loudness/NOTICE b/media/libeffects/loudness/NOTICE new file mode 100644 index 0000000..ad6ed94 --- /dev/null +++ b/media/libeffects/loudness/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2013, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/media/libeffects/loudness/common/core/basic_types.h b/media/libeffects/loudness/common/core/basic_types.h new file mode 100644 index 0000000..593e914 --- /dev/null +++ b/media/libeffects/loudness/common/core/basic_types.h @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LE_FX_ENGINE_COMMON_CORE_BASIC_TYPES_H_ +#define LE_FX_ENGINE_COMMON_CORE_BASIC_TYPES_H_ + +#include +#include +#include +using ::std::string; +using ::std::basic_string; +#include +using ::std::vector; + +#include "common/core/os.h" + +// ----------------------------------------------------------------------------- +// Definitions of common basic types: +// ----------------------------------------------------------------------------- + +#if !defined(G_COMPILE) && !defined(BASE_INTEGRAL_TYPES_H_) + +namespace le_fx { + +typedef signed char schar; +typedef signed char int8; +typedef short int16; +typedef int int32; +typedef long long int64; + +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef unsigned int uint32; +typedef unsigned long long uint64; + +} // namespace le_fx + +#endif + +namespace le_fx { + +struct FloatArray { + int length; + float *data; + + FloatArray(void) { + data = NULL; + length = 0; + } +}; + +struct Int16Array { + int length; + int16 *data; + + Int16Array(void) { + data = NULL; + length = 0; + } +}; + +struct Int32Array { + int length; + int32 *data; + + Int32Array(void) { + data = NULL; + length = 0; + } +}; + +struct Int8Array { + int length; + uint8 *data; + + Int8Array(void) { + data = NULL; + length = 0; + } +}; + +// +// Simple wrapper for waveform data: +// +class WaveData : public vector { + public: + WaveData(); + ~WaveData(); + + void Set(int number_samples, int sampling_rate, int16 *data); + int sample_rate(void) const; + void set_sample_rate(int sample_rate); + bool Equals(const WaveData &wave_data, int threshold = 0) const; + + private: + int sample_rate_; +}; + +} // namespace le_fx + +#endif // LE_FX_ENGINE_COMMON_CORE_BASIC_TYPES_H_ diff --git a/media/libeffects/loudness/common/core/byte_swapper.h b/media/libeffects/loudness/common/core/byte_swapper.h new file mode 100644 index 0000000..8f0caf3 --- /dev/null +++ b/media/libeffects/loudness/common/core/byte_swapper.h @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LE_FX_ENGINE_COMMON_CORE_BYTE_SWAPPER_H_ +#define LE_FX_ENGINE_COMMON_CORE_BYTE_SWAPPER_H_ + +#include +#include + +#include "common/core/basic_types.h" +#include "common/core/os.h" + +namespace le_fx { + +namespace arch { + +inline bool IsLittleEndian(void) { + int16 word = 1; + char *cp = reinterpret_cast(&word); + return cp[0] != 0; +} + +inline bool IsBigEndian(void) { + return !IsLittleEndian(); +} + +template +struct ByteSwapper { + static T Swap(const T &val) { + T new_val = val; + char *first = &new_val, *last = first + kValSize - 1, x; + for (; first < last; ++first, --last) { + x = *last; + *last = *first; + *first = x; + } + return new_val; + } +}; + +template +struct ByteSwapper { + static T Swap(const T &val) { + return val; + } +}; + +template +struct ByteSwapper { + static T Swap(const T &val) { + T new_val; + const char *o = (const char *)&val; + char *p = reinterpret_cast(&new_val); + p[0] = o[1]; + p[1] = o[0]; + return new_val; + } +}; + +template +struct ByteSwapper { + static T Swap(const T &val) { + T new_val; + const char *o = (const char *)&val; + char *p = reinterpret_cast(&new_val); + p[0] = o[3]; + p[1] = o[2]; + p[2] = o[1]; + p[3] = o[0]; + return new_val; + } +}; + +template +struct ByteSwapper { + static T Swap(const T &val) { + T new_val = val; + const char *o = (const char *)&val; + char *p = reinterpret_cast(&new_val); + p[0] = o[7]; + p[1] = o[6]; + p[2] = o[5]; + p[3] = o[4]; + p[4] = o[3]; + p[5] = o[2]; + p[6] = o[1]; + p[7] = o[0]; + return new_val; + } +}; + +template +T SwapBytes(const T &val, bool force_swap) { + if (force_swap) { +#if !defined(LE_FX__NEED_BYTESWAP) + return ByteSwapper::Swap(val); +#else + return val; +#endif // !LE_FX_NEED_BYTESWAP + } else { +#if !defined(LE_FX_NEED_BYTESWAP) + return val; +#else + return ByteSwapper::Swap(val); +#endif // !LE_FX_NEED_BYTESWAP + } +} + +template +const T *SwapBytes(const T *vals, unsigned int num_items, bool force_swap) { + if (force_swap) { +#if !defined(LE_FX_NEED_BYTESWAP) + T *writeable_vals = const_cast(vals); + for (unsigned int i = 0; i < num_items; i++) { + writeable_vals[i] = ByteSwapper::Swap(vals[i]); + } + return writeable_vals; +#else + return vals; +#endif // !LE_FX_NEED_BYTESWAP + } else { +#if !defined(LE_FX_NEED_BYTESWAP) + return vals; +#else + T *writeable_vals = const_cast(vals); + for (unsigned int i = 0; i < num_items; i++) { + writeable_vals[i] = ByteSwapper::Swap(vals[i]); + } + return writeable_vals; +#endif // !LE_FX_NEED_BYTESWAP + } +} + +} // namespace arch + +} // namespace le_fx + +#endif // LE_FX_ENGINE_COMMON_CORE_BYTE_SWAPPER_H_ diff --git a/media/libeffects/loudness/common/core/math.h b/media/libeffects/loudness/common/core/math.h new file mode 100644 index 0000000..3f302cc --- /dev/null +++ b/media/libeffects/loudness/common/core/math.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LE_FX_ENGINE_COMMON_CORE_MATH_H_ +#define LE_FX_ENGINE_COMMON_CORE_MATH_H_ + +#include +#include +using ::std::min; +using ::std::max; +using ::std::fill; +using ::std::fill_n;using ::std::lower_bound; +#include +#include +//using ::std::fpclassify; + +#include "common/core/os.h" +#include "common/core/types.h" + +namespace le_fx { +namespace math { + +// A fast approximation to log2(.) +inline float fast_log2(float val) { + int* const exp_ptr = reinterpret_cast (&val); + int x = *exp_ptr; + const int log_2 = ((x >> 23) & 255) - 128; + x &= ~(255 << 23); + x += 127 << 23; + *exp_ptr = x; + val = ((-1.0f / 3) * val + 2) * val - 2.0f / 3; + return static_cast(val + log_2); +} + +// A fast approximation to log(.) +inline float fast_log(float val) { + return fast_log2(val) * + 0.693147180559945286226763982995180413126945495605468750f; +} + +// An approximation of the exp(.) function using a 5-th order Taylor expansion. +// It's pretty accurate between +-0.1 and accurate to 10e-3 between +-1 +template +inline T ExpApproximationViaTaylorExpansionOrder5(T x) { + const T x2 = x * x; + const T x3 = x2 * x; + const T x4 = x2 * x2; + const T x5 = x3 * x2; + return 1.0f + x + 0.5f * x2 + + 0.16666666666666665741480812812369549646973609924316406250f * x3 + + 0.0416666666666666643537020320309238741174340248107910156250f * x4 + + 0.008333333333333333217685101601546193705871701240539550781250f * x5; +} + +} // namespace math +} // namespace le_fx + +// Math functions missing in Android NDK: +#if defined(LE_FX_OS_ANDROID) + +namespace std { + +// +// Round to the nearest integer: We need this implementation +// since std::round is missing on android. +// +template +inline T round(const T &x) { + return static_cast(std::floor(static_cast(x) + 0.5)); +} + +} // namespace std + +#endif // LE_FX_OS_ANDROID + +#endif // LE_FX_ENGINE_COMMON_CORE_MATH_H_ diff --git a/media/libeffects/loudness/common/core/os.h b/media/libeffects/loudness/common/core/os.h new file mode 100644 index 0000000..4a8ce82 --- /dev/null +++ b/media/libeffects/loudness/common/core/os.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LE_FX_ENGINE_COMMON_CORE_OS_H_ +#define LE_FX_ENGINE_COMMON_CORE_OS_H_ + +// ----------------------------------------------------------------------------- +// OS Identification: +// ----------------------------------------------------------------------------- + +#define LE_FX_OS_UNIX +#if defined(__ANDROID__) +# define LE_FX_OS_ANDROID +#endif // Android + +#endif // LE_FX_ENGINE_COMMON_CORE_OS_H_ diff --git a/media/libeffects/loudness/common/core/types.h b/media/libeffects/loudness/common/core/types.h new file mode 100644 index 0000000..d1b6c6a --- /dev/null +++ b/media/libeffects/loudness/common/core/types.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LE_FX_ENGINE_COMMON_CORE_TYPES_H_ +#define LE_FX_ENGINE_COMMON_CORE_TYPES_H_ + +#include "common/core/os.h" + +#include "common/core/basic_types.h" + +#ifndef LE_FX_DISALLOW_COPY_AND_ASSIGN +#define LE_FX_DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&); \ + void operator=(const TypeName&) +#endif // LE_FX_DISALLOW_COPY_AND_ASSIGN + + +#endif // LE_FX_ENGINE_COMMON_CORE_TYPES_H_ diff --git a/media/libeffects/loudness/dsp/core/basic-inl.h b/media/libeffects/loudness/dsp/core/basic-inl.h new file mode 100644 index 0000000..3f77147 --- /dev/null +++ b/media/libeffects/loudness/dsp/core/basic-inl.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LE_FX_ENGINE_DSP_CORE_BASIC_INL_H_ +#define LE_FX_ENGINE_DSP_CORE_BASIC_INL_H_ + +#include + +namespace le_fx { + +namespace sigmod { + +template +int SearchIndex(const T x_data[], + T x, + int start_index, + int end_index) { + int start = start_index; + int end = end_index; + while (end > start + 1) { + int i = (end + start) / 2; + if (x_data[i] > x) { + end = i; + } else { + start = i; + } + } + return start; +} + +} // namespace sigmod + +} // namespace le_fx + +#endif // LE_FX_ENGINE_DSP_CORE_BASIC_INL_H_ diff --git a/media/libeffects/loudness/dsp/core/basic.h b/media/libeffects/loudness/dsp/core/basic.h new file mode 100644 index 0000000..27e0a8d --- /dev/null +++ b/media/libeffects/loudness/dsp/core/basic.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LE_FX_ENGINE_DSP_CORE_BASIC_H_ +#define LE_FX_ENGINE_DSP_CORE_BASIC_H_ + +#include +#include "common/core/math.h" +#include "common/core/types.h" + +namespace le_fx { + +namespace sigmod { + +// Searchs for the interval that contains using a divide-and-conquer +// algorithm. +// X[]: a vector of sorted values (X[i+1] > X[i]) +// x: a value +// StartIndex: the minimum searched index +// EndIndex: the maximum searched index +// returns: the index that satisfies: X[i] <= x <= X[i+1] && +// StartIndex <= i <= (EndIndex-1) +template +int SearchIndex(const T x_data[], + T x, + int start_index, + int end_index); + +} // namespace sigmod + +} // namespace le_fx + +#include "dsp/core/basic-inl.h" + +#endif // LE_FX_ENGINE_DSP_CORE_BASIC_H_ diff --git a/media/libeffects/loudness/dsp/core/dynamic_range_compression-inl.h b/media/libeffects/loudness/dsp/core/dynamic_range_compression-inl.h new file mode 100644 index 0000000..fed8c2a --- /dev/null +++ b/media/libeffects/loudness/dsp/core/dynamic_range_compression-inl.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef LE_FX_ENGINE_DSP_CORE_DYNAMIC_RANGE_COMPRESSION_INL_H_ +#define LE_FX_ENGINE_DSP_CORE_DYNAMIC_RANGE_COMPRESSION_INL_H_ + +//#define LOG_NDEBUG 0 +#include + + +namespace le_fx { + + +inline void AdaptiveDynamicRangeCompression::set_knee_threshold(float decibel) { + // Converts to 1og-base + knee_threshold_in_decibel_ = decibel; + knee_threshold_ = 0.1151292546497023061569109358970308676362037658691406250f * + decibel + 10.39717719035538401328722102334722876548767089843750f; +} + + +inline void AdaptiveDynamicRangeCompression::set_knee_threshold_via_target_gain( + float target_gain) { + const float decibel = target_gain_to_knee_threshold_.Interpolate( + target_gain); + ALOGE("set_knee_threshold_via_target_gain: decibel =%.3f", decibel); + set_knee_threshold(decibel); +} + +} // namespace le_fx + + +#endif // LE_FX_ENGINE_DSP_CORE_DYNAMIC_RANGE_COMPRESSION_INL_H_ diff --git a/media/libeffects/loudness/dsp/core/dynamic_range_compression.cpp b/media/libeffects/loudness/dsp/core/dynamic_range_compression.cpp new file mode 100644 index 0000000..2bbd043 --- /dev/null +++ b/media/libeffects/loudness/dsp/core/dynamic_range_compression.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "common/core/math.h" +#include "common/core/types.h" +#include "dsp/core/basic.h" +#include "dsp/core/interpolation.h" +#include "dsp/core/dynamic_range_compression.h" + +//#define LOG_NDEBUG 0 +#include + + +namespace le_fx { + +// Definitions for static const class members declared in +// dynamic_range_compression.h. +const float AdaptiveDynamicRangeCompression::kMinAbsValue = 0.000001f; +const float AdaptiveDynamicRangeCompression::kMinLogAbsValue = + 0.032766999999999997517097227728299912996590137481689453125f; +const float AdaptiveDynamicRangeCompression::kFixedPointLimit = 32767.0f; +const float AdaptiveDynamicRangeCompression::kInverseFixedPointLimit = + 1.0f / AdaptiveDynamicRangeCompression::kFixedPointLimit; +const float AdaptiveDynamicRangeCompression::kDefaultKneeThresholdInDecibel = + -8.0f; +const float AdaptiveDynamicRangeCompression::kCompressionRatio = 7.0f; +const float AdaptiveDynamicRangeCompression::kTauAttack = 0.001f; +const float AdaptiveDynamicRangeCompression::kTauRelease = 0.015f; + +AdaptiveDynamicRangeCompression::AdaptiveDynamicRangeCompression() { + static const float kTargetGain[] = { + 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; + static const float kKneeThreshold[] = { + -8.0f, -8.0f, -8.5f, -9.0f, -10.0f }; + target_gain_to_knee_threshold_.Initialize( + &kTargetGain[0], &kKneeThreshold[0], + sizeof(kTargetGain) / sizeof(kTargetGain[0])); +} + +bool AdaptiveDynamicRangeCompression::Initialize( + float target_gain, float sampling_rate) { + set_knee_threshold_via_target_gain(target_gain); + sampling_rate_ = sampling_rate; + state_ = 0.0f; + compressor_gain_ = 1.0f; + if (kTauAttack > 0.0f) { + const float taufs = kTauAttack * sampling_rate_; + alpha_attack_ = std::exp(-1.0f / taufs); + } else { + alpha_attack_ = 0.0f; + } + if (kTauRelease > 0.0f) { + const float taufs = kTauRelease * sampling_rate_; + alpha_release_ = std::exp(-1.0f / taufs); + } else { + alpha_release_ = 0.0f; + } + // Feed-forward topology + slope_ = 1.0f / kCompressionRatio - 1.0f; + return true; +} + +float AdaptiveDynamicRangeCompression::Compress(float x) { + const float max_abs_x = std::max(std::fabs(x), kMinLogAbsValue); + const float max_abs_x_dB = math::fast_log(max_abs_x); + // Subtract Threshold from log-encoded input to get the amount of overshoot + const float overshoot = max_abs_x_dB - knee_threshold_; + // Hard half-wave rectifier + const float rect = std::max(overshoot, 0.0f); + // Multiply rectified overshoot with slope + const float cv = rect * slope_; + const float prev_state = state_; + if (cv <= state_) { + state_ = alpha_attack_ * state_ + (1.0f - alpha_attack_) * cv; + } else { + state_ = alpha_release_ * state_ + (1.0f - alpha_release_) * cv; + } + compressor_gain_ *= + math::ExpApproximationViaTaylorExpansionOrder5(state_ - prev_state); + x *= compressor_gain_; + if (x > kFixedPointLimit) { + return kFixedPointLimit; + } + if (x < -kFixedPointLimit) { + return -kFixedPointLimit; + } + return x; +} + +} // namespace le_fx + diff --git a/media/libeffects/loudness/dsp/core/dynamic_range_compression.h b/media/libeffects/loudness/dsp/core/dynamic_range_compression.h new file mode 100644 index 0000000..4c015df --- /dev/null +++ b/media/libeffects/loudness/dsp/core/dynamic_range_compression.h @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef LE_FX_ENGINE_DSP_CORE_DYNAMIC_RANGE_COMPRESSION_H_ +#define LE_FX_ENGINE_DSP_CORE_DYNAMIC_RANGE_COMPRESSION_H_ + +#include "common/core/types.h" +#include "common/core/math.h" +#include "dsp/core/basic.h" +#include "dsp/core/interpolation.h" + +//#define LOG_NDEBUG 0 +#include + + +namespace le_fx { + +// An adaptive dynamic range compression algorithm. The gain adaptation is made +// at the logarithmic domain and it is based on a Branching-Smooth compensated +// digital peak detector with different time constants for attack and release. +class AdaptiveDynamicRangeCompression { + public: + AdaptiveDynamicRangeCompression(); + + // Initializes the compressor using prior information. It assumes that the + // input signal is speech from high-quality recordings that is scaled and then + // fed to the compressor. The compressor is tuned according to the target gain + // that is expected to be applied. + // + // Target gain receives values between 0.0 and 10.0. The knee threshold is + // reduced as the target gain increases in order to fit the increased range of + // values. + // + // Values between 1.0 and 2.0 will only mildly affect your signal. Higher + // values will reduce the dynamic range of the signal to the benefit of + // increased loudness. + // + // If nothing is known regarding the input, a `target_gain` of 1.0f is a + // relatively safe choice for many signals. + bool Initialize(float target_gain, float sampling_rate); + + // A fast version of the algorithm that uses approximate computations for the + // log(.) and exp(.). + float Compress(float x); + + // This version is slower than Compress(.) but faster than CompressSlow(.) + float CompressNormalSpeed(float x); + + // A slow version of the algorithm that is easier for further developement, + // tuning and debugging + float CompressSlow(float x); + + // Sets knee threshold (in decibel). + void set_knee_threshold(float decibel); + + // Sets knee threshold via the target gain using an experimentally derived + // relationship. + void set_knee_threshold_via_target_gain(float target_gain); + + private: + // The minimum accepted absolute input value and it's natural logarithm. This + // is to prevent numerical issues when the input is close to zero + static const float kMinAbsValue; + static const float kMinLogAbsValue; + // Fixed-point arithmetic limits + static const float kFixedPointLimit; + static const float kInverseFixedPointLimit; + // The default knee threshold in decibel. The knee threshold defines when the + // compressor is actually starting to compress the value of the input samples + static const float kDefaultKneeThresholdInDecibel; + // The compression ratio is the reciprocal of the slope of the line segment + // above the threshold (in the log-domain). The ratio controls the + // effectiveness of the compression. + static const float kCompressionRatio; + // The attack time of the envelope detector + static const float kTauAttack; + // The release time of the envelope detector + static const float kTauRelease; + + float sampling_rate_; + // the internal state of the envelope detector + float state_; + // the latest gain factor that was applied to the input signal + float compressor_gain_; + // attack constant for exponential dumping + float alpha_attack_; + // release constant for exponential dumping + float alpha_release_; + float slope_; + // The knee threshold + float knee_threshold_; + float knee_threshold_in_decibel_; + // This interpolator provides the function that relates target gain to knee + // threshold. + sigmod::InterpolatorLinear target_gain_to_knee_threshold_; + + LE_FX_DISALLOW_COPY_AND_ASSIGN(AdaptiveDynamicRangeCompression); +}; + +} // namespace le_fx + +#include "dsp/core/dynamic_range_compression-inl.h" + +#endif // LE_FX_ENGINE_DSP_CORE_DYNAMIC_RANGE_COMPRESSION_H_ diff --git a/media/libeffects/loudness/dsp/core/interpolation.h b/media/libeffects/loudness/dsp/core/interpolation.h new file mode 100644 index 0000000..23c287c --- /dev/null +++ b/media/libeffects/loudness/dsp/core/interpolation.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef LE_FX_ENGINE_DSP_CORE_INTERPOLATION_H_ +#define LE_FX_ENGINE_DSP_CORE_INTERPOLATION_H_ + +#include "common/core/math.h" +#include "dsp/core/interpolator_base.h" +#include "dsp/core/interpolator_linear.h" + +#endif // LE_FX_ENGINE_DSP_CORE_INTERPOLATION_H_ + diff --git a/media/libeffects/loudness/dsp/core/interpolator_base-inl.h b/media/libeffects/loudness/dsp/core/interpolator_base-inl.h new file mode 100644 index 0000000..bd08b65 --- /dev/null +++ b/media/libeffects/loudness/dsp/core/interpolator_base-inl.h @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LE_FX_ENGINE_DSP_CORE_INTERPOLATOR_BASE_INL_H_ +#define LE_FX_ENGINE_DSP_CORE_INTERPOLATOR_BASE_INL_H_ + +#include "dsp/core/basic.h" + +//#define LOG_NDEBUG 0 +#include + + +namespace le_fx { + +namespace sigmod { + +template +InterpolatorBase::InterpolatorBase() { + status_ = false; + cached_index_ = 0; + x_data_ = NULL; + y_data_ = NULL; + data_length_ = 0; + own_x_data_ = false; + x_start_offset_ = 0.0; + last_element_index_ = -1; + x_inverse_sampling_interval_ = 0.0; + state_ = NULL; +} + +template +InterpolatorBase::~InterpolatorBase() { + delete [] state_; + if (own_x_data_) { + delete [] x_data_; + } +} + +template +bool InterpolatorBase::Initialize(const vector &x_data, + const vector &y_data) { +#ifndef NDEBUG + if (x_data.size() != y_data.size()) { + LoggerError("InterpolatorBase::Initialize: xData size (%d) != yData size" + " (%d)", x_data.size(), y_data.size()); + } +#endif + return Initialize(&x_data[0], &y_data[0], x_data.size()); +} + +template +bool InterpolatorBase::Initialize(double x_start_offset, + double x_sampling_interval, + const vector &y_data) { + return Initialize(x_start_offset, + x_sampling_interval, + &y_data[0], + y_data.size()); +} + +template +bool InterpolatorBase::Initialize(double x_start_offset, + double x_sampling_interval, + const T *y_data, + int data_length) { + // Constructs and populate x-axis data: `x_data_` + T *x_data_tmp = new T[data_length]; + float time_offset = x_start_offset; + for (int n = 0; n < data_length; n++) { + x_data_tmp[n] = time_offset; + time_offset += x_sampling_interval; + } + Initialize(x_data_tmp, y_data, data_length); + // Sets-up the regularly sampled interpolation mode + x_start_offset_ = x_start_offset; + x_inverse_sampling_interval_ = 1.0 / x_sampling_interval; + own_x_data_ = true; + return status_; +} + + +template +bool InterpolatorBase::Initialize( + const T *x_data, const T *y_data, int data_length) { + // Default settings + cached_index_ = 0; + data_length_ = 0; + x_start_offset_ = 0; + x_inverse_sampling_interval_ = 0; + state_ = NULL; + // Input data is externally owned + own_x_data_ = false; + x_data_ = x_data; + y_data_ = y_data; + data_length_ = data_length; + last_element_index_ = data_length - 1; + // Check input data sanity + for (int n = 0; n < last_element_index_; ++n) { + if (x_data_[n + 1] <= x_data_[n]) { + ALOGE("InterpolatorBase::Initialize: xData are not ordered or " + "contain equal values (X[%d] <= X[%d]) (%.5e <= %.5e)", + n + 1, n, x_data_[n + 1], x_data_[n]); + status_ = false; + return false; + } + } + // Pre-compute internal state by calling the corresponding function of the + // derived class. + status_ = static_cast(this)->SetInternalState(); + return status_; +} + +template +T InterpolatorBase::Interpolate(T x) { +#ifndef NDEBUG + if (cached_index_ < 0 || cached_index_ > data_length_ - 2) { + LoggerError("InterpolatorBase:Interpolate: CachedIndex_ out of bounds " + "[0, %d, %d]", cached_index_, data_length_ - 2); + } +#endif + // Search for the containing interval + if (x <= x_data_[cached_index_]) { + if (cached_index_ <= 0) { + cached_index_ = 0; + return y_data_[0]; + } + if (x >= x_data_[cached_index_ - 1]) { + cached_index_--; // Fast descending + } else { + if (x <= x_data_[0]) { + cached_index_ = 0; + return y_data_[0]; + } + cached_index_ = SearchIndex(x_data_, x, 0, cached_index_); + } + } else { + if (cached_index_ >= last_element_index_) { + cached_index_ = last_element_index_; + return y_data_[last_element_index_]; + } + if (x > x_data_[cached_index_ + 1]) { + if (cached_index_ + 2 > last_element_index_) { + cached_index_ = last_element_index_ - 1; + return y_data_[last_element_index_]; + } + if (x <= x_data_[cached_index_ + 2]) { + cached_index_++; // Fast ascending + } else { + if (x >= x_data_[last_element_index_]) { + cached_index_ = last_element_index_ - 1; + return y_data_[last_element_index_]; + } + cached_index_ = SearchIndex( + x_data_, x, cached_index_, last_element_index_); + } + } + } + // Compute interpolated value by calling the corresponding function of the + // derived class. + return static_cast(this)->MethodSpecificInterpolation(x); +} + +} // namespace sigmod + +} // namespace le_fx + +#endif // LE_FX_ENGINE_DSP_CORE_INTERPOLATOR_BASE_INL_H_ diff --git a/media/libeffects/loudness/dsp/core/interpolator_base.h b/media/libeffects/loudness/dsp/core/interpolator_base.h new file mode 100644 index 0000000..0cd1a35 --- /dev/null +++ b/media/libeffects/loudness/dsp/core/interpolator_base.h @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LE_FX_ENGINE_DSP_CORE_INTERPOLATOR_BASE_H_ +#define LE_FX_ENGINE_DSP_CORE_INTERPOLATOR_BASE_H_ + +#include "common/core/types.h" + +namespace le_fx { + +namespace sigmod { + +// Interpolation base-class that provides the interface, while it is the derived +// class that provides the specific interpolation algorithm. The following list +// of interpolation algorithms are currently present: +// +// InterpolationSine: weighted interpolation between y_data[n] and +// y_data[n+1] using a sin(.) weighting factor from +// 0 to pi/4. +// InterpolationLinear: linear interpolation +// InterpolationSplines: spline-based interpolation +// +// Example (using derived spline-based interpolation class): +// InterpolatorSplines interp(x_data, y_data, data_length); +// for (int n = 0; n < data_length; n++) Y[n] = interp.Interpolate(X[n]); +// +template +class InterpolatorBase { + public: + InterpolatorBase(); + ~InterpolatorBase(); + + // Generic random-access interpolation with arbitrary spaced x-axis samples. + // Below X[0], the interpolator returns Y[0]. Above X[data_length-1], it + // returns Y[data_length-1]. + T Interpolate(T x); + + bool get_status() const { + return status_; + } + + // Initializes internal buffers. + // x_data: [(data_length)x1] x-axis coordinates (searching axis) + // y_data: [(data_length)x1] y-axis coordinates (interpolation axis) + // data_length: number of points + // returns `true` if everything is ok, `false`, otherwise + bool Initialize(const T *x_data, const T *y_data, int data_length); + + // Initializes internal buffers. + // x_data: x-axis coordinates (searching axis) + // y_data: y-axis coordinates (interpolating axis) + // returns `true` if everything is ok, `false`, otherwise + bool Initialize(const vector &x_data, const vector &y_data); + + // Initialization for regularly sampled sequences, where: + // x_data[i] = x_start_offset + i * x_sampling_interval + bool Initialize(double x_start_offset, + double x_sampling_interval, + const vector &y_data); + + // Initialization for regularly sampled sequences, where: + // x_data[i] = x_start_offset + i * x_sampling_interval + bool Initialize(double x_start_offset, + double x_sampling_interval, + const T *y_data, + int data_length); + + protected: + // Is set to false if something goes wrong, and to true if everything is ok. + bool status_; + + // The start-index of the previously searched interval + int cached_index_; + + // Data points + const T *x_data_; // Externally or internally owned, depending on own_x_data_ + const T *y_data_; // Externally owned (always) + int data_length_; + // Index of the last element `data_length_ - 1` kept here for optimization + int last_element_index_; + bool own_x_data_; + // For regularly-samples sequences, keep only the boundaries and the intervals + T x_start_offset_; + float x_inverse_sampling_interval_; + + // Algorithm state (internally owned) + double *state_; + + private: + LE_FX_DISALLOW_COPY_AND_ASSIGN(InterpolatorBase); +}; + +} // namespace sigmod + +} // namespace le_fx + +#include "dsp/core/interpolator_base-inl.h" + +#endif // LE_FX_ENGINE_DSP_CORE_INTERPOLATOR_BASE_H_ diff --git a/media/libeffects/loudness/dsp/core/interpolator_linear.h b/media/libeffects/loudness/dsp/core/interpolator_linear.h new file mode 100644 index 0000000..434698a --- /dev/null +++ b/media/libeffects/loudness/dsp/core/interpolator_linear.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LE_FX_ENGINE_DSP_CORE_INTERPOLATOR_LINEAR_H_ +#define LE_FX_ENGINE_DSP_CORE_INTERPOLATOR_LINEAR_H_ + +#include +#include "dsp/core/interpolator_base.h" + +namespace le_fx { + +namespace sigmod { + +// Linear interpolation class. +// +// The main functionality of this class is provided by it's base-class, so +// please refer to: InterpolatorBase +// +// Example: +// InterpolatorLinear interp(x_data, y_data, data_length); +// for (int n = 0; n < data_length; n++) Y[n] = interp.Interpolate(X[n]); +// +template +class InterpolatorLinear: public InterpolatorBase > { + public: + InterpolatorLinear() { } + ~InterpolatorLinear() { } + + protected: + // Provides the main implementation of the linear interpolation algorithm. + // Assumes that: X[cached_index_] < x < X[cached_index_ + 1] + T MethodSpecificInterpolation(T x); + + // Pre-compute internal state_ parameters. + bool SetInternalState(); + + private: + friend class InterpolatorBase >; + typedef InterpolatorBase > BaseClass; + using BaseClass::status_; + using BaseClass::cached_index_; + using BaseClass::x_data_; + using BaseClass::y_data_; + using BaseClass::data_length_; + using BaseClass::state_; + + LE_FX_DISALLOW_COPY_AND_ASSIGN(InterpolatorLinear); +}; + +template +inline T InterpolatorLinear::MethodSpecificInterpolation(T x) { + T dX = x_data_[cached_index_ + 1] - x_data_[cached_index_]; + T dY = y_data_[cached_index_ + 1] - y_data_[cached_index_]; + T dx = x - x_data_[cached_index_]; + return y_data_[cached_index_] + (dY * dx) / dX; +} + +template +bool InterpolatorLinear::SetInternalState() { + state_ = NULL; + return true; +} + +} // namespace sigmod + +} // namespace le_fx + +#endif // LE_FX_ENGINE_DSP_CORE_INTERPOLATOR_LINEAR_H_ -- cgit v1.1 From 5baf2af52cd186633b7173196c1e4a4cd3435f22 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Thu, 12 Sep 2013 17:37:00 -0700 Subject: more support for audio effect offload Offloading of audio effects is now enabled for offloaded output threads. If an effect not supporting offload is enabled, the AudioTrack is invalidated so that it can be recreated in PCM mode. Fix some issues in effect proxy related to handling of effect commands to offloaded and non offloaded effects. Also fixed a bug on capture index in software Visualizer effect. Bug: 8174034. Change-Id: Ib23d3c2d5a652361b0aaec7faee09102f2b18fce --- media/libeffects/proxy/EffectProxy.cpp | 59 +++++++++++++++++++----- media/libeffects/visualizer/EffectVisualizer.cpp | 4 +- 2 files changed, 50 insertions(+), 13 deletions(-) (limited to 'media/libeffects') 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; } -- cgit v1.1 From 09647d29eaf429ce88c9c9709ff63dee62f2147a Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Fri, 20 Sep 2013 11:58:40 -0700 Subject: Add support for level measurements in Visualizer New commands to set a measurement mode and perform peak + RMS measurements. Bug 8413913 Change-Id: Ib25254065c79d365ebb34f9dc9caa0490e2d300d --- media/libeffects/visualizer/EffectVisualizer.cpp | 154 ++++++++++++++++++++--- 1 file changed, 137 insertions(+), 17 deletions(-) (limited to 'media/libeffects') diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp index 96935e3..0f27cbf 100644 --- a/media/libeffects/visualizer/EffectVisualizer.cpp +++ b/media/libeffects/visualizer/EffectVisualizer.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include @@ -54,6 +55,18 @@ enum visualizer_state_e { #define CAPTURE_BUF_SIZE 65536 // "64k should be enough for everyone" +#define DISCARD_MEASUREMENTS_TIME_MS 2000 // discard measurements older than this number of ms + +// maximum number of buffers for which we keep track of the measurements +#define MEASUREMENT_WINDOW_MAX_SIZE_IN_BUFFERS 25 + + +struct BufferStats { + bool mIsValid; + uint16_t mPeakU16; // the positive peak of the absolute value of the samples in a buffer + float mRmsSquared; // the average square of the samples in a buffer +}; + struct VisualizerContext { const struct effect_interface_s *mItfe; effect_config_t mConfig; @@ -65,11 +78,34 @@ struct VisualizerContext { uint32_t mLatency; struct timespec mBufferUpdateTime; uint8_t mCaptureBuf[CAPTURE_BUF_SIZE]; + // for measurements + uint8_t mChannelCount; // to avoid recomputing it every time a buffer is processed + uint32_t mMeasurementMode; + uint8_t mMeasurementWindowSizeInBuffers; + uint8_t mMeasurementBufferIdx; + BufferStats mPastMeasurements[MEASUREMENT_WINDOW_MAX_SIZE_IN_BUFFERS]; }; // //--- Local functions // +uint32_t Visualizer_getDeltaTimeMsFromUpdatedTime(VisualizerContext* pContext) { + uint32_t deltaMs = 0; + if (pContext->mBufferUpdateTime.tv_sec != 0) { + struct timespec ts; + if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) { + time_t secs = ts.tv_sec - pContext->mBufferUpdateTime.tv_sec; + long nsec = ts.tv_nsec - pContext->mBufferUpdateTime.tv_nsec; + if (nsec < 0) { + --secs; + nsec += 1000000000; + } + deltaMs = secs * 1000 + nsec / 1000000; + } + } + return deltaMs; +} + void Visualizer_reset(VisualizerContext *pContext) { @@ -165,9 +201,21 @@ int Visualizer_init(VisualizerContext *pContext) pContext->mConfig.outputCfg.bufferProvider.cookie = NULL; pContext->mConfig.outputCfg.mask = EFFECT_CONFIG_ALL; + // visualization initialization pContext->mCaptureSize = VISUALIZER_CAPTURE_SIZE_MAX; pContext->mScalingMode = VISUALIZER_SCALING_MODE_NORMALIZED; + // measurement initialization + pContext->mChannelCount = popcount(pContext->mConfig.inputCfg.channels); + pContext->mMeasurementMode = MEASUREMENT_MODE_NONE; + pContext->mMeasurementWindowSizeInBuffers = MEASUREMENT_WINDOW_MAX_SIZE_IN_BUFFERS; + pContext->mMeasurementBufferIdx = 0; + for (uint8_t i=0 ; imMeasurementWindowSizeInBuffers ; i++) { + pContext->mPastMeasurements[i].mIsValid = false; + pContext->mPastMeasurements[i].mPeakU16 = 0; + pContext->mPastMeasurements[i].mRmsSquared = 0; + } + Visualizer_setConfig(pContext, &pContext->mConfig); return 0; @@ -270,6 +318,30 @@ int Visualizer_process( return -EINVAL; } + // perform measurements if needed + if (pContext->mMeasurementMode & MEASUREMENT_MODE_PEAK_RMS) { + // find the peak and RMS squared for the new buffer + uint32_t inIdx; + int16_t maxSample = 0; + float rmsSqAcc = 0; + for (inIdx = 0 ; inIdx < inBuffer->frameCount * pContext->mChannelCount ; inIdx++) { + if (inBuffer->s16[inIdx] > maxSample) { + maxSample = inBuffer->s16[inIdx]; + } else if (-inBuffer->s16[inIdx] > maxSample) { + maxSample = -inBuffer->s16[inIdx]; + } + rmsSqAcc += (inBuffer->s16[inIdx] * inBuffer->s16[inIdx]); + } + // store the measurement + pContext->mPastMeasurements[pContext->mMeasurementBufferIdx].mPeakU16 = (uint16_t)maxSample; + pContext->mPastMeasurements[pContext->mMeasurementBufferIdx].mRmsSquared = + rmsSqAcc / (inBuffer->frameCount * pContext->mChannelCount); + pContext->mPastMeasurements[pContext->mMeasurementBufferIdx].mIsValid = true; + if (++pContext->mMeasurementBufferIdx >= pContext->mMeasurementWindowSizeInBuffers) { + pContext->mMeasurementBufferIdx = 0; + } + } + // all code below assumes stereo 16 bit PCM output and input int32_t shift; @@ -423,6 +495,12 @@ int Visualizer_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize, p->vsize = sizeof(uint32_t); *replySize += sizeof(uint32_t); break; + case VISUALIZER_PARAM_MEASUREMENT_MODE: + ALOGV("get mMeasurementMode = %d", pContext->mMeasurementMode); + *((uint32_t *)p->data + 1) = pContext->mMeasurementMode; + p->vsize = sizeof(uint32_t); + *replySize += sizeof(uint32_t); + break; default: p->status = -EINVAL; } @@ -452,6 +530,10 @@ int Visualizer_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize, pContext->mLatency = *((uint32_t *)p->data + 1); ALOGV("set mLatency = %d", pContext->mLatency); break; + case VISUALIZER_PARAM_MEASUREMENT_MODE: + pContext->mMeasurementMode = *((uint32_t *)p->data + 1); + ALOGV("set mMeasurementMode = %d", pContext->mMeasurementMode); + break; default: *(int32_t *)pReplyData = -EINVAL; } @@ -470,24 +552,12 @@ int Visualizer_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize, } if (pContext->mState == VISUALIZER_STATE_ACTIVE) { int32_t latencyMs = pContext->mLatency; - uint32_t deltaMs = 0; - if (pContext->mBufferUpdateTime.tv_sec != 0) { - struct timespec ts; - if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) { - time_t secs = ts.tv_sec - pContext->mBufferUpdateTime.tv_sec; - long nsec = ts.tv_nsec - pContext->mBufferUpdateTime.tv_nsec; - if (nsec < 0) { - --secs; - nsec += 1000000000; - } - deltaMs = secs * 1000 + nsec / 1000000; - latencyMs -= deltaMs; - if (latencyMs < 0) { - latencyMs = 0; - } - } + const uint32_t deltaMs = Visualizer_getDeltaTimeMsFromUpdatedTime(pContext); + latencyMs -= deltaMs; + if (latencyMs < 0) { + latencyMs = 0; } - uint32_t deltaSmpl = pContext->mConfig.inputCfg.samplingRate * latencyMs / 1000; + const uint32_t deltaSmpl = pContext->mConfig.inputCfg.samplingRate * latencyMs / 1000; int32_t capturePoint = pContext->mCaptureIdx - pContext->mCaptureSize - deltaSmpl; int32_t captureSize = pContext->mCaptureSize; @@ -525,6 +595,56 @@ int Visualizer_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize, break; + case VISUALIZER_CMD_MEASURE: { + uint16_t peakU16 = 0; + float sumRmsSquared = 0.0f; + uint8_t nbValidMeasurements = 0; + // reset measurements if last measurement was too long ago (which implies stored + // measurements aren't relevant anymore and shouldn't bias the new one) + const int32_t delayMs = Visualizer_getDeltaTimeMsFromUpdatedTime(pContext); + if (delayMs > DISCARD_MEASUREMENTS_TIME_MS) { + ALOGE("Discarding measurements, last measurement is %dms old", delayMs); + for (uint8_t i=0 ; imMeasurementWindowSizeInBuffers ; i++) { + pContext->mPastMeasurements[i].mIsValid = false; + pContext->mPastMeasurements[i].mPeakU16 = 0; + pContext->mPastMeasurements[i].mRmsSquared = 0; + } + pContext->mMeasurementBufferIdx = 0; + } else { + // only use actual measurements, otherwise the first RMS measure happening before + // MEASUREMENT_WINDOW_MAX_SIZE_IN_BUFFERS have been played will always be artificially + // low + for (uint8_t i=0 ; i < pContext->mMeasurementWindowSizeInBuffers ; i++) { + if (pContext->mPastMeasurements[i].mIsValid) { + if (pContext->mPastMeasurements[i].mPeakU16 > peakU16) { + peakU16 = pContext->mPastMeasurements[i].mPeakU16; + } + if (pContext->mMeasurementWindowSizeInBuffers != 0) { + sumRmsSquared += pContext->mPastMeasurements[i].mRmsSquared; + } + nbValidMeasurements++; + } + } + } + float rms = nbValidMeasurements == 0 ? 0.0f : sqrtf(sumRmsSquared / nbValidMeasurements); + int32_t* pIntReplyData = (int32_t*)pReplyData; + // convert from I16 sample values to mB and write results + if (rms < 0.000016f) { + pIntReplyData[MEASUREMENT_IDX_RMS] = -9600; //-96dB + } else { + pIntReplyData[MEASUREMENT_IDX_RMS] = (int32_t) (2000 * log10(rms / 32767.0f)); + } + if (peakU16 == 0) { + pIntReplyData[MEASUREMENT_IDX_PEAK] = -9600; //-96dB + } else { + pIntReplyData[MEASUREMENT_IDX_PEAK] = (int32_t) (2000 * log10(peakU16 / 32767.0f)); + } + ALOGV("LEVEL_MONITOR_CMD_MEASURE peak=%d (%dmB), rms=%.1f (%dmB)", + peakU16, pIntReplyData[MEASUREMENT_IDX_PEAK], + rms, pIntReplyData[MEASUREMENT_IDX_RMS]); + } + break; + default: ALOGW("Visualizer_command invalid command %d",cmdCode); return -EINVAL; -- cgit v1.1 From ddfbfaeb00295fff7351711f0f044f17d6c40f3c Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Fri, 20 Sep 2013 12:27:32 -0700 Subject: fix oflload effect proxy commmand handling Implement a more generic command handling in offload effect proxy. All commands are sent to both sub effects but only the reply from the active one is returned to the caller. Bug: 8174034. Change-Id: Ia45f9933b3bf338257ec70b37732fa1578d26b9f --- media/libeffects/proxy/EffectProxy.cpp | 95 ++++++++++++++++++---------------- media/libeffects/proxy/EffectProxy.h | 5 ++ 2 files changed, 54 insertions(+), 46 deletions(-) (limited to 'media/libeffects') diff --git a/media/libeffects/proxy/EffectProxy.cpp b/media/libeffects/proxy/EffectProxy.cpp index 41640da..b3304b7 100644 --- a/media/libeffects/proxy/EffectProxy.cpp +++ b/media/libeffects/proxy/EffectProxy.cpp @@ -48,20 +48,6 @@ 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, @@ -80,6 +66,7 @@ int EffectProxyCreate(const effect_uuid_t *uuid, pContext->ioId = ioId; pContext->uuid = *uuid; pContext->common_itfe = &gEffectInterface; + // The sub effects will be created in effect_command when the first command // for the effect is received pContext->eHandle[SUB_FX_HOST] = pContext->eHandle[SUB_FX_OFFLOAD] = NULL; @@ -124,6 +111,10 @@ int EffectProxyCreate(const effect_uuid_t *uuid, uuid_print.node[1], uuid_print.node[2], uuid_print.node[3], uuid_print.node[4], uuid_print.node[5]); #endif + + pContext->replySize = PROXY_REPLY_SIZE_DEFAULT; + pContext->replyData = (char *)malloc(PROXY_REPLY_SIZE_DEFAULT); + *pHandle = (effect_handle_t)pContext; ALOGV("EffectCreate end"); return 0; @@ -137,6 +128,8 @@ int EffectProxyRelease(effect_handle_t handle) { } ALOGV("EffectRelease"); delete pContext->desc; + free(pContext->replyData); + if (pContext->eHandle[SUB_FX_HOST]) EffectRelease(pContext->eHandle[SUB_FX_HOST]); if (pContext->eHandle[SUB_FX_OFFLOAD]) @@ -253,43 +246,53 @@ int Effect_command(effect_handle_t self, } // 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; + int *subStatus[SUB_FX_COUNT]; + uint32_t *subReplySize[SUB_FX_COUNT]; + void *subReplyData[SUB_FX_COUNT]; + uint32_t tmpSize; + int tmpStatus; - 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 != 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 - offloadStatus = (*pContext->eHandle[SUB_FX_OFFLOAD])->command( - pContext->eHandle[SUB_FX_OFFLOAD], cmdCode, cmdSize, - pCmdData, replySize != NULL ? &offloadReplySize : NULL, pReplyData); - offloadReplied = true; + // grow temp reply buffer if needed + if (replySize != NULL) { + tmpSize = pContext->replySize; + while (tmpSize < *replySize && tmpSize < PROXY_REPLY_SIZE_MAX) { + tmpSize *= 2; + } + if (tmpSize > pContext->replySize) { + ALOGV("Effect_command grow reply buf to %d", tmpSize); + pContext->replyData = (char *)realloc(pContext->replyData, tmpSize); + pContext->replySize = tmpSize; + } + if (tmpSize > *replySize) { + tmpSize = *replySize; + } + } else { + tmpSize = 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; + // tmpSize is now the actual reply size for the non active sub effect + + // Send command to sub effects. The command is sent to all sub effects so that their internal + // state is kept in sync. + // Only the reply from the active sub effect is returned to the caller. The reply from the + // other sub effect is lost in pContext->replyData + for (int i = 0; i < SUB_FX_COUNT; i++) { + if (pContext->eHandle[i] == NULL) { + continue; } - } else if (hostReplied) { - status = hostStatus; - if (replySize) { - *replySize = hostReplySize; + if (i == index) { + subStatus[i] = &status; + subReplySize[i] = replySize; + subReplyData[i] = pReplyData; + } else { + subStatus[i] = &tmpStatus; + subReplySize[i] = replySize == NULL ? NULL : &tmpSize; + subReplyData[i] = pReplyData == NULL ? NULL : pContext->replyData; } + *subStatus[i] = (*pContext->eHandle[i])->command( + pContext->eHandle[i], cmdCode, cmdSize, + pCmdData, subReplySize[i], subReplyData[i]); } + return status; } /* end Effect_command */ diff --git a/media/libeffects/proxy/EffectProxy.h b/media/libeffects/proxy/EffectProxy.h index 8992f93..acbe17e 100644 --- a/media/libeffects/proxy/EffectProxy.h +++ b/media/libeffects/proxy/EffectProxy.h @@ -57,6 +57,9 @@ const struct effect_interface_s gEffectInterface = { NULL, }; +#define PROXY_REPLY_SIZE_MAX (64 * 1024) // must be power of two +#define PROXY_REPLY_SIZE_DEFAULT 32 // must be power of two + struct EffectContext { const struct effect_interface_s *common_itfe; // Holds the itfe of the Proxy effect_descriptor_t* desc; // Points to the sub effect descriptors @@ -67,6 +70,8 @@ struct EffectContext { int32_t ioId; // The ioId in which the effect is created. // Stored in context to pass on to sub effect creation effect_uuid_t uuid; // UUID of the Proxy + char* replyData; // temporary buffer for non active sub effect command reply + uint32_t replySize; // current size of temporary reply buffer }; #if __cplusplus -- cgit v1.1 From 6fbc9ef121b081f888163190bb13cbac31599900 Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Tue, 24 Sep 2013 15:31:13 -0700 Subject: Fix log typos in Visualizer effect Fix errors in logs for Visualizer. Set loop counters on 32 bits Bug 8413913 Change-Id: Iad2140d003d15d45be46826a5e89baff14fe9e77 --- media/libeffects/visualizer/EffectVisualizer.cpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'media/libeffects') diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp index 0f27cbf..dc403ab 100644 --- a/media/libeffects/visualizer/EffectVisualizer.cpp +++ b/media/libeffects/visualizer/EffectVisualizer.cpp @@ -58,7 +58,7 @@ enum visualizer_state_e { #define DISCARD_MEASUREMENTS_TIME_MS 2000 // discard measurements older than this number of ms // maximum number of buffers for which we keep track of the measurements -#define MEASUREMENT_WINDOW_MAX_SIZE_IN_BUFFERS 25 +#define MEASUREMENT_WINDOW_MAX_SIZE_IN_BUFFERS 25 // note: buffer index is stored in uint8_t struct BufferStats { @@ -210,7 +210,7 @@ int Visualizer_init(VisualizerContext *pContext) pContext->mMeasurementMode = MEASUREMENT_MODE_NONE; pContext->mMeasurementWindowSizeInBuffers = MEASUREMENT_WINDOW_MAX_SIZE_IN_BUFFERS; pContext->mMeasurementBufferIdx = 0; - for (uint8_t i=0 ; imMeasurementWindowSizeInBuffers ; i++) { + for (uint32_t i=0 ; imMeasurementWindowSizeInBuffers ; i++) { pContext->mPastMeasurements[i].mIsValid = false; pContext->mPastMeasurements[i].mPeakU16 = 0; pContext->mPastMeasurements[i].mRmsSquared = 0; @@ -603,8 +603,8 @@ int Visualizer_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize, // measurements aren't relevant anymore and shouldn't bias the new one) const int32_t delayMs = Visualizer_getDeltaTimeMsFromUpdatedTime(pContext); if (delayMs > DISCARD_MEASUREMENTS_TIME_MS) { - ALOGE("Discarding measurements, last measurement is %dms old", delayMs); - for (uint8_t i=0 ; imMeasurementWindowSizeInBuffers ; i++) { + ALOGV("Discarding measurements, last measurement is %dms old", delayMs); + for (uint32_t i=0 ; imMeasurementWindowSizeInBuffers ; i++) { pContext->mPastMeasurements[i].mIsValid = false; pContext->mPastMeasurements[i].mPeakU16 = 0; pContext->mPastMeasurements[i].mRmsSquared = 0; @@ -614,14 +614,12 @@ int Visualizer_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize, // only use actual measurements, otherwise the first RMS measure happening before // MEASUREMENT_WINDOW_MAX_SIZE_IN_BUFFERS have been played will always be artificially // low - for (uint8_t i=0 ; i < pContext->mMeasurementWindowSizeInBuffers ; i++) { + for (uint32_t i=0 ; i < pContext->mMeasurementWindowSizeInBuffers ; i++) { if (pContext->mPastMeasurements[i].mIsValid) { if (pContext->mPastMeasurements[i].mPeakU16 > peakU16) { peakU16 = pContext->mPastMeasurements[i].mPeakU16; } - if (pContext->mMeasurementWindowSizeInBuffers != 0) { - sumRmsSquared += pContext->mPastMeasurements[i].mRmsSquared; - } + sumRmsSquared += pContext->mPastMeasurements[i].mRmsSquared; nbValidMeasurements++; } } @@ -639,7 +637,7 @@ int Visualizer_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize, } else { pIntReplyData[MEASUREMENT_IDX_PEAK] = (int32_t) (2000 * log10(peakU16 / 32767.0f)); } - ALOGV("LEVEL_MONITOR_CMD_MEASURE peak=%d (%dmB), rms=%.1f (%dmB)", + ALOGV("VISUALIZER_CMD_MEASURE peak=%d (%dmB), rms=%.1f (%dmB)", peakU16, pIntReplyData[MEASUREMENT_IDX_PEAK], rms, pIntReplyData[MEASUREMENT_IDX_RMS]); } -- cgit v1.1 From cd0c4683947231a7d3dc7811bedb75c5a965103c Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Wed, 25 Sep 2013 18:43:55 -0700 Subject: LoudnessEnhancer compatible with stereo imaging Use a single compressor for both channels. Envelope of signal is determined by looking at both channels. Bug 8413913 Change-Id: Ia9b6f34923d2977c60a3352500b858dfa1fab33c --- .../libeffects/loudness/EffectLoudnessEnhancer.cpp | 42 +++++++++------------- .../dsp/core/dynamic_range_compression-inl.h | 2 +- .../dsp/core/dynamic_range_compression.cpp | 35 ++++++++++++++++++ .../loudness/dsp/core/dynamic_range_compression.h | 3 ++ 4 files changed, 56 insertions(+), 26 deletions(-) (limited to 'media/libeffects') diff --git a/media/libeffects/loudness/EffectLoudnessEnhancer.cpp b/media/libeffects/loudness/EffectLoudnessEnhancer.cpp index dfc25db..91ed677 100644 --- a/media/libeffects/loudness/EffectLoudnessEnhancer.cpp +++ b/media/libeffects/loudness/EffectLoudnessEnhancer.cpp @@ -56,8 +56,7 @@ struct LoudnessEnhancerContext { int32_t mTargetGainmB;// target gain in mB // in this implementation, there is no coupling between the compression on the left and right // channels - le_fx::AdaptiveDynamicRangeCompression* mCompressorL; - le_fx::AdaptiveDynamicRangeCompression* mCompressorR; + le_fx::AdaptiveDynamicRangeCompression* mCompressor; }; // @@ -68,11 +67,10 @@ void LE_reset(LoudnessEnhancerContext *pContext) { ALOGV(" > LE_reset(%p)", pContext); - if ((pContext->mCompressorL != NULL) && (pContext->mCompressorR != NULL)) { + if (pContext->mCompressor != NULL) { float targetAmp = pow(10, pContext->mTargetGainmB/2000.0f); // mB to linear amplification ALOGV("LE_reset(): Target gain=%dmB <=> factor=%.2fX", pContext->mTargetGainmB, targetAmp); - pContext->mCompressorL->Initialize(targetAmp, pContext->mConfig.inputCfg.samplingRate); - pContext->mCompressorR->Initialize(targetAmp, pContext->mConfig.inputCfg.samplingRate); + pContext->mCompressor->Initialize(targetAmp, pContext->mConfig.inputCfg.samplingRate); } else { ALOGE("LE_reset(%p): null compressors, can't apply target gain", pContext); } @@ -176,13 +174,9 @@ int LE_init(LoudnessEnhancerContext *pContext) float targetAmp = pow(10, pContext->mTargetGainmB/2000.0f); // mB to linear amplification ALOGV("LE_init(): Target gain=%dmB <=> factor=%.2fX", pContext->mTargetGainmB, targetAmp); - if (pContext->mCompressorL == NULL) { - pContext->mCompressorL = new le_fx::AdaptiveDynamicRangeCompression(); - pContext->mCompressorL->Initialize(targetAmp, pContext->mConfig.inputCfg.samplingRate); - } - if (pContext->mCompressorR == NULL) { - pContext->mCompressorR = new le_fx::AdaptiveDynamicRangeCompression(); - pContext->mCompressorR->Initialize(targetAmp, pContext->mConfig.inputCfg.samplingRate); + if (pContext->mCompressor == NULL) { + pContext->mCompressor = new le_fx::AdaptiveDynamicRangeCompression(); + pContext->mCompressor->Initialize(targetAmp, pContext->mConfig.inputCfg.samplingRate); } LE_setConfig(pContext, &pContext->mConfig); @@ -215,8 +209,7 @@ int LELib_Create(const effect_uuid_t *uuid, pContext->mItfe = &gLEInterface; pContext->mState = LOUDNESS_ENHANCER_STATE_UNINITIALIZED; - pContext->mCompressorL = NULL; - pContext->mCompressorR = NULL; + pContext->mCompressor = NULL; ret = LE_init(pContext); if (ret < 0) { ALOGW("LELib_Create() init failed"); @@ -242,13 +235,9 @@ int LELib_Release(effect_handle_t handle) { return -EINVAL; } pContext->mState = LOUDNESS_ENHANCER_STATE_UNINITIALIZED; - if (pContext->mCompressorL != NULL) { - delete pContext->mCompressorL; - pContext->mCompressorL = NULL; - } - if (pContext->mCompressorR != NULL) { - delete pContext->mCompressorR; - pContext->mCompressorR = NULL; + if (pContext->mCompressor != NULL) { + delete pContext->mCompressor; + pContext->mCompressor = NULL; } delete pContext; @@ -293,11 +282,14 @@ int LE_process( //ALOGV("LE about to process %d samples", inBuffer->frameCount); uint16_t inIdx; float inputAmp = pow(10, pContext->mTargetGainmB/2000.0f); + float leftSample, rightSample; for (inIdx = 0 ; inIdx < inBuffer->frameCount ; inIdx++) { - inBuffer->s16[2*inIdx] = pContext->mCompressorL->Compress( - inputAmp * (float)inBuffer->s16[2*inIdx]); - inBuffer->s16[2*inIdx +1] = pContext->mCompressorR->Compress( - inputAmp * (float)inBuffer->s16[2*inIdx +1]); + // makeup gain is applied on the input of the compressor + leftSample = inputAmp * (float)inBuffer->s16[2*inIdx]; + rightSample = inputAmp * (float)inBuffer->s16[2*inIdx +1]; + pContext->mCompressor->Compress(&leftSample, &rightSample); + inBuffer->s16[2*inIdx] = (int16_t) leftSample; + inBuffer->s16[2*inIdx +1] = (int16_t) rightSample; } if (inBuffer->raw != outBuffer->raw) { diff --git a/media/libeffects/loudness/dsp/core/dynamic_range_compression-inl.h b/media/libeffects/loudness/dsp/core/dynamic_range_compression-inl.h index fed8c2a..da75ceb 100644 --- a/media/libeffects/loudness/dsp/core/dynamic_range_compression-inl.h +++ b/media/libeffects/loudness/dsp/core/dynamic_range_compression-inl.h @@ -35,7 +35,7 @@ inline void AdaptiveDynamicRangeCompression::set_knee_threshold_via_target_gain( float target_gain) { const float decibel = target_gain_to_knee_threshold_.Interpolate( target_gain); - ALOGE("set_knee_threshold_via_target_gain: decibel =%.3f", decibel); + ALOGV("set_knee_threshold_via_target_gain: decibel =%.3fdB", decibel); set_knee_threshold(decibel); } diff --git a/media/libeffects/loudness/dsp/core/dynamic_range_compression.cpp b/media/libeffects/loudness/dsp/core/dynamic_range_compression.cpp index 2bbd043..7bd068e 100644 --- a/media/libeffects/loudness/dsp/core/dynamic_range_compression.cpp +++ b/media/libeffects/loudness/dsp/core/dynamic_range_compression.cpp @@ -102,5 +102,40 @@ float AdaptiveDynamicRangeCompression::Compress(float x) { return x; } +void AdaptiveDynamicRangeCompression::Compress(float *x1, float *x2) { + // Taking the maximum amplitude of both channels + const float max_abs_x = std::max(std::fabs(*x1), + std::max(std::fabs(*x2), kMinLogAbsValue)); + const float max_abs_x_dB = math::fast_log(max_abs_x); + // Subtract Threshold from log-encoded input to get the amount of overshoot + const float overshoot = max_abs_x_dB - knee_threshold_; + // Hard half-wave rectifier + const float rect = std::max(overshoot, 0.0f); + // Multiply rectified overshoot with slope + const float cv = rect * slope_; + const float prev_state = state_; + if (cv <= state_) { + state_ = alpha_attack_ * state_ + (1.0f - alpha_attack_) * cv; + } else { + state_ = alpha_release_ * state_ + (1.0f - alpha_release_) * cv; + } + compressor_gain_ *= + math::ExpApproximationViaTaylorExpansionOrder5(state_ - prev_state); + *x1 *= compressor_gain_; + if (*x1 > kFixedPointLimit) { + *x1 = kFixedPointLimit; + } + if (*x1 < -kFixedPointLimit) { + *x1 = -kFixedPointLimit; + } + *x2 *= compressor_gain_; + if (*x2 > kFixedPointLimit) { + *x2 = kFixedPointLimit; + } + if (*x2 < -kFixedPointLimit) { + *x2 = -kFixedPointLimit; + } +} + } // namespace le_fx diff --git a/media/libeffects/loudness/dsp/core/dynamic_range_compression.h b/media/libeffects/loudness/dsp/core/dynamic_range_compression.h index 4c015df..2821a78 100644 --- a/media/libeffects/loudness/dsp/core/dynamic_range_compression.h +++ b/media/libeffects/loudness/dsp/core/dynamic_range_compression.h @@ -55,6 +55,9 @@ class AdaptiveDynamicRangeCompression { // log(.) and exp(.). float Compress(float x); + // Stereo channel version of the compressor + void Compress(float *x1, float *x2); + // This version is slower than Compress(.) but faster than CompressSlow(.) float CompressNormalSpeed(float x); -- cgit v1.1 From 5b8ce24b849f6cd5629b4ba508f7c78d6227d250 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Fri, 27 Sep 2013 14:50:48 -0700 Subject: Revert "Effect Offload Proxy for effects offload" This reverts commit 60c60df7db278d2fa5c90b0fa14f99a61d50272b. Change-Id: Iafba9e02a9f3bfde6248d802e96c4e649686a87d --- media/libeffects/data/audio_effects.conf | 2 +- media/libeffects/proxy/Android.mk | 34 ---- media/libeffects/proxy/EffectProxy.cpp | 338 ------------------------------- media/libeffects/proxy/EffectProxy.h | 80 -------- 4 files changed, 1 insertion(+), 453 deletions(-) delete mode 100644 media/libeffects/proxy/Android.mk delete mode 100644 media/libeffects/proxy/EffectProxy.cpp delete mode 100644 media/libeffects/proxy/EffectProxy.h (limited to 'media/libeffects') diff --git a/media/libeffects/data/audio_effects.conf b/media/libeffects/data/audio_effects.conf index c3c4b67..f1c5f5b 100644 --- a/media/libeffects/data/audio_effects.conf +++ b/media/libeffects/data/audio_effects.conf @@ -10,7 +10,7 @@ libraries { # the HW and SW effects #proxy { - #path /system/lib/soundfx/libeffectproxy.so + #path /system/lib/soundfx/libProxy.so #} # This is the SW implementation library of the effect diff --git a/media/libeffects/proxy/Android.mk b/media/libeffects/proxy/Android.mk deleted file mode 100644 index 01b3be1..0000000 --- a/media/libeffects/proxy/Android.mk +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright 2013 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) -LOCAL_MODULE:= libeffectproxy -LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/soundfx -LOCAL_MODULE_TAGS := optional - - -LOCAL_SRC_FILES := \ - EffectProxy.cpp - -LOCAL_CFLAGS+= -fvisibility=hidden - -LOCAL_SHARED_LIBRARIES := liblog libcutils libutils libdl libeffects - -LOCAL_C_INCLUDES := \ - system/media/audio_effects/include \ - bionic/libc/include - -include $(BUILD_SHARED_LIBRARY) - diff --git a/media/libeffects/proxy/EffectProxy.cpp b/media/libeffects/proxy/EffectProxy.cpp deleted file mode 100644 index b3304b7..0000000 --- a/media/libeffects/proxy/EffectProxy.cpp +++ /dev/null @@ -1,338 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "EffectProxy" -//#define LOG_NDEBUG 0 - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace android { -// This is a dummy proxy descriptor just to return to Factory during the initial -// GetDescriptor call. Later in the factory, it is replaced with the -// SW sub effect descriptor -const effect_descriptor_t gProxyDescriptor = { - EFFECT_UUID_INITIALIZER, // type - EFFECT_UUID_INITIALIZER, // uuid - EFFECT_CONTROL_API_VERSION, //version of effect control API - (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_LAST | - EFFECT_FLAG_VOLUME_CTRL), // effect capability flags - 0, // CPU load - 1, // Data memory - "Proxy", //effect name - "AOSP", //implementor name -}; - - -static const effect_descriptor_t *const gDescriptors[] = -{ - &gProxyDescriptor, -}; - - -int EffectProxyCreate(const effect_uuid_t *uuid, - int32_t sessionId, - int32_t ioId, - effect_handle_t *pHandle) { - - effect_descriptor_t* desc; - EffectContext* pContext; - if (pHandle == NULL || uuid == NULL) { - ALOGE("EffectProxyCreate() called with NULL pointer"); - return -EINVAL; - } - ALOGV("EffectProxyCreate start.."); - pContext = new EffectContext; - pContext->sessionId = sessionId; - pContext->ioId = ioId; - pContext->uuid = *uuid; - pContext->common_itfe = &gEffectInterface; - - // The sub effects will be created in effect_command when the first command - // for the effect is received - pContext->eHandle[SUB_FX_HOST] = pContext->eHandle[SUB_FX_OFFLOAD] = NULL; - - // Get the HW and SW sub effect descriptors from the effects factory - desc = new effect_descriptor_t[SUB_FX_COUNT]; - pContext->desc = new effect_descriptor_t[SUB_FX_COUNT]; - int retValue = EffectGetSubEffects(uuid, desc, - sizeof(effect_descriptor_t) * SUB_FX_COUNT); - // EffectGetSubEffects returns the number of sub-effects copied. - if (retValue != SUB_FX_COUNT) { - ALOGE("EffectCreate() could not get the sub effects"); - delete desc; - delete pContext->desc; - return -EINVAL; - } - // Check which is the HW descriptor and copy the descriptors - // to the Context desc array - // Also check if there is only one HW and one SW descriptor. - // HW descriptor alone has the HW_TUNNEL flag. - if ((desc[0].flags & EFFECT_FLAG_HW_ACC_TUNNEL) && - !(desc[1].flags & EFFECT_FLAG_HW_ACC_TUNNEL)) { - pContext->desc[SUB_FX_OFFLOAD] = desc[0]; - pContext->desc[SUB_FX_HOST] = desc[1]; - } - else if ((desc[1].flags & EFFECT_FLAG_HW_ACC_TUNNEL) && - !(desc[0].flags & EFFECT_FLAG_HW_ACC_TUNNEL)) { - pContext->desc[SUB_FX_HOST] = desc[0]; - pContext->desc[SUB_FX_OFFLOAD] = desc[1]; - } - delete desc; -#if (LOG_NDEBUG == 0) - effect_uuid_t uuid_print = pContext->desc[SUB_FX_HOST].uuid; - ALOGV("EffectCreate() UUID of HOST: %08X-%04X-%04X-%04X-%02X%02X%02X%02X" - "%02X%02X\n",uuid_print.timeLow, uuid_print.timeMid, - uuid_print.timeHiAndVersion, uuid_print.clockSeq, uuid_print.node[0], - uuid_print.node[1], uuid_print.node[2], uuid_print.node[3], - uuid_print.node[4], uuid_print.node[5]); - ALOGV("EffectCreate() UUID of OFFLOAD: %08X-%04X-%04X-%04X-%02X%02X%02X%02X" - "%02X%02X\n", uuid_print.timeLow, uuid_print.timeMid, - uuid_print.timeHiAndVersion, uuid_print.clockSeq, uuid_print.node[0], - uuid_print.node[1], uuid_print.node[2], uuid_print.node[3], - uuid_print.node[4], uuid_print.node[5]); -#endif - - pContext->replySize = PROXY_REPLY_SIZE_DEFAULT; - pContext->replyData = (char *)malloc(PROXY_REPLY_SIZE_DEFAULT); - - *pHandle = (effect_handle_t)pContext; - ALOGV("EffectCreate end"); - return 0; -} //end EffectProxyCreate - -int EffectProxyRelease(effect_handle_t handle) { - EffectContext * pContext = (EffectContext *)handle; - if (pContext == NULL) { - ALOGV("ERROR : EffectRelease called with NULL pointer"); - return -EINVAL; - } - ALOGV("EffectRelease"); - delete pContext->desc; - free(pContext->replyData); - - if (pContext->eHandle[SUB_FX_HOST]) - EffectRelease(pContext->eHandle[SUB_FX_HOST]); - if (pContext->eHandle[SUB_FX_OFFLOAD]) - EffectRelease(pContext->eHandle[SUB_FX_OFFLOAD]); - delete pContext; - pContext = NULL; - return 0; -} /*end EffectProxyRelease */ - -int EffectProxyGetDescriptor(const effect_uuid_t *uuid, - effect_descriptor_t *pDescriptor) { - const effect_descriptor_t *desc = NULL; - - if (pDescriptor == NULL || uuid == NULL) { - ALOGV("EffectGetDescriptor() called with NULL pointer"); - return -EINVAL; - } - desc = &gProxyDescriptor; - *pDescriptor = *desc; - return 0; -} /* end EffectProxyGetDescriptor */ - -/* Effect Control Interface Implementation: Process */ -int Effect_process(effect_handle_t self, - audio_buffer_t *inBuffer, - audio_buffer_t *outBuffer) { - - EffectContext *pContext = (EffectContext *) self; - int ret = 0; - if (pContext != NULL) { - int index = pContext->index; - // if the index refers to HW , do not do anything. Just return. - if (index == SUB_FX_HOST) { - ret = (*pContext->eHandle[index])->process(pContext->eHandle[index], - inBuffer, outBuffer); - } - } - return ret; -} /* end Effect_process */ - -/* Effect Control Interface Implementation: Command */ -int Effect_command(effect_handle_t self, - uint32_t cmdCode, - uint32_t cmdSize, - void *pCmdData, - uint32_t *replySize, - void *pReplyData) { - - EffectContext *pContext = (EffectContext *) self; - int status = 0; - if (pContext == NULL) { - ALOGV("Effect_command() Proxy context is NULL"); - return -EINVAL; - } - if (pContext->eHandle[SUB_FX_HOST] == NULL) { - ALOGV("Effect_command() Calling HOST EffectCreate"); - status = EffectCreate(&pContext->desc[SUB_FX_HOST].uuid, - pContext->sessionId, pContext->ioId, - &(pContext->eHandle[SUB_FX_HOST])); - if (status != NO_ERROR || (pContext->eHandle[SUB_FX_HOST] == NULL)) { - ALOGV("Effect_command() Error creating SW sub effect"); - return status; - } - } - if (pContext->eHandle[SUB_FX_OFFLOAD] == NULL) { - ALOGV("Effect_command() Calling OFFLOAD EffectCreate"); - status = EffectCreate(&pContext->desc[SUB_FX_OFFLOAD].uuid, - pContext->sessionId, pContext->ioId, - &(pContext->eHandle[SUB_FX_OFFLOAD])); - if (status != NO_ERROR || (pContext->eHandle[SUB_FX_OFFLOAD] == NULL)) { - ALOGV("Effect_command() Error creating HW effect"); - // Do not return error here as SW effect is created - // Return error if the CMD_OFFLOAD sends the index as OFFLOAD - } - pContext->index = SUB_FX_HOST; - } - // EFFECT_CMD_OFFLOAD used to (1) send whether the thread is offload or not - // (2) Send the ioHandle of the effectThread when the effect - // is moved from one type of thread to another. - // pCmdData points to a memory holding effect_offload_param_t structure - if (cmdCode == EFFECT_CMD_OFFLOAD) { - ALOGV("Effect_command() cmdCode = EFFECT_CMD_OFFLOAD"); - if (cmdSize == 0 || pCmdData == NULL) { - ALOGV("effectsOffload: Effect_command: CMD_OFFLOAD has no data"); - *(int*)pReplyData = FAILED_TRANSACTION; - return FAILED_TRANSACTION; - } - effect_offload_param_t* offloadParam = (effect_offload_param_t*)pCmdData; - // Assign the effect context index based on isOffload field of the structure - pContext->index = offloadParam->isOffload ? SUB_FX_OFFLOAD : SUB_FX_HOST; - // if the index is HW and the HW effect is unavailable, return error - // and reset the index to SW - if (pContext->eHandle[pContext->index] == NULL) { - ALOGV("Effect_command()CMD_OFFLOAD sub effect unavailable"); - *(int*)pReplyData = FAILED_TRANSACTION; - return FAILED_TRANSACTION; - } - pContext->ioId = offloadParam->ioHandle; - ALOGV("Effect_command()CMD_OFFLOAD index:%d io %d", pContext->index, pContext->ioId); - // Update the DSP wrapper with the new ioHandle. - // Pass the OFFLOAD command to the wrapper. - // The DSP wrapper needs to handle this CMD - if (pContext->eHandle[SUB_FX_OFFLOAD]) - status = (*pContext->eHandle[SUB_FX_OFFLOAD])->command( - pContext->eHandle[SUB_FX_OFFLOAD], cmdCode, cmdSize, - pCmdData, replySize, pReplyData); - return status; - } - - int index = pContext->index; - if (index != SUB_FX_HOST && index != SUB_FX_OFFLOAD) { - ALOGV("Effect_command: effect index is neither offload nor host"); - return -EINVAL; - } - - // Getter commands are only sent to the active sub effect. - int *subStatus[SUB_FX_COUNT]; - uint32_t *subReplySize[SUB_FX_COUNT]; - void *subReplyData[SUB_FX_COUNT]; - uint32_t tmpSize; - int tmpStatus; - - // grow temp reply buffer if needed - if (replySize != NULL) { - tmpSize = pContext->replySize; - while (tmpSize < *replySize && tmpSize < PROXY_REPLY_SIZE_MAX) { - tmpSize *= 2; - } - if (tmpSize > pContext->replySize) { - ALOGV("Effect_command grow reply buf to %d", tmpSize); - pContext->replyData = (char *)realloc(pContext->replyData, tmpSize); - pContext->replySize = tmpSize; - } - if (tmpSize > *replySize) { - tmpSize = *replySize; - } - } else { - tmpSize = 0; - } - // tmpSize is now the actual reply size for the non active sub effect - - // Send command to sub effects. The command is sent to all sub effects so that their internal - // state is kept in sync. - // Only the reply from the active sub effect is returned to the caller. The reply from the - // other sub effect is lost in pContext->replyData - for (int i = 0; i < SUB_FX_COUNT; i++) { - if (pContext->eHandle[i] == NULL) { - continue; - } - if (i == index) { - subStatus[i] = &status; - subReplySize[i] = replySize; - subReplyData[i] = pReplyData; - } else { - subStatus[i] = &tmpStatus; - subReplySize[i] = replySize == NULL ? NULL : &tmpSize; - subReplyData[i] = pReplyData == NULL ? NULL : pContext->replyData; - } - *subStatus[i] = (*pContext->eHandle[i])->command( - pContext->eHandle[i], cmdCode, cmdSize, - pCmdData, subReplySize[i], subReplyData[i]); - } - - return status; -} /* end Effect_command */ - - -/* Effect Control Interface Implementation: get_descriptor */ -int Effect_getDescriptor(effect_handle_t self, - effect_descriptor_t *pDescriptor) { - - EffectContext * pContext = (EffectContext *) self; - const effect_descriptor_t *desc; - - ALOGV("Effect_getDescriptor"); - if (pContext == NULL || pDescriptor == NULL) { - ALOGV("Effect_getDescriptor() invalid param"); - return -EINVAL; - } - if (pContext->desc == NULL) { - ALOGV("Effect_getDescriptor() could not get descriptor"); - return -EINVAL; - } - desc = &pContext->desc[SUB_FX_HOST]; - *pDescriptor = *desc; - pDescriptor->uuid = pContext->uuid; // Replace the uuid with the Proxy UUID - // Also set/clear the EFFECT_FLAG_OFFLOAD_SUPPORTED flag based on the sub effects availability - if (pContext->eHandle[SUB_FX_OFFLOAD] != NULL) - pDescriptor->flags |= EFFECT_FLAG_OFFLOAD_SUPPORTED; - else - pDescriptor->flags &= ~EFFECT_FLAG_OFFLOAD_SUPPORTED; - return 0; -} /* end Effect_getDescriptor */ - -} // namespace android - -__attribute__ ((visibility ("default"))) -audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = { - tag : AUDIO_EFFECT_LIBRARY_TAG, - version : EFFECT_LIBRARY_API_VERSION, - name : "Effect Proxy", - implementor : "AOSP", - create_effect : android::EffectProxyCreate, - release_effect : android::EffectProxyRelease, - get_descriptor : android::EffectProxyGetDescriptor, -}; diff --git a/media/libeffects/proxy/EffectProxy.h b/media/libeffects/proxy/EffectProxy.h deleted file mode 100644 index acbe17e..0000000 --- a/media/libeffects/proxy/EffectProxy.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -namespace android { -enum { - SUB_FX_HOST, // Index of HOST in the descriptor and handle arrays - // of the Proxy context - SUB_FX_OFFLOAD, // Index of OFFLOAD in the descriptor and handle arrays - // of the Proxy context - SUB_FX_COUNT // The number of sub effects for a Proxy(1 HW, 1 SW) -}; -#if __cplusplus -extern "C" { -#endif - -int EffectProxyCreate(const effect_uuid_t *uuid, - int32_t sessionId, - int32_t ioId, - effect_handle_t *pHandle); -int EffectProxyRelease(effect_handle_t handle); -int EffectProxyGetDescriptor(const effect_uuid_t *uuid, - effect_descriptor_t *pDescriptor); -/* Effect Control Interface Implementation: Process */ -int Effect_process(effect_handle_t self, - audio_buffer_t *inBuffer, - audio_buffer_t *outBuffer); - -/* Effect Control Interface Implementation: Command */ -int Effect_command(effect_handle_t self, - uint32_t cmdCode, - uint32_t cmdSize, - void *pCmdData, - uint32_t *replySize, - void *pReplyData); -int Effect_getDescriptor(effect_handle_t self, - effect_descriptor_t *pDescriptor); - -const struct effect_interface_s gEffectInterface = { - Effect_process, - Effect_command, - Effect_getDescriptor, - NULL, -}; - -#define PROXY_REPLY_SIZE_MAX (64 * 1024) // must be power of two -#define PROXY_REPLY_SIZE_DEFAULT 32 // must be power of two - -struct EffectContext { - const struct effect_interface_s *common_itfe; // Holds the itfe of the Proxy - effect_descriptor_t* desc; // Points to the sub effect descriptors - effect_handle_t eHandle[SUB_FX_COUNT]; // The effect handles of the sub effects - int index; // The index that is currently active - HOST or OFFLOAD - int32_t sessionId; // The sessiond in which the effect is created. - // Stored in context to pass on to sub effect creation - int32_t ioId; // The ioId in which the effect is created. - // Stored in context to pass on to sub effect creation - effect_uuid_t uuid; // UUID of the Proxy - char* replyData; // temporary buffer for non active sub effect command reply - uint32_t replySize; // current size of temporary reply buffer -}; - -#if __cplusplus -} // extern "C" -#endif -} //namespace android -- cgit v1.1 From 83f400056ac913250f0926326ff78697c68d18a1 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Fri, 27 Sep 2013 14:53:24 -0700 Subject: Revert "Effects Factory changes for effects offload" This reverts commit 284c17e73bbff51cb5b1adcee98386d47733757a. Change-Id: I31db21e1ad4758b21356bfe4c4c64f15b2da8737 --- media/libeffects/data/audio_effects.conf | 39 ------ media/libeffects/factory/EffectsFactory.c | 218 +----------------------------- media/libeffects/factory/EffectsFactory.h | 19 --- 3 files changed, 2 insertions(+), 274 deletions(-) (limited to 'media/libeffects') diff --git a/media/libeffects/data/audio_effects.conf b/media/libeffects/data/audio_effects.conf index f1c5f5b..0c3c687 100644 --- a/media/libeffects/data/audio_effects.conf +++ b/media/libeffects/data/audio_effects.conf @@ -6,23 +6,6 @@ # } # } libraries { -# This is a proxy library that will be an abstraction for -# the HW and SW effects - - #proxy { - #path /system/lib/soundfx/libProxy.so - #} - -# This is the SW implementation library of the effect - #libSW { - #path /system/lib/soundfx/libswwrapper.so - #} - -# This is the HW implementation library for the effect - #libHW { - #path /system/lib/soundfx/libhwwrapper.so - #} - bundle { path /system/lib/soundfx/libbundlewrapper.so } @@ -63,28 +46,6 @@ libraries { # } effects { - -# additions for the proxy implementation -# Proxy implementation - #effectname { - #library proxy - #uuid xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx - - # SW implemetation of the effect. Added as a node under the proxy to - # indicate this as a sub effect. - #libsw { - #library libSW - #uuid yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy - #} End of SW effect - - # HW implementation of the effect. Added as a node under the proxy to - # indicate this as a sub effect. - #libhw { - #library libHW - #uuid zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz - #}End of HW effect - #} End of effect proxy - bassboost { library bundle uuid 8631f300-72e2-11df-b57e-0002a5d5c51b diff --git a/media/libeffects/factory/EffectsFactory.c b/media/libeffects/factory/EffectsFactory.c index f8d6041..f158929 100644 --- a/media/libeffects/factory/EffectsFactory.c +++ b/media/libeffects/factory/EffectsFactory.c @@ -28,9 +28,6 @@ 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 -// list of effect_descriptor and list of sub effects : all currently loaded -// It does not contain effects without sub effects. -static list_sub_elem_t *gSubEffectList; 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 @@ -53,8 +50,6 @@ static int loadLibraries(cnode *root); static int loadLibrary(cnode *root, const char *name); static int loadEffects(cnode *root); static int loadEffect(cnode *node); -// To get and add the effect pointed by the passed node to the gSubEffectList -static int addSubEffect(cnode *root); static lib_entry_t *getLibrary(const char *path); static void resetEffectEnumeration(); static uint32_t updateNumEffects(); @@ -62,10 +57,6 @@ static int findEffect(const effect_uuid_t *type, const effect_uuid_t *uuid, lib_entry_t **lib, effect_descriptor_t **desc); -// To search a subeffect in the gSubEffectList -int findSubEffect(const effect_uuid_t *uuid, - lib_entry_t **lib, - effect_descriptor_t **desc); static void dumpEffectDescriptor(effect_descriptor_t *desc, char *str, size_t len); static int stringToUuid(const char *str, effect_uuid_t *uuid); static int uuidToString(const effect_uuid_t *uuid, char *str, size_t maxLen); @@ -296,12 +287,7 @@ int EffectCreate(const effect_uuid_t *uuid, int32_t sessionId, int32_t ioId, eff ret = findEffect(NULL, uuid, &l, &d); if (ret < 0){ - // Sub effects are not associated with the library->effects, - // so, findEffect will fail. Search for the effect in gSubEffectList. - ret = findSubEffect(uuid, &l, &d); - if (ret < 0 ) { - goto exit; - } + goto exit; } // create effect in library @@ -368,27 +354,21 @@ int EffectRelease(effect_handle_t handle) } if (e1 == NULL) { ret = -ENOENT; - pthread_mutex_unlock(&gLibLock); goto exit; } // release effect in library if (fx->lib == NULL) { ALOGW("EffectRelease() fx %p library already unloaded", handle); - pthread_mutex_unlock(&gLibLock); } else { pthread_mutex_lock(&fx->lib->lock); - // Releasing the gLibLock here as the list access is over as the - // effect is removed from the list. - // If the gLibLock is not released, we will have a deadlock situation - // since we call the sub effect release inside the EffectRelease of Proxy - pthread_mutex_unlock(&gLibLock); fx->lib->desc->release_effect(fx->subItfe); pthread_mutex_unlock(&fx->lib->lock); } free(fx); exit: + pthread_mutex_unlock(&gLibLock); return ret; } @@ -400,49 +380,6 @@ int EffectIsNullUuid(const effect_uuid_t *uuid) return 1; } -// Function to get the sub effect descriptors of the effect whose uuid -// is pointed by the first argument. It searches the gSubEffectList for the -// matching uuid and then copies the corresponding sub effect descriptors -// to the inout param -int EffectGetSubEffects(const effect_uuid_t *uuid, - effect_descriptor_t *pDescriptors, size_t size) -{ - ALOGV("EffectGetSubEffects() UUID: %08X-%04X-%04X-%04X-%02X%02X%02X%02X%02X" - "%02X\n",uuid->timeLow, uuid->timeMid, uuid->timeHiAndVersion, - uuid->clockSeq, uuid->node[0], uuid->node[1],uuid->node[2], - uuid->node[3],uuid->node[4],uuid->node[5]); - - // Check if the size of the desc buffer is large enough for 2 subeffects - if ((uuid == NULL) || (pDescriptors == NULL) || - (size < 2*sizeof(effect_descriptor_t))) { - ALOGW("NULL pointer or insufficient memory. Cannot query subeffects"); - return -EINVAL; - } - int ret = init(); - if (ret < 0) - return ret; - list_sub_elem_t *e = gSubEffectList; - sub_effect_entry_t *subeffect; - effect_descriptor_t *d; - int count = 0; - while (e != NULL) { - d = (effect_descriptor_t*)e->object; - if (memcmp(uuid, &d->uuid, sizeof(effect_uuid_t)) == 0) { - ALOGV("EffectGetSubEffects: effect found in the list"); - list_elem_t *subefx = e->sub_elem; - while (subefx != NULL) { - subeffect = (sub_effect_entry_t*)subefx->object; - d = (effect_descriptor_t*)(subeffect->object); - pDescriptors[count++] = *d; - subefx = subefx->next; - } - ALOGV("EffectGetSubEffects end - copied the sub effect descriptors"); - return count; - } - e = e->next; - } - return -ENOENT; -} ///////////////////////////////////////////////// // Local functions ///////////////////////////////////////////////// @@ -566,65 +503,6 @@ error: return -EINVAL; } -// This will find the library and UUID tags of the sub effect pointed by the -// node, gets the effect descriptor and lib_entry_t and adds the subeffect - -// sub_entry_t to the gSubEffectList -int addSubEffect(cnode *root) -{ - ALOGV("addSubEffect"); - cnode *node; - effect_uuid_t uuid; - effect_descriptor_t *d; - lib_entry_t *l; - list_elem_t *e; - node = config_find(root, LIBRARY_TAG); - if (node == NULL) { - return -EINVAL; - } - l = getLibrary(node->value); - if (l == NULL) { - ALOGW("addSubEffect() could not get library %s", node->value); - return -EINVAL; - } - node = config_find(root, UUID_TAG); - if (node == NULL) { - return -EINVAL; - } - if (stringToUuid(node->value, &uuid) != 0) { - ALOGW("addSubEffect() invalid uuid %s", node->value); - return -EINVAL; - } - d = malloc(sizeof(effect_descriptor_t)); - if (l->desc->get_descriptor(&uuid, d) != 0) { - char s[40]; - uuidToString(&uuid, s, 40); - ALOGW("Error querying effect %s on lib %s", s, l->name); - free(d); - return -EINVAL; - } -#if (LOG_NDEBUG==0) - char s[256]; - dumpEffectDescriptor(d, s, 256); - ALOGV("addSubEffect() read descriptor %p:%s",d, s); -#endif - if (EFFECT_API_VERSION_MAJOR(d->apiVersion) != - EFFECT_API_VERSION_MAJOR(EFFECT_CONTROL_API_VERSION)) { - ALOGW("Bad API version %08x on lib %s", d->apiVersion, l->name); - free(d); - return -EINVAL; - } - sub_effect_entry_t *sub_effect = malloc(sizeof(sub_effect_entry_t)); - sub_effect->object = d; - // lib_entry_t is stored since the sub effects are not linked to the library - sub_effect->lib = l; - e = malloc(sizeof(list_elem_t)); - e->object = sub_effect; - e->next = gSubEffectList->sub_elem; - gSubEffectList->sub_elem = e; - ALOGV("addSubEffect end"); - return 0; -} - int loadEffects(cnode *root) { cnode *node; @@ -693,101 +571,9 @@ int loadEffect(cnode *root) e->next = l->effects; l->effects = e; - // After the UUID node in the config_tree, if node->next is valid, - // that would be sub effect node. - // Find the sub effects and add them to the gSubEffectList - node = node->next; - int count = 2; - bool hwSubefx = false, swSubefx = false; - list_sub_elem_t *sube = NULL; - if (node != NULL) { - ALOGV("Adding the effect to gEffectSubList as there are sub effects"); - sube = malloc(sizeof(list_sub_elem_t)); - sube->object = d; - sube->sub_elem = NULL; - sube->next = gSubEffectList; - gSubEffectList = sube; - } - while (node != NULL && count) { - if (addSubEffect(node)) { - ALOGW("loadEffect() could not add subEffect %s", node->value); - // Change the gSubEffectList to point to older list; - gSubEffectList = sube->next; - free(sube->sub_elem);// Free an already added sub effect - sube->sub_elem = NULL; - free(sube); - return -ENOENT; - } - sub_effect_entry_t *subEntry = (sub_effect_entry_t*)gSubEffectList->sub_elem->object; - effect_descriptor_t *subEffectDesc = (effect_descriptor_t*)(subEntry->object); - // Since we return a dummy descriptor for the proxy during - // get_descriptor call,we replace it with the correspoding - // sw effect descriptor, but with Proxy UUID - // check for Sw desc - if (!((subEffectDesc->flags & EFFECT_FLAG_HW_ACC_MASK) == - EFFECT_FLAG_HW_ACC_TUNNEL)) { - swSubefx = true; - *d = *subEffectDesc; - d->uuid = uuid; - ALOGV("loadEffect() Changed the Proxy desc"); - } else - hwSubefx = true; - count--; - node = node->next; - } - // 1 HW and 1 SW sub effect found. Set the offload flag in the Proxy desc - if (hwSubefx && swSubefx) { - d->flags |= EFFECT_FLAG_OFFLOAD_SUPPORTED; - } return 0; } -// Searches the sub effect matching to the specified uuid -// in the gSubEffectList. It gets the lib_entry_t for -// the matched sub_effect . Used in EffectCreate of sub effects -int findSubEffect(const effect_uuid_t *uuid, - lib_entry_t **lib, - effect_descriptor_t **desc) -{ - list_sub_elem_t *e = gSubEffectList; - list_elem_t *subefx; - sub_effect_entry_t *effect; - lib_entry_t *l = NULL; - effect_descriptor_t *d = NULL; - int found = 0; - int ret = 0; - - if (uuid == NULL) - return -EINVAL; - - while (e != NULL && !found) { - subefx = (list_elem_t*)(e->sub_elem); - while (subefx != NULL) { - effect = (sub_effect_entry_t*)subefx->object; - l = (lib_entry_t *)effect->lib; - d = (effect_descriptor_t *)effect->object; - if (memcmp(&d->uuid, uuid, sizeof(effect_uuid_t)) == 0) { - ALOGV("uuid matched"); - found = 1; - break; - } - subefx = subefx->next; - } - e = e->next; - } - if (!found) { - ALOGV("findSubEffect() effect not found"); - ret = -ENOENT; - } else { - ALOGV("findSubEffect() found effect: %s in lib %s", d->name, l->name); - *lib = l; - if (desc != NULL) { - *desc = d; - } - } - return ret; -} - lib_entry_t *getLibrary(const char *name) { list_elem_t *e; diff --git a/media/libeffects/factory/EffectsFactory.h b/media/libeffects/factory/EffectsFactory.h index 147ff18..c1d4319 100644 --- a/media/libeffects/factory/EffectsFactory.h +++ b/media/libeffects/factory/EffectsFactory.h @@ -32,15 +32,6 @@ typedef struct list_elem_s { struct list_elem_s *next; } list_elem_t; -// Structure used for storing effects with their sub effects. -// Used in creating gSubEffectList. Here, -// object holds the effect desc and the list sub_elem holds the sub effects -typedef struct list_sub_elem_s { - void *object; - list_elem_t *sub_elem; - struct list_sub_elem_s *next; -} list_sub_elem_t; - typedef struct lib_entry_s { audio_effect_library_t *desc; char *name; @@ -56,16 +47,6 @@ typedef struct effect_entry_s { lib_entry_t *lib; } effect_entry_t; -// Structure used to store the lib entry -// and the descriptor of the sub effects. -// The library entry is to be stored in case of -// sub effects as the sub effects are not linked -// to the library list - gLibraryList. -typedef struct sub_effect_entry_s { - lib_entry_t *lib; - void *object; -} sub_effect_entry_t; - #if __cplusplus } // extern "C" #endif -- cgit v1.1 From 2eab94f7dfd41a65e13aca379a1aed97447f8884 Mon Sep 17 00:00:00 2001 From: jpadmana Date: Tue, 4 Jun 2013 16:08:29 +0530 Subject: Effects Factory changes for effects offload audio_effects.conf - commented changes to illustrate the addition of Proxy and sub effects to the conf file Added an effectFactoryApi - EffectGetSubEffects for querying the sub effect descriptors from the factory. This api is used by the Proxy to get the sub effects Added functions and data structures in factory code for loading the sub effects gSubEffectList - has the Proxies and their corresponding sub effects - addSubEffect() - reads a sub effect node and adds to the gSubEffectList - findSubEffect() - searches through the gSubEffectList to find a SubEffect Bug: 8174034. Change-Id: Id7f6aa67c41db370d32beaf43a979ba4ac925928 Signed-off-by: jpadmana --- media/libeffects/data/audio_effects.conf | 39 ++++++ media/libeffects/factory/EffectsFactory.c | 218 +++++++++++++++++++++++++++++- media/libeffects/factory/EffectsFactory.h | 19 +++ 3 files changed, 274 insertions(+), 2 deletions(-) (limited to 'media/libeffects') diff --git a/media/libeffects/data/audio_effects.conf b/media/libeffects/data/audio_effects.conf index 0c3c687..f1c5f5b 100644 --- a/media/libeffects/data/audio_effects.conf +++ b/media/libeffects/data/audio_effects.conf @@ -6,6 +6,23 @@ # } # } libraries { +# This is a proxy library that will be an abstraction for +# the HW and SW effects + + #proxy { + #path /system/lib/soundfx/libProxy.so + #} + +# This is the SW implementation library of the effect + #libSW { + #path /system/lib/soundfx/libswwrapper.so + #} + +# This is the HW implementation library for the effect + #libHW { + #path /system/lib/soundfx/libhwwrapper.so + #} + bundle { path /system/lib/soundfx/libbundlewrapper.so } @@ -46,6 +63,28 @@ libraries { # } effects { + +# additions for the proxy implementation +# Proxy implementation + #effectname { + #library proxy + #uuid xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + + # SW implemetation of the effect. Added as a node under the proxy to + # indicate this as a sub effect. + #libsw { + #library libSW + #uuid yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy + #} End of SW effect + + # HW implementation of the effect. Added as a node under the proxy to + # indicate this as a sub effect. + #libhw { + #library libHW + #uuid zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz + #}End of HW effect + #} End of effect proxy + bassboost { library bundle uuid 8631f300-72e2-11df-b57e-0002a5d5c51b diff --git a/media/libeffects/factory/EffectsFactory.c b/media/libeffects/factory/EffectsFactory.c index f158929..f8d6041 100644 --- a/media/libeffects/factory/EffectsFactory.c +++ b/media/libeffects/factory/EffectsFactory.c @@ -28,6 +28,9 @@ 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 +// list of effect_descriptor and list of sub effects : all currently loaded +// It does not contain effects without sub effects. +static list_sub_elem_t *gSubEffectList; 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 @@ -50,6 +53,8 @@ static int loadLibraries(cnode *root); static int loadLibrary(cnode *root, const char *name); static int loadEffects(cnode *root); static int loadEffect(cnode *node); +// To get and add the effect pointed by the passed node to the gSubEffectList +static int addSubEffect(cnode *root); static lib_entry_t *getLibrary(const char *path); static void resetEffectEnumeration(); static uint32_t updateNumEffects(); @@ -57,6 +62,10 @@ static int findEffect(const effect_uuid_t *type, const effect_uuid_t *uuid, lib_entry_t **lib, effect_descriptor_t **desc); +// To search a subeffect in the gSubEffectList +int findSubEffect(const effect_uuid_t *uuid, + lib_entry_t **lib, + effect_descriptor_t **desc); static void dumpEffectDescriptor(effect_descriptor_t *desc, char *str, size_t len); static int stringToUuid(const char *str, effect_uuid_t *uuid); static int uuidToString(const effect_uuid_t *uuid, char *str, size_t maxLen); @@ -287,7 +296,12 @@ int EffectCreate(const effect_uuid_t *uuid, int32_t sessionId, int32_t ioId, eff ret = findEffect(NULL, uuid, &l, &d); if (ret < 0){ - goto exit; + // Sub effects are not associated with the library->effects, + // so, findEffect will fail. Search for the effect in gSubEffectList. + ret = findSubEffect(uuid, &l, &d); + if (ret < 0 ) { + goto exit; + } } // create effect in library @@ -354,21 +368,27 @@ int EffectRelease(effect_handle_t handle) } if (e1 == NULL) { ret = -ENOENT; + pthread_mutex_unlock(&gLibLock); goto exit; } // release effect in library if (fx->lib == NULL) { ALOGW("EffectRelease() fx %p library already unloaded", handle); + pthread_mutex_unlock(&gLibLock); } else { pthread_mutex_lock(&fx->lib->lock); + // Releasing the gLibLock here as the list access is over as the + // effect is removed from the list. + // If the gLibLock is not released, we will have a deadlock situation + // since we call the sub effect release inside the EffectRelease of Proxy + pthread_mutex_unlock(&gLibLock); fx->lib->desc->release_effect(fx->subItfe); pthread_mutex_unlock(&fx->lib->lock); } free(fx); exit: - pthread_mutex_unlock(&gLibLock); return ret; } @@ -380,6 +400,49 @@ int EffectIsNullUuid(const effect_uuid_t *uuid) return 1; } +// Function to get the sub effect descriptors of the effect whose uuid +// is pointed by the first argument. It searches the gSubEffectList for the +// matching uuid and then copies the corresponding sub effect descriptors +// to the inout param +int EffectGetSubEffects(const effect_uuid_t *uuid, + effect_descriptor_t *pDescriptors, size_t size) +{ + ALOGV("EffectGetSubEffects() UUID: %08X-%04X-%04X-%04X-%02X%02X%02X%02X%02X" + "%02X\n",uuid->timeLow, uuid->timeMid, uuid->timeHiAndVersion, + uuid->clockSeq, uuid->node[0], uuid->node[1],uuid->node[2], + uuid->node[3],uuid->node[4],uuid->node[5]); + + // Check if the size of the desc buffer is large enough for 2 subeffects + if ((uuid == NULL) || (pDescriptors == NULL) || + (size < 2*sizeof(effect_descriptor_t))) { + ALOGW("NULL pointer or insufficient memory. Cannot query subeffects"); + return -EINVAL; + } + int ret = init(); + if (ret < 0) + return ret; + list_sub_elem_t *e = gSubEffectList; + sub_effect_entry_t *subeffect; + effect_descriptor_t *d; + int count = 0; + while (e != NULL) { + d = (effect_descriptor_t*)e->object; + if (memcmp(uuid, &d->uuid, sizeof(effect_uuid_t)) == 0) { + ALOGV("EffectGetSubEffects: effect found in the list"); + list_elem_t *subefx = e->sub_elem; + while (subefx != NULL) { + subeffect = (sub_effect_entry_t*)subefx->object; + d = (effect_descriptor_t*)(subeffect->object); + pDescriptors[count++] = *d; + subefx = subefx->next; + } + ALOGV("EffectGetSubEffects end - copied the sub effect descriptors"); + return count; + } + e = e->next; + } + return -ENOENT; +} ///////////////////////////////////////////////// // Local functions ///////////////////////////////////////////////// @@ -503,6 +566,65 @@ error: return -EINVAL; } +// This will find the library and UUID tags of the sub effect pointed by the +// node, gets the effect descriptor and lib_entry_t and adds the subeffect - +// sub_entry_t to the gSubEffectList +int addSubEffect(cnode *root) +{ + ALOGV("addSubEffect"); + cnode *node; + effect_uuid_t uuid; + effect_descriptor_t *d; + lib_entry_t *l; + list_elem_t *e; + node = config_find(root, LIBRARY_TAG); + if (node == NULL) { + return -EINVAL; + } + l = getLibrary(node->value); + if (l == NULL) { + ALOGW("addSubEffect() could not get library %s", node->value); + return -EINVAL; + } + node = config_find(root, UUID_TAG); + if (node == NULL) { + return -EINVAL; + } + if (stringToUuid(node->value, &uuid) != 0) { + ALOGW("addSubEffect() invalid uuid %s", node->value); + return -EINVAL; + } + d = malloc(sizeof(effect_descriptor_t)); + if (l->desc->get_descriptor(&uuid, d) != 0) { + char s[40]; + uuidToString(&uuid, s, 40); + ALOGW("Error querying effect %s on lib %s", s, l->name); + free(d); + return -EINVAL; + } +#if (LOG_NDEBUG==0) + char s[256]; + dumpEffectDescriptor(d, s, 256); + ALOGV("addSubEffect() read descriptor %p:%s",d, s); +#endif + if (EFFECT_API_VERSION_MAJOR(d->apiVersion) != + EFFECT_API_VERSION_MAJOR(EFFECT_CONTROL_API_VERSION)) { + ALOGW("Bad API version %08x on lib %s", d->apiVersion, l->name); + free(d); + return -EINVAL; + } + sub_effect_entry_t *sub_effect = malloc(sizeof(sub_effect_entry_t)); + sub_effect->object = d; + // lib_entry_t is stored since the sub effects are not linked to the library + sub_effect->lib = l; + e = malloc(sizeof(list_elem_t)); + e->object = sub_effect; + e->next = gSubEffectList->sub_elem; + gSubEffectList->sub_elem = e; + ALOGV("addSubEffect end"); + return 0; +} + int loadEffects(cnode *root) { cnode *node; @@ -571,9 +693,101 @@ int loadEffect(cnode *root) e->next = l->effects; l->effects = e; + // After the UUID node in the config_tree, if node->next is valid, + // that would be sub effect node. + // Find the sub effects and add them to the gSubEffectList + node = node->next; + int count = 2; + bool hwSubefx = false, swSubefx = false; + list_sub_elem_t *sube = NULL; + if (node != NULL) { + ALOGV("Adding the effect to gEffectSubList as there are sub effects"); + sube = malloc(sizeof(list_sub_elem_t)); + sube->object = d; + sube->sub_elem = NULL; + sube->next = gSubEffectList; + gSubEffectList = sube; + } + while (node != NULL && count) { + if (addSubEffect(node)) { + ALOGW("loadEffect() could not add subEffect %s", node->value); + // Change the gSubEffectList to point to older list; + gSubEffectList = sube->next; + free(sube->sub_elem);// Free an already added sub effect + sube->sub_elem = NULL; + free(sube); + return -ENOENT; + } + sub_effect_entry_t *subEntry = (sub_effect_entry_t*)gSubEffectList->sub_elem->object; + effect_descriptor_t *subEffectDesc = (effect_descriptor_t*)(subEntry->object); + // Since we return a dummy descriptor for the proxy during + // get_descriptor call,we replace it with the correspoding + // sw effect descriptor, but with Proxy UUID + // check for Sw desc + if (!((subEffectDesc->flags & EFFECT_FLAG_HW_ACC_MASK) == + EFFECT_FLAG_HW_ACC_TUNNEL)) { + swSubefx = true; + *d = *subEffectDesc; + d->uuid = uuid; + ALOGV("loadEffect() Changed the Proxy desc"); + } else + hwSubefx = true; + count--; + node = node->next; + } + // 1 HW and 1 SW sub effect found. Set the offload flag in the Proxy desc + if (hwSubefx && swSubefx) { + d->flags |= EFFECT_FLAG_OFFLOAD_SUPPORTED; + } return 0; } +// Searches the sub effect matching to the specified uuid +// in the gSubEffectList. It gets the lib_entry_t for +// the matched sub_effect . Used in EffectCreate of sub effects +int findSubEffect(const effect_uuid_t *uuid, + lib_entry_t **lib, + effect_descriptor_t **desc) +{ + list_sub_elem_t *e = gSubEffectList; + list_elem_t *subefx; + sub_effect_entry_t *effect; + lib_entry_t *l = NULL; + effect_descriptor_t *d = NULL; + int found = 0; + int ret = 0; + + if (uuid == NULL) + return -EINVAL; + + while (e != NULL && !found) { + subefx = (list_elem_t*)(e->sub_elem); + while (subefx != NULL) { + effect = (sub_effect_entry_t*)subefx->object; + l = (lib_entry_t *)effect->lib; + d = (effect_descriptor_t *)effect->object; + if (memcmp(&d->uuid, uuid, sizeof(effect_uuid_t)) == 0) { + ALOGV("uuid matched"); + found = 1; + break; + } + subefx = subefx->next; + } + e = e->next; + } + if (!found) { + ALOGV("findSubEffect() effect not found"); + ret = -ENOENT; + } else { + ALOGV("findSubEffect() found effect: %s in lib %s", d->name, l->name); + *lib = l; + if (desc != NULL) { + *desc = d; + } + } + return ret; +} + lib_entry_t *getLibrary(const char *name) { list_elem_t *e; diff --git a/media/libeffects/factory/EffectsFactory.h b/media/libeffects/factory/EffectsFactory.h index c1d4319..147ff18 100644 --- a/media/libeffects/factory/EffectsFactory.h +++ b/media/libeffects/factory/EffectsFactory.h @@ -32,6 +32,15 @@ typedef struct list_elem_s { struct list_elem_s *next; } list_elem_t; +// Structure used for storing effects with their sub effects. +// Used in creating gSubEffectList. Here, +// object holds the effect desc and the list sub_elem holds the sub effects +typedef struct list_sub_elem_s { + void *object; + list_elem_t *sub_elem; + struct list_sub_elem_s *next; +} list_sub_elem_t; + typedef struct lib_entry_s { audio_effect_library_t *desc; char *name; @@ -47,6 +56,16 @@ typedef struct effect_entry_s { lib_entry_t *lib; } effect_entry_t; +// Structure used to store the lib entry +// and the descriptor of the sub effects. +// The library entry is to be stored in case of +// sub effects as the sub effects are not linked +// to the library list - gLibraryList. +typedef struct sub_effect_entry_s { + lib_entry_t *lib; + void *object; +} sub_effect_entry_t; + #if __cplusplus } // extern "C" #endif -- cgit v1.1 From faca05e96744dfaa2f352e3dbb29eead4e55cfa0 Mon Sep 17 00:00:00 2001 From: jpadmana Date: Tue, 4 Jun 2013 16:03:29 +0530 Subject: Effect Offload Proxy for effects offload Effect Proxy abstracts the sub effects to the upper layers. It has the following functionalities: - creation and release of sub effects - routing the effect commands and process to the appropriate sub effect Bug: 8174034. Change-Id: Iec34b61104f0bbec4ef67c62f0710a5536dc325b Signed-off-by: jpadmana --- media/libeffects/data/audio_effects.conf | 2 +- media/libeffects/proxy/Android.mk | 34 ++++ media/libeffects/proxy/EffectProxy.cpp | 298 +++++++++++++++++++++++++++++++ media/libeffects/proxy/EffectProxy.h | 75 ++++++++ 4 files changed, 408 insertions(+), 1 deletion(-) create mode 100644 media/libeffects/proxy/Android.mk create mode 100644 media/libeffects/proxy/EffectProxy.cpp create mode 100644 media/libeffects/proxy/EffectProxy.h (limited to 'media/libeffects') diff --git a/media/libeffects/data/audio_effects.conf b/media/libeffects/data/audio_effects.conf index f1c5f5b..c3c4b67 100644 --- a/media/libeffects/data/audio_effects.conf +++ b/media/libeffects/data/audio_effects.conf @@ -10,7 +10,7 @@ libraries { # the HW and SW effects #proxy { - #path /system/lib/soundfx/libProxy.so + #path /system/lib/soundfx/libeffectproxy.so #} # This is the SW implementation library of the effect diff --git a/media/libeffects/proxy/Android.mk b/media/libeffects/proxy/Android.mk new file mode 100644 index 0000000..01b3be1 --- /dev/null +++ b/media/libeffects/proxy/Android.mk @@ -0,0 +1,34 @@ +# Copyright 2013 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) +LOCAL_MODULE:= libeffectproxy +LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/soundfx +LOCAL_MODULE_TAGS := optional + + +LOCAL_SRC_FILES := \ + EffectProxy.cpp + +LOCAL_CFLAGS+= -fvisibility=hidden + +LOCAL_SHARED_LIBRARIES := liblog libcutils libutils libdl libeffects + +LOCAL_C_INCLUDES := \ + system/media/audio_effects/include \ + bionic/libc/include + +include $(BUILD_SHARED_LIBRARY) + diff --git a/media/libeffects/proxy/EffectProxy.cpp b/media/libeffects/proxy/EffectProxy.cpp new file mode 100644 index 0000000..77c6e89 --- /dev/null +++ b/media/libeffects/proxy/EffectProxy.cpp @@ -0,0 +1,298 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "EffectProxy" +//#define LOG_NDEBUG 0 + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace android { +// This is a dummy proxy descriptor just to return to Factory during the initial +// GetDescriptor call. Later in the factory, it is replaced with the +// SW sub effect descriptor +const effect_descriptor_t gProxyDescriptor = { + EFFECT_UUID_INITIALIZER, // type + EFFECT_UUID_INITIALIZER, // uuid + EFFECT_CONTROL_API_VERSION, //version of effect control API + (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_LAST | + EFFECT_FLAG_VOLUME_CTRL), // effect capability flags + 0, // CPU load + 1, // Data memory + "Proxy", //effect name + "AOSP", //implementor name +}; + + +static const effect_descriptor_t *const gDescriptors[] = +{ + &gProxyDescriptor, +}; + +int EffectProxyCreate(const effect_uuid_t *uuid, + int32_t sessionId, + int32_t ioId, + effect_handle_t *pHandle) { + + effect_descriptor_t* desc; + EffectContext* pContext; + if (pHandle == NULL || uuid == NULL) { + ALOGE("EffectProxyCreate() called with NULL pointer"); + return -EINVAL; + } + ALOGV("EffectProxyCreate start.."); + pContext = new EffectContext; + pContext->sessionId = sessionId; + pContext->ioId = ioId; + pContext->uuid = *uuid; + pContext->common_itfe = &gEffectInterface; + // The sub effects will be created in effect_command when the first command + // for the effect is received + pContext->eHandle[SUB_FX_HOST] = pContext->eHandle[SUB_FX_OFFLOAD] = NULL; + + // Get the HW and SW sub effect descriptors from the effects factory + desc = new effect_descriptor_t[SUB_FX_COUNT]; + pContext->desc = new effect_descriptor_t[SUB_FX_COUNT]; + int retValue = EffectGetSubEffects(uuid, desc, + sizeof(effect_descriptor_t) * SUB_FX_COUNT); + // EffectGetSubEffects returns the number of sub-effects copied. + if (retValue != SUB_FX_COUNT) { + ALOGE("EffectCreate() could not get the sub effects"); + delete desc; + delete pContext->desc; + return -EINVAL; + } + // Check which is the HW descriptor and copy the descriptors + // to the Context desc array + // Also check if there is only one HW and one SW descriptor. + // HW descriptor alone has the HW_TUNNEL flag. + if ((desc[0].flags & EFFECT_FLAG_HW_ACC_TUNNEL) && + !(desc[1].flags & EFFECT_FLAG_HW_ACC_TUNNEL)) { + pContext->desc[SUB_FX_OFFLOAD] = desc[0]; + pContext->desc[SUB_FX_HOST] = desc[1]; + } + else if ((desc[1].flags & EFFECT_FLAG_HW_ACC_TUNNEL) && + !(desc[0].flags & EFFECT_FLAG_HW_ACC_TUNNEL)) { + pContext->desc[SUB_FX_HOST] = desc[0]; + pContext->desc[SUB_FX_OFFLOAD] = desc[1]; + } + delete desc; +#if (LOG_NDEBUG == 0) + effect_uuid_t uuid_print = pContext->desc[SUB_FX_HOST].uuid; + ALOGV("EffectCreate() UUID of HOST: %08X-%04X-%04X-%04X-%02X%02X%02X%02X" + "%02X%02X\n",uuid_print.timeLow, uuid_print.timeMid, + uuid_print.timeHiAndVersion, uuid_print.clockSeq, uuid_print.node[0], + uuid_print.node[1], uuid_print.node[2], uuid_print.node[3], + uuid_print.node[4], uuid_print.node[5]); + ALOGV("EffectCreate() UUID of OFFLOAD: %08X-%04X-%04X-%04X-%02X%02X%02X%02X" + "%02X%02X\n", uuid_print.timeLow, uuid_print.timeMid, + uuid_print.timeHiAndVersion, uuid_print.clockSeq, uuid_print.node[0], + uuid_print.node[1], uuid_print.node[2], uuid_print.node[3], + uuid_print.node[4], uuid_print.node[5]); +#endif + *pHandle = (effect_handle_t)pContext; + ALOGV("EffectCreate end"); + return 0; +} //end EffectProxyCreate + +int EffectProxyRelease(effect_handle_t handle) { + EffectContext * pContext = (EffectContext *)handle; + if (pContext == NULL) { + ALOGV("ERROR : EffectRelease called with NULL pointer"); + return -EINVAL; + } + ALOGV("EffectRelease"); + delete pContext->desc; + if (pContext->eHandle[SUB_FX_HOST]) + EffectRelease(pContext->eHandle[SUB_FX_HOST]); + if (pContext->eHandle[SUB_FX_OFFLOAD]) + EffectRelease(pContext->eHandle[SUB_FX_OFFLOAD]); + delete pContext; + pContext = NULL; + return 0; +} /*end EffectProxyRelease */ + +int EffectProxyGetDescriptor(const effect_uuid_t *uuid, + effect_descriptor_t *pDescriptor) { + const effect_descriptor_t *desc = NULL; + + if (pDescriptor == NULL || uuid == NULL) { + ALOGV("EffectGetDescriptor() called with NULL pointer"); + return -EINVAL; + } + desc = &gProxyDescriptor; + *pDescriptor = *desc; + return 0; +} /* end EffectProxyGetDescriptor */ + +/* Effect Control Interface Implementation: Process */ +int Effect_process(effect_handle_t self, + audio_buffer_t *inBuffer, + audio_buffer_t *outBuffer) { + + EffectContext *pContext = (EffectContext *) self; + int ret = 0; + if (pContext != NULL) { + 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); + } + } + return ret; +} /* end Effect_process */ + +/* Effect Control Interface Implementation: Command */ +int Effect_command(effect_handle_t self, + uint32_t cmdCode, + uint32_t cmdSize, + void *pCmdData, + uint32_t *replySize, + void *pReplyData) { + + EffectContext *pContext = (EffectContext *) self; + int status; + if (pContext == NULL) { + ALOGV("Effect_command() Proxy context is NULL"); + return -EINVAL; + } + if (pContext->eHandle[SUB_FX_HOST] == NULL) { + ALOGV("Effect_command() Calling HOST EffectCreate"); + status = EffectCreate(&pContext->desc[SUB_FX_HOST].uuid, + pContext->sessionId, pContext->ioId, + &(pContext->eHandle[SUB_FX_HOST])); + if (status != NO_ERROR || (pContext->eHandle[SUB_FX_HOST] == NULL)) { + ALOGV("Effect_command() Error creating SW sub effect"); + return status; + } + } + if (pContext->eHandle[SUB_FX_OFFLOAD] == NULL) { + ALOGV("Effect_command() Calling OFFLOAD EffectCreate"); + status = EffectCreate(&pContext->desc[SUB_FX_OFFLOAD].uuid, + pContext->sessionId, pContext->ioId, + &(pContext->eHandle[SUB_FX_OFFLOAD])); + if (status != NO_ERROR || (pContext->eHandle[SUB_FX_OFFLOAD] == NULL)) { + ALOGV("Effect_command() Error creating HW effect"); + // Do not return error here as SW effect is created + // Return error if the CMD_OFFLOAD sends the index as OFFLOAD + } + pContext->index = SUB_FX_HOST; + } + // EFFECT_CMD_OFFLOAD used to (1) send whether the thread is offload or not + // (2) Send the ioHandle of the effectThread when the effect + // is moved from one type of thread to another. + // pCmdData points to a memory holding effect_offload_param_t structure + if (cmdCode == EFFECT_CMD_OFFLOAD) { + ALOGV("Effect_command() cmdCode = EFFECT_CMD_OFFLOAD"); + if (cmdSize == 0 || pCmdData == NULL) { + ALOGV("effectsOffload: Effect_command: CMD_OFFLOAD has no data"); + *(int*)pReplyData = FAILED_TRANSACTION; + return FAILED_TRANSACTION; + } + effect_offload_param_t* offloadParam = (effect_offload_param_t*)pCmdData; + // Assign the effect context index based on isOffload field of the structure + pContext->index = offloadParam->isOffload ? SUB_FX_OFFLOAD : SUB_FX_HOST; + // if the index is HW and the HW effect is unavailable, return error + // and reset the index to SW + if (pContext->eHandle[pContext->index] == NULL) { + ALOGV("Effect_command()CMD_OFFLOAD sub effect unavailable"); + *(int*)pReplyData = FAILED_TRANSACTION; + return FAILED_TRANSACTION; + } + pContext->ioId = offloadParam->ioHandle; + ALOGV("Effect_command()CMD_OFFLOAD index:%d io %d", pContext->index, pContext->ioId); + // Update the DSP wrapper with the new ioHandle. + // Pass the OFFLOAD command to the wrapper. + // The DSP wrapper needs to handle this CMD + if (pContext->eHandle[SUB_FX_OFFLOAD]) + status = (*pContext->eHandle[SUB_FX_OFFLOAD])->command( + pContext->eHandle[SUB_FX_OFFLOAD], cmdCode, cmdSize, + pCmdData, replySize, pReplyData); + return status; + } + + int index = pContext->index; + if (index != SUB_FX_HOST && index != SUB_FX_OFFLOAD) { + 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( + pContext->eHandle[SUB_FX_HOST], cmdCode, cmdSize, + pCmdData, replySize, pReplyData); + if (pContext->eHandle[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( + pContext->eHandle[SUB_FX_OFFLOAD], cmdCode, cmdSize, + pCmdData, replySize, pReplyData); + } + return 0; +} /* end Effect_command */ + + +/* Effect Control Interface Implementation: get_descriptor */ +int Effect_getDescriptor(effect_handle_t self, + effect_descriptor_t *pDescriptor) { + + EffectContext * pContext = (EffectContext *) self; + const effect_descriptor_t *desc; + + ALOGV("Effect_getDescriptor"); + if (pContext == NULL || pDescriptor == NULL) { + ALOGV("Effect_getDescriptor() invalid param"); + return -EINVAL; + } + if (pContext->desc == NULL) { + ALOGV("Effect_getDescriptor() could not get descriptor"); + return -EINVAL; + } + desc = &pContext->desc[SUB_FX_HOST]; + *pDescriptor = *desc; + pDescriptor->uuid = pContext->uuid; // Replace the uuid with the Proxy UUID + // Also set/clear the EFFECT_FLAG_OFFLOAD_SUPPORTED flag based on the sub effects availability + if (pContext->eHandle[SUB_FX_OFFLOAD] != NULL) + pDescriptor->flags |= EFFECT_FLAG_OFFLOAD_SUPPORTED; + else + pDescriptor->flags &= ~EFFECT_FLAG_OFFLOAD_SUPPORTED; + return 0; +} /* end Effect_getDescriptor */ + +} // namespace android + +__attribute__ ((visibility ("default"))) +audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = { + tag : AUDIO_EFFECT_LIBRARY_TAG, + version : EFFECT_LIBRARY_API_VERSION, + name : "Effect Proxy", + implementor : "AOSP", + create_effect : android::EffectProxyCreate, + release_effect : android::EffectProxyRelease, + get_descriptor : android::EffectProxyGetDescriptor, +}; diff --git a/media/libeffects/proxy/EffectProxy.h b/media/libeffects/proxy/EffectProxy.h new file mode 100644 index 0000000..8992f93 --- /dev/null +++ b/media/libeffects/proxy/EffectProxy.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +namespace android { +enum { + SUB_FX_HOST, // Index of HOST in the descriptor and handle arrays + // of the Proxy context + SUB_FX_OFFLOAD, // Index of OFFLOAD in the descriptor and handle arrays + // of the Proxy context + SUB_FX_COUNT // The number of sub effects for a Proxy(1 HW, 1 SW) +}; +#if __cplusplus +extern "C" { +#endif + +int EffectProxyCreate(const effect_uuid_t *uuid, + int32_t sessionId, + int32_t ioId, + effect_handle_t *pHandle); +int EffectProxyRelease(effect_handle_t handle); +int EffectProxyGetDescriptor(const effect_uuid_t *uuid, + effect_descriptor_t *pDescriptor); +/* Effect Control Interface Implementation: Process */ +int Effect_process(effect_handle_t self, + audio_buffer_t *inBuffer, + audio_buffer_t *outBuffer); + +/* Effect Control Interface Implementation: Command */ +int Effect_command(effect_handle_t self, + uint32_t cmdCode, + uint32_t cmdSize, + void *pCmdData, + uint32_t *replySize, + void *pReplyData); +int Effect_getDescriptor(effect_handle_t self, + effect_descriptor_t *pDescriptor); + +const struct effect_interface_s gEffectInterface = { + Effect_process, + Effect_command, + Effect_getDescriptor, + NULL, +}; + +struct EffectContext { + const struct effect_interface_s *common_itfe; // Holds the itfe of the Proxy + effect_descriptor_t* desc; // Points to the sub effect descriptors + effect_handle_t eHandle[SUB_FX_COUNT]; // The effect handles of the sub effects + int index; // The index that is currently active - HOST or OFFLOAD + int32_t sessionId; // The sessiond in which the effect is created. + // Stored in context to pass on to sub effect creation + int32_t ioId; // The ioId in which the effect is created. + // Stored in context to pass on to sub effect creation + effect_uuid_t uuid; // UUID of the Proxy +}; + +#if __cplusplus +} // extern "C" +#endif +} //namespace android -- cgit v1.1 From eba9bf72fb5e036bb15ca4a1dc126883a2cb938d Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Fri, 27 Sep 2013 15:04:26 -0700 Subject: fix command handling in effect offload proxy Fix some issues in effect proxy related to handling of effect commands to offloaded and non offloaded effects. Also fixed a bug on capture index in software Visualizer effect. Bug: 8174034. Change-Id: I119458fea597cc3acbc0ef9ec315f67aa211cbd9 --- media/libeffects/proxy/EffectProxy.cpp | 59 +++++++++++++++++++++++++++------- 1 file changed, 48 insertions(+), 11 deletions(-) (limited to 'media/libeffects') 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 */ -- cgit v1.1 From 5d6d86a4d102704f49b9235eaf282c428d7100b6 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Fri, 20 Sep 2013 12:27:32 -0700 Subject: fix oflload effect proxy commmand handling Implement a more generic command handling in offload effect proxy. All commands are sent to both sub effects but only the reply from the active one is returned to the caller. Bug: 8174034. Change-Id: I28aa0f0d806e846332bc29801ee40d34e4ea0c43 --- media/libeffects/proxy/EffectProxy.cpp | 95 ++++++++++++++++++---------------- media/libeffects/proxy/EffectProxy.h | 5 ++ 2 files changed, 54 insertions(+), 46 deletions(-) (limited to 'media/libeffects') diff --git a/media/libeffects/proxy/EffectProxy.cpp b/media/libeffects/proxy/EffectProxy.cpp index 41640da..b3304b7 100644 --- a/media/libeffects/proxy/EffectProxy.cpp +++ b/media/libeffects/proxy/EffectProxy.cpp @@ -48,20 +48,6 @@ 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, @@ -80,6 +66,7 @@ int EffectProxyCreate(const effect_uuid_t *uuid, pContext->ioId = ioId; pContext->uuid = *uuid; pContext->common_itfe = &gEffectInterface; + // The sub effects will be created in effect_command when the first command // for the effect is received pContext->eHandle[SUB_FX_HOST] = pContext->eHandle[SUB_FX_OFFLOAD] = NULL; @@ -124,6 +111,10 @@ int EffectProxyCreate(const effect_uuid_t *uuid, uuid_print.node[1], uuid_print.node[2], uuid_print.node[3], uuid_print.node[4], uuid_print.node[5]); #endif + + pContext->replySize = PROXY_REPLY_SIZE_DEFAULT; + pContext->replyData = (char *)malloc(PROXY_REPLY_SIZE_DEFAULT); + *pHandle = (effect_handle_t)pContext; ALOGV("EffectCreate end"); return 0; @@ -137,6 +128,8 @@ int EffectProxyRelease(effect_handle_t handle) { } ALOGV("EffectRelease"); delete pContext->desc; + free(pContext->replyData); + if (pContext->eHandle[SUB_FX_HOST]) EffectRelease(pContext->eHandle[SUB_FX_HOST]); if (pContext->eHandle[SUB_FX_OFFLOAD]) @@ -253,43 +246,53 @@ int Effect_command(effect_handle_t self, } // 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; + int *subStatus[SUB_FX_COUNT]; + uint32_t *subReplySize[SUB_FX_COUNT]; + void *subReplyData[SUB_FX_COUNT]; + uint32_t tmpSize; + int tmpStatus; - 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 != 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 - offloadStatus = (*pContext->eHandle[SUB_FX_OFFLOAD])->command( - pContext->eHandle[SUB_FX_OFFLOAD], cmdCode, cmdSize, - pCmdData, replySize != NULL ? &offloadReplySize : NULL, pReplyData); - offloadReplied = true; + // grow temp reply buffer if needed + if (replySize != NULL) { + tmpSize = pContext->replySize; + while (tmpSize < *replySize && tmpSize < PROXY_REPLY_SIZE_MAX) { + tmpSize *= 2; + } + if (tmpSize > pContext->replySize) { + ALOGV("Effect_command grow reply buf to %d", tmpSize); + pContext->replyData = (char *)realloc(pContext->replyData, tmpSize); + pContext->replySize = tmpSize; + } + if (tmpSize > *replySize) { + tmpSize = *replySize; + } + } else { + tmpSize = 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; + // tmpSize is now the actual reply size for the non active sub effect + + // Send command to sub effects. The command is sent to all sub effects so that their internal + // state is kept in sync. + // Only the reply from the active sub effect is returned to the caller. The reply from the + // other sub effect is lost in pContext->replyData + for (int i = 0; i < SUB_FX_COUNT; i++) { + if (pContext->eHandle[i] == NULL) { + continue; } - } else if (hostReplied) { - status = hostStatus; - if (replySize) { - *replySize = hostReplySize; + if (i == index) { + subStatus[i] = &status; + subReplySize[i] = replySize; + subReplyData[i] = pReplyData; + } else { + subStatus[i] = &tmpStatus; + subReplySize[i] = replySize == NULL ? NULL : &tmpSize; + subReplyData[i] = pReplyData == NULL ? NULL : pContext->replyData; } + *subStatus[i] = (*pContext->eHandle[i])->command( + pContext->eHandle[i], cmdCode, cmdSize, + pCmdData, subReplySize[i], subReplyData[i]); } + return status; } /* end Effect_command */ diff --git a/media/libeffects/proxy/EffectProxy.h b/media/libeffects/proxy/EffectProxy.h index 8992f93..acbe17e 100644 --- a/media/libeffects/proxy/EffectProxy.h +++ b/media/libeffects/proxy/EffectProxy.h @@ -57,6 +57,9 @@ const struct effect_interface_s gEffectInterface = { NULL, }; +#define PROXY_REPLY_SIZE_MAX (64 * 1024) // must be power of two +#define PROXY_REPLY_SIZE_DEFAULT 32 // must be power of two + struct EffectContext { const struct effect_interface_s *common_itfe; // Holds the itfe of the Proxy effect_descriptor_t* desc; // Points to the sub effect descriptors @@ -67,6 +70,8 @@ struct EffectContext { int32_t ioId; // The ioId in which the effect is created. // Stored in context to pass on to sub effect creation effect_uuid_t uuid; // UUID of the Proxy + char* replyData; // temporary buffer for non active sub effect command reply + uint32_t replySize; // current size of temporary reply buffer }; #if __cplusplus -- cgit v1.1 From 385e7509eb563c983647e72b1232225c2200435f Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Fri, 4 Oct 2013 08:36:52 -0700 Subject: fix offload audio effect proxy implementation uuid The proxy implementation UUID should not be the NULL UUID as AudioFlinger will reject effect creation if the AudioEffect is constructed by passing the implementation UUID and not the type UUID. Bug: 11070481. Change-Id: Ia9049d974e76303c5b63a607ee594b7dc1f182d4 --- media/libeffects/proxy/EffectProxy.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'media/libeffects') diff --git a/media/libeffects/proxy/EffectProxy.cpp b/media/libeffects/proxy/EffectProxy.cpp index b3304b7..dd4ad08 100644 --- a/media/libeffects/proxy/EffectProxy.cpp +++ b/media/libeffects/proxy/EffectProxy.cpp @@ -30,9 +30,10 @@ namespace android { // This is a dummy proxy descriptor just to return to Factory during the initial // GetDescriptor call. Later in the factory, it is replaced with the // SW sub effect descriptor +// proxy UUID af8da7e0-2ca1-11e3-b71d-0002a5d5c51b const effect_descriptor_t gProxyDescriptor = { EFFECT_UUID_INITIALIZER, // type - EFFECT_UUID_INITIALIZER, // uuid + {0xaf8da7e0, 0x2ca1, 0x11e3, 0xb71d, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b }}, // uuid EFFECT_CONTROL_API_VERSION, //version of effect control API (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_LAST | EFFECT_FLAG_VOLUME_CTRL), // effect capability flags -- cgit v1.1