Merge "Disable detection of MP3 audio contained in MPEG1"
diff --git a/media/libaaudio/src/binding/AAudioServiceMessage.h b/media/libaaudio/src/binding/AAudioServiceMessage.h
index 54e8001..9779f24 100644
--- a/media/libaaudio/src/binding/AAudioServiceMessage.h
+++ b/media/libaaudio/src/binding/AAudioServiceMessage.h
@@ -38,13 +38,16 @@
AAUDIO_SERVICE_EVENT_FLUSHED,
AAUDIO_SERVICE_EVENT_CLOSED,
AAUDIO_SERVICE_EVENT_DISCONNECTED,
- AAUDIO_SERVICE_EVENT_VOLUME
+ AAUDIO_SERVICE_EVENT_VOLUME,
+ AAUDIO_SERVICE_EVENT_XRUN
} aaudio_service_event_t;
struct AAudioMessageEvent {
aaudio_service_event_t event;
- double dataDouble;
- int64_t dataLong;
+ union {
+ double dataDouble;
+ int64_t dataLong;
+ };
};
typedef struct AAudioServiceMessage_s {
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index 3a7a342..b7b4b5c 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -492,6 +492,9 @@
doSetVolume();
ALOGD("%s - AAUDIO_SERVICE_EVENT_VOLUME %lf", __func__, message->event.dataDouble);
break;
+ case AAUDIO_SERVICE_EVENT_XRUN:
+ mXRunCount = static_cast<int32_t>(message->event.dataLong);
+ break;
default:
ALOGE("%s - Unrecognized event = %d", __func__, (int) message->event.event);
break;
diff --git a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
index 77a481b..3e82a88 100644
--- a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
@@ -102,7 +102,8 @@
}
// If the write index passed the read index then consider it an overrun.
- if (mAudioEndpoint.getEmptyFramesAvailable() < 0) {
+ // For shared streams, the xRunCount is passed up from the service.
+ if (mAudioEndpoint.isFreeRunning() && mAudioEndpoint.getEmptyFramesAvailable() < 0) {
mXRunCount++;
if (ATRACE_ENABLED()) {
ATRACE_INT("aaOverRuns", mXRunCount);
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
index 8d7a01e..b49e08c 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
@@ -140,7 +140,8 @@
}
// If the read index passed the write index then consider it an underrun.
- if (mAudioEndpoint.getFullFramesAvailable() < 0) {
+ // For shared streams, the xRunCount is passed up from the service.
+ if (mAudioEndpoint.isFreeRunning() && mAudioEndpoint.getFullFramesAvailable() < 0) {
mXRunCount++;
if (ATRACE_ENABLED()) {
ATRACE_INT("aaUnderRuns", mXRunCount);
diff --git a/media/libaudiohal/EffectBufferHalHidl.h b/media/libaudiohal/EffectBufferHalHidl.h
index 66a81c2..d7a43ae 100644
--- a/media/libaudiohal/EffectBufferHalHidl.h
+++ b/media/libaudiohal/EffectBufferHalHidl.h
@@ -35,6 +35,8 @@
virtual audio_buffer_t* audioBuffer();
virtual void* externalData() const;
+ virtual size_t getSize() const override { return mBufferSize; }
+
virtual void setExternalData(void* external);
virtual void setFrameCount(size_t frameCount);
virtual bool checkFrameCountChange();
diff --git a/media/libaudiohal/include/media/audiohal/EffectBufferHalInterface.h b/media/libaudiohal/include/media/audiohal/EffectBufferHalInterface.h
index e862f6e..1cae662 100644
--- a/media/libaudiohal/include/media/audiohal/EffectBufferHalInterface.h
+++ b/media/libaudiohal/include/media/audiohal/EffectBufferHalInterface.h
@@ -37,6 +37,8 @@
return externalData() != nullptr ? externalData() : audioBuffer()->raw;
}
+ virtual size_t getSize() const = 0;
+
virtual void setExternalData(void* external) = 0;
virtual void setFrameCount(size_t frameCount) = 0;
virtual bool checkFrameCountChange() = 0; // returns whether frame count has been updated
diff --git a/media/libeffects/lvm/lib/Common/lib/LVM_Types.h b/media/libeffects/lvm/lib/Common/lib/LVM_Types.h
index cb15b60..ea16072 100644
--- a/media/libeffects/lvm/lib/Common/lib/LVM_Types.h
+++ b/media/libeffects/lvm/lib/Common/lib/LVM_Types.h
@@ -44,9 +44,6 @@
#define LVM_MAXINT_8 127 /* Maximum positive integer size */
#define LVM_MAXINT_16 32767
-#ifdef BUILD_FLOAT
-#define LVM_MAXFLOAT 1.0f
-#endif
#define LVM_MAXINT_32 2147483647
#define LVM_MAXENUM 2147483647
@@ -99,8 +96,32 @@
typedef uint32_t LVM_UINT32; /* Unsigned 32-bit word */
#ifdef BUILD_FLOAT
-typedef float LVM_FLOAT; /* single precission floating point*/
-#endif
+
+#define LVM_MAXFLOAT 1.f
+
+typedef float LVM_FLOAT; /* single precision floating point */
+
+// If NATIVE_FLOAT_BUFFER is defined, we expose effects as floating point format;
+// otherwise we expose as integer 16 bit and translate to float for the effect libraries.
+// Hence, NATIVE_FLOAT_BUFFER should only be enabled under BUILD_FLOAT compilation.
+
+#define NATIVE_FLOAT_BUFFER
+
+#endif // BUILD_FLOAT
+
+// Select whether we expose int16_t or float buffers.
+#ifdef NATIVE_FLOAT_BUFFER
+
+#define EFFECT_BUFFER_FORMAT AUDIO_FORMAT_PCM_FLOAT
+typedef float effect_buffer_t;
+
+#else // NATIVE_FLOAT_BUFFER
+
+#define EFFECT_BUFFER_FORMAT AUDIO_FORMAT_PCM_16_BIT
+typedef int16_t effect_buffer_t;
+
+#endif // NATIVE_FLOAT_BUFFER
+
/****************************************************************************************/
/* */
/* Standard Enumerated types */
diff --git a/media/libeffects/lvm/wrapper/Android.mk b/media/libeffects/lvm/wrapper/Android.mk
index 91e2246..341dbc2 100644
--- a/media/libeffects/lvm/wrapper/Android.mk
+++ b/media/libeffects/lvm/wrapper/Android.mk
@@ -1,5 +1,8 @@
LOCAL_PATH:= $(call my-dir)
+# The wrapper -DBUILD_FLOAT needs to match
+# the lvm library -DBUILD_FLOAT.
+
# music bundle wrapper
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
@@ -20,15 +23,17 @@
LOCAL_STATIC_LIBRARIES += libmusicbundle
LOCAL_SHARED_LIBRARIES := \
- liblog \
+ libaudioutils \
libcutils \
- libdl
+ libdl \
+ liblog \
LOCAL_C_INCLUDES += \
$(LOCAL_PATH)/Bundle \
$(LOCAL_PATH)/../lib/Common/lib/ \
$(LOCAL_PATH)/../lib/Bundle/lib/ \
- $(call include-path-for, audio-effects)
+ $(call include-path-for, audio-effects) \
+ $(call include-path-for, audio-utils) \
LOCAL_HEADER_LIBRARIES += libhardware_headers
include $(BUILD_SHARED_LIBRARY)
@@ -53,15 +58,17 @@
LOCAL_STATIC_LIBRARIES += libreverb
LOCAL_SHARED_LIBRARIES := \
- liblog \
+ libaudioutils \
libcutils \
- libdl
+ libdl \
+ liblog \
LOCAL_C_INCLUDES += \
$(LOCAL_PATH)/Reverb \
$(LOCAL_PATH)/../lib/Common/lib/ \
$(LOCAL_PATH)/../lib/Reverb/lib/ \
- $(call include-path-for, audio-effects)
+ $(call include-path-for, audio-effects) \
+ $(call include-path-for, audio-utils) \
LOCAL_HEADER_LIBRARIES += libhardware_headers
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index aae80b6..146e9e8 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -27,6 +27,7 @@
#include <stdlib.h>
#include <string.h>
+#include <audio_utils/primitives.h>
#include <log/log.h>
#include "EffectBundle.h"
@@ -63,16 +64,6 @@
}\
}
-
-static inline int16_t clamp16(int32_t sample)
-{
- // check overflow for both positive and negative values:
- // all bits above short range must me equal to sign bit
- if ((sample>>15) ^ (sample>>31))
- sample = 0x7FFF ^ (sample>>31);
- return sample;
-}
-
// Namespaces
namespace android {
namespace {
@@ -299,7 +290,7 @@
pContext->pBundledContext->SamplesToExitCountVirt = 0;
pContext->pBundledContext->SamplesToExitCountBb = 0;
pContext->pBundledContext->SamplesToExitCountEq = 0;
-#ifdef BUILD_FLOAT
+#if defined(BUILD_FLOAT) && !defined(NATIVE_FLOAT_BUFFER)
pContext->pBundledContext->pInputBuffer = NULL;
pContext->pBundledContext->pOutputBuffer = NULL;
#endif
@@ -470,13 +461,9 @@
if (pContext->pBundledContext->workBuffer != NULL) {
free(pContext->pBundledContext->workBuffer);
}
-#ifdef BUILD_FLOAT
- if (pContext->pBundledContext->pInputBuffer != NULL) {
- free(pContext->pBundledContext->pInputBuffer);
- }
- if (pContext->pBundledContext->pOutputBuffer != NULL) {
- free(pContext->pBundledContext->pOutputBuffer);
- }
+#if defined(BUILD_FLOAT) && !defined(NATIVE_FLOAT_BUFFER)
+ free(pContext->pBundledContext->pInputBuffer);
+ free(pContext->pBundledContext->pOutputBuffer);
#endif
delete pContext->pBundledContext;
pContext->pBundledContext = LVM_NULL;
@@ -549,7 +536,7 @@
pContext->config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
pContext->config.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
- pContext->config.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+ pContext->config.inputCfg.format = EFFECT_BUFFER_FORMAT;
pContext->config.inputCfg.samplingRate = 44100;
pContext->config.inputCfg.bufferProvider.getBuffer = NULL;
pContext->config.inputCfg.bufferProvider.releaseBuffer = NULL;
@@ -557,7 +544,7 @@
pContext->config.inputCfg.mask = EFFECT_CONFIG_ALL;
pContext->config.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE;
pContext->config.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
- pContext->config.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+ pContext->config.outputCfg.format = EFFECT_BUFFER_FORMAT;
pContext->config.outputCfg.samplingRate = 44100;
pContext->config.outputCfg.bufferProvider.getBuffer = NULL;
pContext->config.outputCfg.bufferProvider.releaseBuffer = NULL;
@@ -734,47 +721,6 @@
return 0;
} /* end LvmBundle_init */
-#ifdef BUILD_FLOAT
-/**********************************************************************************
- FUNCTION INT16LTOFLOAT
-***********************************************************************************/
-// Todo: need to write function descriptor
-static void Int16ToFloat(const LVM_INT16 *src, LVM_FLOAT *dst, size_t n) {
- size_t ii;
- src += n-1;
- dst += n-1;
- for (ii = n; ii != 0; ii--) {
- *dst = ((LVM_FLOAT)((LVM_INT16)*src)) / 32768.0f;
- src--;
- dst--;
- }
- return;
-}
-/**********************************************************************************
- FUNCTION FLOATTOINT16_SAT
-***********************************************************************************/
-// Todo : Need to write function descriptor
-static void FloatToInt16_SAT(const LVM_FLOAT *src, LVM_INT16 *dst, size_t n) {
- size_t ii;
- LVM_INT32 temp;
-
- src += n-1;
- dst += n-1;
- for (ii = n; ii != 0; ii--) {
- temp = (LVM_INT32)((*src) * 32768.0f);
- if (temp >= 32767) {
- *dst = 32767;
- } else if (temp <= -32768) {
- *dst = -32768;
- } else {
- *dst = (LVM_INT16)temp;
- }
- src--;
- dst--;
- }
- return;
-}
-#endif
//----------------------------------------------------------------------------
// LvmBundle_process()
//----------------------------------------------------------------------------
@@ -782,8 +728,8 @@
// Apply LVM Bundle effects
//
// Inputs:
-// pIn: pointer to stereo 16 bit input data
-// pOut: pointer to stereo 16 bit output data
+// pIn: pointer to stereo float or 16 bit input data
+// pOut: pointer to stereo float or 16 bit output data
// frameCount: Frames to process
// pContext: effect engine context
// strength strength to be applied
@@ -793,44 +739,37 @@
//
//----------------------------------------------------------------------------
#ifdef BUILD_FLOAT
-int LvmBundle_process(LVM_INT16 *pIn,
- LVM_INT16 *pOut,
+int LvmBundle_process(effect_buffer_t *pIn,
+ effect_buffer_t *pOut,
int frameCount,
EffectContext *pContext){
-
- //LVM_ControlParams_t ActiveParams; /* Current control Parameters */
LVM_ReturnStatus_en LvmStatus = LVM_SUCCESS; /* Function call status */
- LVM_INT16 *pOutTmp;
- LVM_FLOAT *pInputBuff;
- LVM_FLOAT *pOutputBuff;
-
- if (pContext->pBundledContext->pInputBuffer == NULL ||
+ effect_buffer_t *pOutTmp;
+#ifndef NATIVE_FLOAT_BUFFER
+ if (pContext->pBundledContext->pInputBuffer == nullptr ||
pContext->pBundledContext->frameCount < frameCount) {
- if (pContext->pBundledContext->pInputBuffer != NULL) {
- free(pContext->pBundledContext->pInputBuffer);
- }
- pContext->pBundledContext->pInputBuffer = (LVM_FLOAT *)malloc(frameCount * \
- sizeof(LVM_FLOAT) * FCC_2);
+ free(pContext->pBundledContext->pInputBuffer);
+ pContext->pBundledContext->pInputBuffer =
+ (LVM_FLOAT *)calloc(frameCount, sizeof(LVM_FLOAT) * FCC_2);
}
- if (pContext->pBundledContext->pOutputBuffer == NULL ||
+ if (pContext->pBundledContext->pOutputBuffer == nullptr ||
pContext->pBundledContext->frameCount < frameCount) {
- if (pContext->pBundledContext->pOutputBuffer != NULL) {
- free(pContext->pBundledContext->pOutputBuffer);
- }
- pContext->pBundledContext->pOutputBuffer = (LVM_FLOAT *)malloc(frameCount * \
- sizeof(LVM_FLOAT) * FCC_2);
+ free(pContext->pBundledContext->pOutputBuffer);
+ pContext->pBundledContext->pOutputBuffer =
+ (LVM_FLOAT *)calloc(frameCount, sizeof(LVM_FLOAT) * FCC_2);
}
- if ((pContext->pBundledContext->pInputBuffer == NULL) ||
- (pContext->pBundledContext->pOutputBuffer == NULL)) {
- ALOGV("LVM_ERROR : LvmBundle_process memory allocation for float buffer's failed");
+ if (pContext->pBundledContext->pInputBuffer == nullptr ||
+ pContext->pBundledContext->pOutputBuffer == nullptr) {
+ ALOGE("LVM_ERROR : LvmBundle_process memory allocation for float buffer's failed");
return -EINVAL;
}
- pInputBuff = pContext->pBundledContext->pInputBuffer;
- pOutputBuff = pContext->pBundledContext->pOutputBuffer;
+ LVM_FLOAT * const pInputBuff = pContext->pBundledContext->pInputBuffer;
+ LVM_FLOAT * const pOutputBuff = pContext->pBundledContext->pOutputBuffer;
+#endif
if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_WRITE){
pOutTmp = pOut;
@@ -840,7 +779,7 @@
free(pContext->pBundledContext->workBuffer);
}
pContext->pBundledContext->workBuffer =
- (LVM_INT16 *)calloc(frameCount, sizeof(LVM_INT16) * FCC_2);
+ (effect_buffer_t *)calloc(frameCount, sizeof(effect_buffer_t) * FCC_2);
if (pContext->pBundledContext->workBuffer == NULL) {
return -ENOMEM;
}
@@ -852,43 +791,61 @@
return -EINVAL;
}
- #ifdef LVM_PCM
- fwrite(pIn, frameCount*sizeof(LVM_INT16) * FCC_2, 1, pContext->pBundledContext->PcmInPtr);
+#ifdef LVM_PCM
+ fwrite(pIn,
+ frameCount*sizeof(effect_buffer_t) * FCC_2, 1, pContext->pBundledContext->PcmInPtr);
fflush(pContext->pBundledContext->PcmInPtr);
- #endif
+#endif
+#ifndef NATIVE_FLOAT_BUFFER
/* Converting input data from fixed point to float point */
- Int16ToFloat(pIn, pInputBuff, frameCount * 2);
+ memcpy_to_float_from_i16(pInputBuff, pIn, frameCount * FCC_2);
/* Process the samples */
LvmStatus = LVM_Process(pContext->pBundledContext->hInstance, /* Instance handle */
pInputBuff, /* Input buffer */
pOutputBuff, /* Output buffer */
(LVM_UINT16)frameCount, /* Number of samples to read */
- 0); /* Audo Time */
+ 0); /* Audio Time */
+ /* Converting output data from float point to fixed point */
+ memcpy_to_i16_from_float(pOutTmp, pOutputBuff, frameCount * FCC_2);
+
+#else
+ /* Process the samples */
+ LvmStatus = LVM_Process(pContext->pBundledContext->hInstance, /* Instance handle */
+ pIn, /* Input buffer */
+ pOutTmp, /* Output buffer */
+ (LVM_UINT16)frameCount, /* Number of samples to read */
+ 0); /* Audio Time */
+#endif
LVM_ERROR_CHECK(LvmStatus, "LVM_Process", "LvmBundle_process")
if(LvmStatus != LVM_SUCCESS) return -EINVAL;
- /* Converting output data from float point to fixed point */
- FloatToInt16_SAT(pOutputBuff, pOutTmp, (LVM_UINT16)frameCount * 2);
- #ifdef LVM_PCM
- fwrite(pOutTmp, frameCount*sizeof(LVM_INT16) * FCC_2, 1, pContext->pBundledContext->PcmOutPtr);
+#ifdef LVM_PCM
+ fwrite(pOutTmp,
+ frameCount*sizeof(effect_buffer_t) * FCC_2, 1, pContext->pBundledContext->PcmOutPtr);
fflush(pContext->pBundledContext->PcmOutPtr);
- #endif
+#endif
if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE){
- for (int i = 0; i < frameCount * 2; i++){
+ for (int i = 0; i < frameCount * FCC_2; i++) {
+#ifndef NATIVE_FLOAT_BUFFER
pOut[i] = clamp16((LVM_INT32)pOut[i] + (LVM_INT32)pOutTmp[i]);
+#else
+ pOut[i] = pOut[i] + pOutTmp[i];
+#endif
}
}
return 0;
} /* end LvmBundle_process */
-#else
+
+#else // BUILD_FLOAT
+
int LvmBundle_process(LVM_INT16 *pIn,
LVM_INT16 *pOut,
int frameCount,
- EffectContext *pContext){
+ EffectContext *pContext) {
LVM_ReturnStatus_en LvmStatus = LVM_SUCCESS; /* Function call status */
LVM_INT16 *pOutTmp;
@@ -901,7 +858,7 @@
free(pContext->pBundledContext->workBuffer);
}
pContext->pBundledContext->workBuffer =
- (LVM_INT16 *)calloc(frameCount, sizeof(LVM_INT16) * 2);
+ (effect_buffer_t *)calloc(frameCount, sizeof(effect_buffer_t) * FCC_2);
if (pContext->pBundledContext->workBuffer == NULL) {
return -ENOMEM;
}
@@ -913,10 +870,11 @@
return -EINVAL;
}
- #ifdef LVM_PCM
- fwrite(pIn, frameCount*sizeof(LVM_INT16)*2, 1, pContext->pBundledContext->PcmInPtr);
+#ifdef LVM_PCM
+ fwrite(pIn, frameCount * sizeof(*pIn) * FCC_2,
+ 1 /* nmemb */, pContext->pBundledContext->PcmInPtr);
fflush(pContext->pBundledContext->PcmInPtr);
- #endif
+#endif
//ALOGV("Calling LVM_Process");
@@ -925,15 +883,16 @@
pIn, /* Input buffer */
pOutTmp, /* Output buffer */
(LVM_UINT16)frameCount, /* Number of samples to read */
- 0); /* Audo Time */
+ 0); /* Audio Time */
LVM_ERROR_CHECK(LvmStatus, "LVM_Process", "LvmBundle_process")
if(LvmStatus != LVM_SUCCESS) return -EINVAL;
- #ifdef LVM_PCM
- fwrite(pOutTmp, frameCount*sizeof(LVM_INT16)*2, 1, pContext->pBundledContext->PcmOutPtr);
+#ifdef LVM_PCM
+ fwrite(pOutTmp, frameCount * sizeof(*pOutTmp) * FCC_2,
+ 1 /* nmemb */, pContext->pBundledContext->PcmOutPtr);
fflush(pContext->pBundledContext->PcmOutPtr);
- #endif
+#endif
if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE){
for (int i=0; i<frameCount*2; i++){
@@ -942,7 +901,8 @@
}
return 0;
} /* end LvmBundle_process */
-#endif
+
+#endif // BUILD_FLOAT
//----------------------------------------------------------------------------
// EqualizerUpdateActiveParams()
@@ -1276,8 +1236,7 @@
CHECK_ARG(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_16_BIT);
-
+ CHECK_ARG(pConfig->inputCfg.format == EFFECT_BUFFER_FORMAT);
pContext->config = *pConfig;
switch (pConfig->inputCfg.samplingRate) {
@@ -3349,10 +3308,17 @@
pContext->pBundledContext->NumberEffectsCalled = 0;
/* Process all the available frames, block processing is
handled internalLY by the LVM bundle */
- processStatus = android::LvmBundle_process( (LVM_INT16 *)inBuffer->raw,
- (LVM_INT16 *)outBuffer->raw,
- outBuffer->frameCount,
- pContext);
+#ifdef NATIVE_FLOAT_BUFFER
+ processStatus = android::LvmBundle_process(inBuffer->f32,
+ outBuffer->f32,
+ outBuffer->frameCount,
+ pContext);
+#else
+ processStatus = android::LvmBundle_process(inBuffer->s16,
+ outBuffer->s16,
+ outBuffer->frameCount,
+ pContext);
+#endif
if (processStatus != 0){
ALOGV("\tLVM_ERROR : LvmBundle_process returned error %d", processStatus);
if (status == 0) {
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
index 291383a..6bf045d 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
@@ -95,7 +95,7 @@
int SamplesToExitCountEq;
int SamplesToExitCountBb;
int SamplesToExitCountVirt;
- LVM_INT16 *workBuffer;
+ effect_buffer_t *workBuffer;
int frameCount;
int32_t bandGaindB[FIVEBAND_NUMBANDS];
int volume;
@@ -103,10 +103,10 @@
FILE *PcmInPtr;
FILE *PcmOutPtr;
#endif
- #ifdef BUILD_FLOAT
+#if defined(BUILD_FLOAT) && !defined(NATIVE_FLOAT_BUFFER)
LVM_FLOAT *pInputBuffer;
LVM_FLOAT *pOutputBuffer;
- #endif
+#endif
};
/* SessionContext : One session */
diff --git a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
index 3d8e982..cc58b7f 100644
--- a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
+++ b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
@@ -27,6 +27,7 @@
#include <stdlib.h>
#include <string.h>
+#include <audio_utils/primitives.h>
#include <log/log.h>
#include "EffectReverb.h"
@@ -135,6 +136,12 @@
&gInsertPresetReverbDescriptor
};
+#ifdef BUILD_FLOAT
+typedef float process_buffer_t; // process in float
+#else
+typedef int32_t process_buffer_t; // process in Q4_27
+#endif // BUILD_FLOAT
+
struct ReverbContext{
const struct effect_interface_s *itfe;
effect_config_t config;
@@ -152,8 +159,8 @@
FILE *PcmOutPtr;
#endif
LVM_Fs_en SampleRate;
- LVM_INT32 *InFrames32;
- LVM_INT32 *OutFrames32;
+ process_buffer_t *InFrames;
+ process_buffer_t *OutFrames;
size_t bufferSizeIn;
size_t bufferSizeOut;
bool auxiliary;
@@ -262,7 +269,7 @@
*pHandle = (effect_handle_t)pContext;
- #ifdef LVM_PCM
+#ifdef LVM_PCM
pContext->PcmInPtr = NULL;
pContext->PcmOutPtr = NULL;
@@ -273,19 +280,15 @@
(pContext->PcmOutPtr == NULL)){
return -EINVAL;
}
- #endif
+#endif
+ int channels = audio_channel_count_from_out_mask(pContext->config.inputCfg.channels);
// Allocate memory for reverb process (*2 is for STEREO)
-#ifdef BUILD_FLOAT
- pContext->bufferSizeIn = LVREV_MAX_FRAME_SIZE * sizeof(float) * 2;
- pContext->bufferSizeOut = pContext->bufferSizeIn;
-#else
- pContext->bufferSizeIn = LVREV_MAX_FRAME_SIZE * sizeof(LVM_INT32) * 2;
- pContext->bufferSizeOut = pContext->bufferSizeIn;
-#endif
- pContext->InFrames32 = (LVM_INT32 *)malloc(pContext->bufferSizeIn);
- pContext->OutFrames32 = (LVM_INT32 *)malloc(pContext->bufferSizeOut);
+ pContext->bufferSizeIn = LVREV_MAX_FRAME_SIZE * sizeof(process_buffer_t) * channels;
+ pContext->bufferSizeOut = LVREV_MAX_FRAME_SIZE * sizeof(process_buffer_t) * FCC_2;
+ pContext->InFrames = (process_buffer_t *)calloc(pContext->bufferSizeIn, 1 /* size */);
+ pContext->OutFrames = (process_buffer_t *)calloc(pContext->bufferSizeOut, 1 /* size */);
ALOGV("\tEffectCreate %p, size %zu", pContext, sizeof(ReverbContext));
ALOGV("\tEffectCreate end\n");
@@ -305,8 +308,8 @@
fclose(pContext->PcmInPtr);
fclose(pContext->PcmOutPtr);
#endif
- free(pContext->InFrames32);
- free(pContext->OutFrames32);
+ free(pContext->InFrames);
+ free(pContext->OutFrames);
pContext->bufferSizeIn = 0;
pContext->bufferSizeOut = 0;
Reverb_free(pContext);
@@ -344,114 +347,6 @@
} \
}
-#if 0
-//----------------------------------------------------------------------------
-// MonoTo2I_32()
-//----------------------------------------------------------------------------
-// Purpose:
-// Convert MONO to STEREO
-//
-//----------------------------------------------------------------------------
-
-void MonoTo2I_32( const LVM_INT32 *src,
- LVM_INT32 *dst,
- LVM_INT16 n)
-{
- LVM_INT16 ii;
- src += (n-1);
- dst += ((n*2)-1);
-
- for (ii = n; ii != 0; ii--)
- {
- *dst = *src;
- dst--;
-
- *dst = *src;
- dst--;
- src--;
- }
-
- return;
-}
-
-//----------------------------------------------------------------------------
-// From2iToMono_32()
-//----------------------------------------------------------------------------
-// Purpose:
-// Convert STEREO to MONO
-//
-//----------------------------------------------------------------------------
-
-void From2iToMono_32( const LVM_INT32 *src,
- LVM_INT32 *dst,
- LVM_INT16 n)
-{
- LVM_INT16 ii;
- LVM_INT32 Temp;
-
- for (ii = n; ii != 0; ii--)
- {
- Temp = (*src>>1);
- src++;
-
- Temp +=(*src>>1);
- src++;
-
- *dst = Temp;
- dst++;
- }
-
- return;
-}
-#endif
-
-#ifdef BUILD_FLOAT
-/**********************************************************************************
- FUNCTION INT16LTOFLOAT
-***********************************************************************************/
-// Todo: need to write function descriptor
-static void Int16ToFloat(const LVM_INT16 *src, LVM_FLOAT *dst, size_t n) {
- size_t ii;
- src += n-1;
- dst += n-1;
- for (ii = n; ii != 0; ii--) {
- *dst = ((LVM_FLOAT)((LVM_INT16)*src)) / 32768.0f;
- src--;
- dst--;
- }
- return;
-}
-/**********************************************************************************
- FUNCTION FLOATTOINT16_SAT
-***********************************************************************************/
-// Todo : Need to write function descriptor
-static void FloatToInt16_SAT(const LVM_FLOAT *src, LVM_INT16 *dst, size_t n) {
- size_t ii;
- LVM_INT32 temp;
-
- for (ii = 0; ii < n; ii++) {
- temp = (LVM_INT32)((*src) * 32768.0f);
- if (temp >= 32767) {
- *dst = 32767;
- } else if (temp <= -32768) {
- *dst = -32768;
- } else {
- *dst = (LVM_INT16)temp;
- }
- src++;
- dst++;
- }
- return;
-}
-#endif
-
-static inline int16_t clamp16(int32_t sample)
-{
- if ((sample>>15) ^ (sample>>31))
- sample = 0x7FFF ^ (sample>>31);
- return sample;
-}
-
//----------------------------------------------------------------------------
// process()
//----------------------------------------------------------------------------
@@ -459,8 +354,8 @@
// Apply the Reverb
//
// Inputs:
-// pIn: pointer to stereo/mono 16 bit input data
-// pOut: pointer to stereo 16 bit output data
+// pIn: pointer to stereo/mono float or 16 bit input data
+// pOut: pointer to stereo float or 16 bit output data
// frameCount: Frames to process
// pContext: effect engine context
// strength strength to be applied
@@ -469,116 +364,107 @@
// pOut: pointer to updated stereo 16 bit output data
//
//----------------------------------------------------------------------------
-
-int process( LVM_INT16 *pIn,
- LVM_INT16 *pOut,
+int process( effect_buffer_t *pIn,
+ effect_buffer_t *pOut,
int frameCount,
ReverbContext *pContext){
- LVM_INT16 samplesPerFrame = 1;
+ int channels = audio_channel_count_from_out_mask(pContext->config.inputCfg.channels);
LVREV_ReturnStatus_en LvmStatus = LVREV_SUCCESS; /* Function call status */
- LVM_INT16 *OutFrames16;
-#ifdef BUILD_FLOAT
- LVM_FLOAT *pInputBuff;
- LVM_FLOAT *pOutputBuff;
-#endif
-#ifdef BUILD_FLOAT
- if (pContext->InFrames32 == NULL ||
- pContext->bufferSizeIn < frameCount * sizeof(float) * 2) {
- if (pContext->InFrames32 != NULL) {
- free(pContext->InFrames32);
- }
- pContext->bufferSizeIn = frameCount * sizeof(float) * 2;
- pContext->InFrames32 = (LVM_INT32 *)malloc(pContext->bufferSizeIn);
- }
- if (pContext->OutFrames32 == NULL ||
- pContext->bufferSizeOut < frameCount * sizeof(float) * 2) {
- if (pContext->OutFrames32 != NULL) {
- free(pContext->OutFrames32);
- }
- pContext->bufferSizeOut = frameCount * sizeof(float) * 2;
- pContext->OutFrames32 = (LVM_INT32 *)malloc(pContext->bufferSizeOut);
- }
- pInputBuff = (float *)pContext->InFrames32;
- pOutputBuff = (float *)pContext->OutFrames32;
-#endif
// Check that the input is either mono or stereo
- if (pContext->config.inputCfg.channels == AUDIO_CHANNEL_OUT_STEREO) {
- samplesPerFrame = 2;
- } else if (pContext->config.inputCfg.channels != AUDIO_CHANNEL_OUT_MONO) {
- ALOGV("\tLVREV_ERROR : process invalid PCM format");
+ if (!(channels == 1 || channels == FCC_2) ) {
+ ALOGE("\tLVREV_ERROR : process invalid PCM format");
return -EINVAL;
}
- OutFrames16 = (LVM_INT16 *)pContext->OutFrames32;
+#ifdef BUILD_FLOAT
+ size_t inSize = frameCount * sizeof(process_buffer_t) * channels;
+ size_t outSize = frameCount * sizeof(process_buffer_t) * FCC_2;
+ if (pContext->InFrames == NULL ||
+ pContext->bufferSizeIn < inSize) {
+ free(pContext->InFrames);
+ pContext->bufferSizeIn = inSize;
+ pContext->InFrames = (process_buffer_t *)calloc(1, pContext->bufferSizeIn);
+ }
+ if (pContext->OutFrames == NULL ||
+ pContext->bufferSizeOut < outSize) {
+ free(pContext->OutFrames);
+ pContext->bufferSizeOut = outSize;
+ pContext->OutFrames = (process_buffer_t *)calloc(1, pContext->bufferSizeOut);
+ }
+
+#ifndef NATIVE_FLOAT_BUFFER
+ effect_buffer_t * const OutFrames16 = (effect_buffer_t *)pContext->OutFrames;
+#endif
+#endif
// Check for NULL pointers
- if((pContext->InFrames32 == NULL)||(pContext->OutFrames32 == NULL)){
- ALOGV("\tLVREV_ERROR : process failed to allocate memory for temporary buffers ");
+ if ((pContext->InFrames == NULL) || (pContext->OutFrames == NULL)) {
+ ALOGE("\tLVREV_ERROR : process failed to allocate memory for temporary buffers ");
return -EINVAL;
}
- #ifdef LVM_PCM
- fwrite(pIn, frameCount*sizeof(LVM_INT16)*samplesPerFrame, 1, pContext->PcmInPtr);
+#ifdef LVM_PCM
+ fwrite(pIn, frameCount * sizeof(*pIn) * channels, 1 /* nmemb */, pContext->PcmInPtr);
fflush(pContext->PcmInPtr);
- #endif
+#endif
if (pContext->preset && pContext->nextPreset != pContext->curPreset) {
Reverb_LoadPreset(pContext);
}
- // Convert to Input 32 bits
if (pContext->auxiliary) {
#ifdef BUILD_FLOAT
- Int16ToFloat(pIn, pInputBuff, frameCount * samplesPerFrame);
+#ifdef NATIVE_FLOAT_BUFFER
+ static_assert(std::is_same<decltype(*pIn), decltype(*pContext->InFrames)>::value,
+ "pIn and InFrames must be same type");
+ memcpy(pContext->InFrames, pIn, frameCount * channels * sizeof(*pIn));
#else
- for(int i=0; i<frameCount*samplesPerFrame; i++){
- pContext->InFrames32[i] = (LVM_INT32)pIn[i]<<8;
+ memcpy_to_float_from_i16(
+ pContext->InFrames, pIn, frameCount * channels);
+#endif
+#else //no BUILD_FLOAT
+ for (int i = 0; i < frameCount * channels; i++) {
+ pContext->InFrames[i] = (process_buffer_t)pIn[i]<<8;
}
#endif
} else {
// insert reverb input is always stereo
for (int i = 0; i < frameCount; i++) {
-#ifndef BUILD_FLOAT
- pContext->InFrames32[2*i] = (pIn[2*i] * REVERB_SEND_LEVEL) >> 4; // <<8 + >>12
- pContext->InFrames32[2*i+1] = (pIn[2*i+1] * REVERB_SEND_LEVEL) >> 4; // <<8 + >>12
+#ifdef BUILD_FLOAT
+#ifdef NATIVE_FLOAT_BUFFER
+ pContext->InFrames[2 * i] = (process_buffer_t)pIn[2 * i] * REVERB_SEND_LEVEL;
+ pContext->InFrames[2 * i + 1] = (process_buffer_t)pIn[2 * i + 1] * REVERB_SEND_LEVEL;
#else
- pInputBuff[2 * i] = (LVM_FLOAT)pIn[2 * i] * REVERB_SEND_LEVEL / 32768.0f;
- pInputBuff[2 * i + 1] = (LVM_FLOAT)pIn[2 * i + 1] * REVERB_SEND_LEVEL / 32768.0f;
+ pContext->InFrames[2 * i] =
+ (process_buffer_t)pIn[2 * i] * REVERB_SEND_LEVEL / 32768.0f;
+ pContext->InFrames[2 * i + 1] =
+ (process_buffer_t)pIn[2 * i + 1] * REVERB_SEND_LEVEL / 32768.0f;
+#endif
+#else
+ pContext->InFrames[2*i] = (pIn[2*i] * REVERB_SEND_LEVEL) >> 4; // <<8 + >>12
+ pContext->InFrames[2*i+1] = (pIn[2*i+1] * REVERB_SEND_LEVEL) >> 4; // <<8 + >>12
#endif
}
}
if (pContext->preset && pContext->curPreset == REVERB_PRESET_NONE) {
-#ifdef BUILD_FLOAT
- memset(pOutputBuff, 0, frameCount * sizeof(LVM_FLOAT) * 2); //always stereo here
-#else
- memset(pContext->OutFrames32, 0, frameCount * sizeof(LVM_INT32) * 2); //always stereo here
-#endif
+ memset(pContext->OutFrames, 0,
+ frameCount * sizeof(*pContext->OutFrames) * FCC_2); //always stereo here
} else {
if(pContext->bEnabled == LVM_FALSE && pContext->SamplesToExitCount > 0) {
-#ifdef BUILD_FLOAT
- memset(pInputBuff, 0, frameCount * sizeof(LVM_FLOAT) * samplesPerFrame);
-#else
- memset(pContext->InFrames32,0,frameCount * sizeof(LVM_INT32) * samplesPerFrame);
-#endif
- ALOGV("\tZeroing %d samples per frame at the end of call", samplesPerFrame);
+ memset(pContext->InFrames, 0,
+ frameCount * sizeof(*pContext->OutFrames) * channels);
+ ALOGV("\tZeroing %d samples per frame at the end of call", channels);
}
/* Process the samples, producing a stereo output */
-#ifdef BUILD_FLOAT
LvmStatus = LVREV_Process(pContext->hInstance, /* Instance handle */
- pInputBuff, /* Input buffer */
- pOutputBuff, /* Output buffer */
+ pContext->InFrames, /* Input buffer */
+ pContext->OutFrames, /* Output buffer */
frameCount); /* Number of samples to read */
-#else
- LvmStatus = LVREV_Process(pContext->hInstance, /* Instance handle */
- pContext->InFrames32, /* Input buffer */
- pContext->OutFrames32, /* Output buffer */
- frameCount); /* Number of samples to read */
-#endif
- }
+ }
LVM_ERROR_CHECK(LvmStatus, "LVREV_Process", "process")
if(LvmStatus != LVREV_SUCCESS) return -EINVAL;
@@ -586,55 +472,89 @@
// Convert to 16 bits
if (pContext->auxiliary) {
#ifdef BUILD_FLOAT
- FloatToInt16_SAT(pOutputBuff, OutFrames16, (size_t)frameCount * 2);
+ // nothing to do here
+#ifndef NATIVE_FLOAT_BUFFER
+ // pContext->OutFrames and OutFrames16 point to the same buffer
+ // make sure the float to int conversion happens in the right order.
+ memcpy_to_i16_from_float(OutFrames16, pContext->OutFrames,
+ (size_t)frameCount * FCC_2);
+#endif
#else
- for (int i=0; i < frameCount*2; i++) { //always stereo here
- OutFrames16[i] = clamp16(pContext->OutFrames32[i]>>8);
+ for (int i = 0; i < frameCount * FCC_2; i++) { //always stereo here
+ OutFrames16[i] = clamp16(pContext->OutFrames[i]>>8);
}
#endif
- } else {
+ } else {
#ifdef BUILD_FLOAT
- for (int i = 0; i < frameCount * 2; i++) {//always stereo here
- //pOutputBuff and OutFrames16 point to the same buffer, so better to
- //accumulate in pInputBuff, which is available
- pInputBuff[i] = pOutputBuff[i] + (LVM_FLOAT)pIn[i] / 32768.0f;
- }
-
- FloatToInt16_SAT(pInputBuff, OutFrames16, (size_t)frameCount * 2);
+#ifdef NATIVE_FLOAT_BUFFER
+ for (int i = 0; i < frameCount * FCC_2; i++) { // always stereo here
+ // Mix with dry input
+ pContext->OutFrames[i] += pIn[i];
+ }
#else
- for (int i=0; i < frameCount*2; i++) { //always stereo here
- OutFrames16[i] = clamp16((pContext->OutFrames32[i]>>8) + (LVM_INT32)pIn[i]);
- }
+ for (int i = 0; i < frameCount * FCC_2; i++) { // always stereo here
+ // pOutputBuff and OutFrames16 point to the same buffer
+ // make sure the float to int conversion happens in the right order.
+ pContext->OutFrames[i] += (process_buffer_t)pIn[i] / 32768.0f;
+ }
+ memcpy_to_i16_from_float(OutFrames16, pContext->OutFrames,
+ (size_t)frameCount * FCC_2);
+#endif
+#else
+ for (int i=0; i < frameCount * FCC_2; i++) { // always stereo here
+ OutFrames16[i] = clamp16((pContext->OutFrames[i]>>8) + (process_buffer_t)pIn[i]);
+ }
#endif
// apply volume with ramp if needed
if ((pContext->leftVolume != pContext->prevLeftVolume ||
pContext->rightVolume != pContext->prevRightVolume) &&
pContext->volumeMode == REVERB_VOLUME_RAMP) {
+#if defined (BUILD_FLOAT) && defined (NATIVE_FLOAT_BUFFER)
+ // FIXME: still using int16 volumes.
+ // For reference: REVERB_UNIT_VOLUME (0x1000) // 1.0 in 4.12 format
+ float vl = (float)pContext->prevLeftVolume / 4096;
+ float incl = (((float)pContext->leftVolume / 4096) - vl) / frameCount;
+ float vr = (float)pContext->prevRightVolume / 4096;
+ float incr = (((float)pContext->rightVolume / 4096) - vr) / frameCount;
+
+ for (int i = 0; i < frameCount; i++) {
+ pContext->OutFrames[FCC_2 * i] *= vl;
+ pContext->OutFrames[FCC_2 * i + 1] *= vr;
+
+ vl += incl;
+ vr += incr;
+ }
+#else
LVM_INT32 vl = (LVM_INT32)pContext->prevLeftVolume << 16;
LVM_INT32 incl = (((LVM_INT32)pContext->leftVolume << 16) - vl) / frameCount;
LVM_INT32 vr = (LVM_INT32)pContext->prevRightVolume << 16;
LVM_INT32 incr = (((LVM_INT32)pContext->rightVolume << 16) - vr) / frameCount;
for (int i = 0; i < frameCount; i++) {
- OutFrames16[2*i] =
+ OutFrames16[FCC_2 * i] =
clamp16((LVM_INT32)((vl >> 16) * OutFrames16[2*i]) >> 12);
- OutFrames16[2*i+1] =
+ OutFrames16[FCC_2 * i + 1] =
clamp16((LVM_INT32)((vr >> 16) * OutFrames16[2*i+1]) >> 12);
vl += incl;
vr += incr;
}
-
+#endif
pContext->prevLeftVolume = pContext->leftVolume;
pContext->prevRightVolume = pContext->rightVolume;
} else if (pContext->volumeMode != REVERB_VOLUME_OFF) {
if (pContext->leftVolume != REVERB_UNIT_VOLUME ||
pContext->rightVolume != REVERB_UNIT_VOLUME) {
for (int i = 0; i < frameCount; i++) {
- OutFrames16[2*i] =
+#if defined(BUILD_FLOAT) && defined(NATIVE_FLOAT_BUFFER)
+ pContext->OutFrames[FCC_2 * i] *= ((float)pContext->leftVolume / 4096);
+ pContext->OutFrames[FCC_2 * i + 1] *= ((float)pContext->rightVolume / 4096);
+#else
+ OutFrames16[FCC_2 * i] =
clamp16((LVM_INT32)(pContext->leftVolume * OutFrames16[2*i]) >> 12);
- OutFrames16[2*i+1] =
+ OutFrames16[FCC_2 * i + 1] =
clamp16((LVM_INT32)(pContext->rightVolume * OutFrames16[2*i+1]) >> 12);
+#endif
}
}
pContext->prevLeftVolume = pContext->leftVolume;
@@ -643,20 +563,25 @@
}
}
- #ifdef LVM_PCM
- fwrite(OutFrames16, frameCount*sizeof(LVM_INT16)*2, 1, pContext->PcmOutPtr);
+#ifdef LVM_PCM
+ fwrite(pContext->OutFrames, frameCount * sizeof(*pContext->OutFrames) * FCC_2,
+ 1 /* nmemb */, pContext->PcmOutPtr);
fflush(pContext->PcmOutPtr);
- #endif
+#endif
// Accumulate if required
if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE){
//ALOGV("\tBuffer access is ACCUMULATE");
- for (int i=0; i<frameCount*2; i++){ //always stereo here
+ for (int i = 0; i < frameCount * FCC_2; i++) { // always stereo here
+#ifndef NATIVE_FLOAT_BUFFER
pOut[i] = clamp16((int32_t)pOut[i] + (int32_t)OutFrames16[i]);
+#else
+ pOut[i] += pContext->OutFrames[i];
+#endif
}
}else{
//ALOGV("\tBuffer access is WRITE");
- memcpy(pOut, OutFrames16, frameCount*sizeof(LVM_INT16)*2);
+ memcpy(pOut, pContext->OutFrames, frameCount * sizeof(*pOut) * FCC_2);
}
return 0;
@@ -733,8 +658,7 @@
CHECK_ARG(pConfig->outputCfg.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_16_BIT);
-
+ CHECK_ARG(pConfig->inputCfg.format == EFFECT_BUFFER_FORMAT);
//ALOGV("\tReverb_setConfig calling memcpy");
pContext->config = *pConfig;
@@ -847,8 +771,7 @@
} else {
pContext->config.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
}
-
- pContext->config.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+ pContext->config.inputCfg.format = EFFECT_BUFFER_FORMAT;
pContext->config.inputCfg.samplingRate = 44100;
pContext->config.inputCfg.bufferProvider.getBuffer = NULL;
pContext->config.inputCfg.bufferProvider.releaseBuffer = NULL;
@@ -856,7 +779,7 @@
pContext->config.inputCfg.mask = EFFECT_CONFIG_ALL;
pContext->config.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE;
pContext->config.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
- pContext->config.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+ pContext->config.outputCfg.format = EFFECT_BUFFER_FORMAT;
pContext->config.outputCfg.samplingRate = 44100;
pContext->config.outputCfg.bufferProvider.getBuffer = NULL;
pContext->config.outputCfg.bufferProvider.releaseBuffer = NULL;
@@ -2031,10 +1954,17 @@
}
//ALOGV("\tReverb_process() Calling process with %d frames", outBuffer->frameCount);
/* Process all the available frames, block processing is handled internalLY by the LVM bundle */
- status = process( (LVM_INT16 *)inBuffer->raw,
- (LVM_INT16 *)outBuffer->raw,
- outBuffer->frameCount,
- pContext);
+#if defined (BUILD_FLOAT) && defined (NATIVE_FLOAT_BUFFER)
+ status = process( inBuffer->f32,
+ outBuffer->f32,
+ outBuffer->frameCount,
+ pContext);
+#else
+ status = process( inBuffer->s16,
+ outBuffer->s16,
+ outBuffer->frameCount,
+ pContext);
+#endif
if (pContext->bEnabled == LVM_FALSE) {
if (pContext->SamplesToExitCount > 0) {
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 7e9ef26..506420c 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -526,6 +526,13 @@
};
// --- PlaybackThread ---
+#ifdef FLOAT_EFFECT_CHAIN
+#define EFFECT_BUFFER_FORMAT AUDIO_FORMAT_PCM_FLOAT
+using effect_buffer_t = float;
+#else
+#define EFFECT_BUFFER_FORMAT AUDIO_FORMAT_PCM_16_BIT
+using effect_buffer_t = int16_t;
+#endif
#include "Threads.h"
diff --git a/services/audioflinger/Configuration.h b/services/audioflinger/Configuration.h
index 845697a..bad46dc 100644
--- a/services/audioflinger/Configuration.h
+++ b/services/audioflinger/Configuration.h
@@ -41,4 +41,7 @@
// uncomment to log CPU statistics every n wall clock seconds
//#define DEBUG_CPU_USAGE 10
+// define FLOAT_EFFECT_CHAIN to request float effects (falls back to int16_t if unavailable)
+#define FLOAT_EFFECT_CHAIN
+
#endif // ANDROID_AUDIOFLINGER_CONFIGURATION_H
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index bd5f146..9717075 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -19,6 +19,8 @@
#define LOG_TAG "AudioFlinger"
//#define LOG_NDEBUG 0
+#include <algorithm>
+
#include "Configuration.h"
#include <utils/Log.h>
#include <system/audio_effects/effect_aec.h>
@@ -47,8 +49,6 @@
#define ALOGVV(a...) do { } while(0)
#endif
-#define min(a, b) ((a) < (b) ? (a) : (b))
-
namespace android {
// ----------------------------------------------------------------------------
@@ -73,6 +73,9 @@
// mDisableWaitCnt is set by process() and updateState() and not used before then
mSuspended(false),
mAudioFlinger(thread->mAudioFlinger)
+#ifdef FLOAT_EFFECT_CHAIN
+ , mSupportsFloat(false)
+#endif
{
ALOGV("Constructor %p pinned %d", this, pinned);
int lStatus;
@@ -285,31 +288,116 @@
return;
}
+ // TODO: Implement multichannel effects; here outChannelCount == FCC_2 == 2
+ const uint32_t inChannelCount =
+ audio_channel_count_from_out_mask(mConfig.inputCfg.channels);
+ const uint32_t outChannelCount =
+ audio_channel_count_from_out_mask(mConfig.outputCfg.channels);
+ const bool auxType =
+ (mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY;
+
if (isProcessEnabled()) {
- // do 32 bit to 16 bit conversion for auxiliary effect input buffer
- if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
- ditherAndClamp(mConfig.inputCfg.buffer.s32,
- mConfig.inputCfg.buffer.s32,
- mConfig.inputCfg.buffer.frameCount/2);
- }
int ret;
if (isProcessImplemented()) {
- // do the actual processing in the effect engine
+ if (auxType) {
+ // We overwrite the aux input buffer here and clear after processing.
+ // Note that aux input buffers are format q4_27.
+#ifdef FLOAT_EFFECT_CHAIN
+ if (mSupportsFloat) {
+ // Do in-place float conversion for auxiliary effect input buffer.
+ static_assert(sizeof(float) <= sizeof(int32_t),
+ "in-place conversion requires sizeof(float) <= sizeof(int32_t)");
+
+ const int32_t * const p32 = mConfig.inputCfg.buffer.s32;
+ float * const pFloat = mConfig.inputCfg.buffer.f32;
+ memcpy_to_float_from_q4_27(pFloat, p32, mConfig.inputCfg.buffer.frameCount);
+ } else {
+ const size_t pairs = mConfig.inputCfg.buffer.frameCount / 2;
+ ditherAndClamp(mConfig.inputCfg.buffer.s32,
+ mConfig.inputCfg.buffer.s32,
+ pairs);
+ }
+#else
+ const size_t pairs = mConfig.inputCfg.buffer.frameCount / 2;
+ ditherAndClamp(mConfig.inputCfg.buffer.s32,
+ mConfig.inputCfg.buffer.s32,
+ pairs);
+#endif
+ }
+#ifdef FLOAT_EFFECT_CHAIN
+ if (mSupportsFloat) {
+ ret = mEffectInterface->process();
+ } else {
+ { // convert input to int16_t as effect doesn't support float.
+ if (!auxType) {
+ if (mInBuffer16.get() == nullptr) {
+ ALOGW("%s: mInBuffer16 is null, bypassing", __func__);
+ goto data_bypass;
+ }
+ const float * const pIn = mInBuffer->audioBuffer()->f32;
+ int16_t * const pIn16 = mInBuffer16->audioBuffer()->s16;
+ memcpy_to_i16_from_float(
+ pIn16, pIn, inChannelCount * mConfig.inputCfg.buffer.frameCount);
+ }
+ if (mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
+ if (mOutBuffer16.get() == nullptr) {
+ ALOGW("%s: mOutBuffer16 is null, bypassing", __func__);
+ goto data_bypass;
+ }
+ int16_t * const pOut16 = mOutBuffer16->audioBuffer()->s16;
+ const float * const pOut = mOutBuffer->audioBuffer()->f32;
+ memcpy_to_i16_from_float(
+ pOut16,
+ pOut,
+ outChannelCount * mConfig.outputCfg.buffer.frameCount);
+ }
+ }
+
+ ret = mEffectInterface->process();
+
+ { // convert output back to float.
+ const int16_t * const pOut16 = mOutBuffer16->audioBuffer()->s16;
+ float * const pOut = mOutBuffer->audioBuffer()->f32;
+ memcpy_to_float_from_i16(
+ pOut, pOut16, outChannelCount * mConfig.outputCfg.buffer.frameCount);
+ }
+ }
+#else
ret = mEffectInterface->process();
+#endif
} else {
- if (mConfig.inputCfg.buffer.raw != mConfig.outputCfg.buffer.raw) {
- size_t frameCnt = mConfig.inputCfg.buffer.frameCount * FCC_2; //always stereo here
- int16_t *in = mConfig.inputCfg.buffer.s16;
- int16_t *out = mConfig.outputCfg.buffer.s16;
+#ifdef FLOAT_EFFECT_CHAIN
+ data_bypass:
+#endif
+ if (!auxType /* aux effects do not require data bypass */
+ && mConfig.inputCfg.buffer.raw != mConfig.outputCfg.buffer.raw
+ && inChannelCount == outChannelCount) {
+ const size_t sampleCount = std::min(
+ mConfig.inputCfg.buffer.frameCount,
+ mConfig.outputCfg.buffer.frameCount) * outChannelCount;
+
+#ifdef FLOAT_EFFECT_CHAIN
+ const float * const in = mConfig.inputCfg.buffer.f32;
+ float * const out = mConfig.outputCfg.buffer.f32;
if (mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
- for (size_t i = 0; i < frameCnt; i++) {
- out[i] = clamp16((int32_t)out[i] + (int32_t)in[i]);
- }
+ accumulate_float(out, in, sampleCount);
} else {
- memcpy(mConfig.outputCfg.buffer.raw, mConfig.inputCfg.buffer.raw,
- frameCnt * sizeof(int16_t));
+ memcpy(mConfig.outputCfg.buffer.f32, mConfig.inputCfg.buffer.f32,
+ sampleCount * sizeof(*mConfig.outputCfg.buffer.f32));
}
+
+#else
+ const int16_t * const in = mConfig.inputCfg.buffer.s16;
+ int16_t * const out = mConfig.outputCfg.buffer.s16;
+
+ if (mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
+ accumulate_i16(out, in, sampleCount);
+ } else {
+ memcpy(mConfig.outputCfg.buffer.s16, mConfig.inputCfg.buffer.s16,
+ sampleCount * sizeof(*mConfig.outputCfg.buffer.s16));
+ }
+#endif
}
ret = -ENODATA;
}
@@ -319,22 +407,33 @@
}
// clear auxiliary effect input buffer for next accumulation
- if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
- memset(mConfig.inputCfg.buffer.raw, 0,
- mConfig.inputCfg.buffer.frameCount*sizeof(int32_t));
+ if (auxType) {
+ // input always q4_27 regardless of FLOAT_EFFECT_CHAIN.
+ const size_t size =
+ mConfig.inputCfg.buffer.frameCount * inChannelCount * sizeof(int32_t);
+ memset(mConfig.inputCfg.buffer.raw, 0, size);
}
} else if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_INSERT &&
+ // mInBuffer->audioBuffer()->raw != mOutBuffer->audioBuffer()->raw
mConfig.inputCfg.buffer.raw != mConfig.outputCfg.buffer.raw) {
// If an insert effect is idle and input buffer is different from output buffer,
// accumulate input onto output
sp<EffectChain> chain = mChain.promote();
- if (chain != 0 && chain->activeTrackCnt() != 0) {
- size_t frameCnt = mConfig.inputCfg.buffer.frameCount * FCC_2; //always stereo here
- int16_t *in = mConfig.inputCfg.buffer.s16;
- int16_t *out = mConfig.outputCfg.buffer.s16;
- for (size_t i = 0; i < frameCnt; i++) {
- out[i] = clamp16((int32_t)out[i] + (int32_t)in[i]);
- }
+ if (chain != 0
+ && chain->activeTrackCnt() != 0
+ && inChannelCount == outChannelCount) {
+ const size_t sampleCount = std::min(
+ mConfig.inputCfg.buffer.frameCount,
+ mConfig.outputCfg.buffer.frameCount) * outChannelCount;
+#ifdef FLOAT_EFFECT_CHAIN
+ const float * const in = mConfig.inputCfg.buffer.f32;
+ float * const out = mConfig.outputCfg.buffer.f32;
+ accumulate_float(out, in, sampleCount);
+#else
+ const int16_t * const in = mConfig.inputCfg.buffer.s16;
+ int16_t * const out = mConfig.outputCfg.buffer.s16;
+ accumulate_i16(out, in, sampleCount);
+#endif
}
}
}
@@ -349,6 +448,7 @@
status_t AudioFlinger::EffectModule::configure()
{
+ ALOGVV("configure() started");
status_t status;
sp<ThreadBase> thread;
uint32_t size;
@@ -384,8 +484,8 @@
}
}
- mConfig.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
- mConfig.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+ mConfig.inputCfg.format = EFFECT_BUFFER_FORMAT;
+ mConfig.outputCfg.format = EFFECT_BUFFER_FORMAT;
mConfig.inputCfg.samplingRate = thread->sampleRate();
mConfig.outputCfg.samplingRate = mConfig.inputCfg.samplingRate;
mConfig.inputCfg.bufferProvider.cookie = NULL;
@@ -413,12 +513,6 @@
mConfig.outputCfg.mask = EFFECT_CONFIG_ALL;
mConfig.inputCfg.buffer.frameCount = thread->frameCount();
mConfig.outputCfg.buffer.frameCount = mConfig.inputCfg.buffer.frameCount;
- if (mInBuffer != 0) {
- mInBuffer->setFrameCount(mConfig.inputCfg.buffer.frameCount);
- }
- if (mOutBuffer != 0) {
- mOutBuffer->setFrameCount(mConfig.outputCfg.buffer.frameCount);
- }
ALOGV("configure() %p thread %p buffer %p framecount %zu",
this, thread.get(), mConfig.inputCfg.buffer.raw, mConfig.inputCfg.buffer.frameCount);
@@ -430,32 +524,60 @@
&mConfig,
&size,
&cmdStatus);
- if (status == 0) {
+ if (status == NO_ERROR) {
status = cmdStatus;
+#ifdef FLOAT_EFFECT_CHAIN
+ mSupportsFloat = true;
+#endif
}
-
- if (status == 0 &&
- (memcmp(&mDescriptor.type, SL_IID_VISUALIZATION, sizeof(effect_uuid_t)) == 0)) {
- uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
- effect_param_t *p = (effect_param_t *)buf32;
-
- p->psize = sizeof(uint32_t);
- p->vsize = sizeof(uint32_t);
- size = sizeof(int);
- *(int32_t *)p->data = VISUALIZER_PARAM_LATENCY;
-
- uint32_t latency = 0;
- PlaybackThread *pbt = thread->mAudioFlinger->checkPlaybackThread_l(thread->mId);
- if (pbt != NULL) {
- latency = pbt->latency_l();
+#ifdef FLOAT_EFFECT_CHAIN
+ else {
+ ALOGV("EFFECT_CMD_SET_CONFIG failed with float format, retry with int16_t.");
+ mConfig.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+ mConfig.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+ status = mEffectInterface->command(EFFECT_CMD_SET_CONFIG,
+ sizeof(effect_config_t),
+ &mConfig,
+ &size,
+ &cmdStatus);
+ if (status == NO_ERROR) {
+ status = cmdStatus;
+ mSupportsFloat = false;
+ ALOGVV("config worked with 16 bit");
+ } else {
+ ALOGE("%s failed %d with int16_t (as well as float)", __func__, status);
}
+ }
+#endif
- *((int32_t *)p->data + 1)= latency;
- mEffectInterface->command(EFFECT_CMD_SET_PARAM,
- sizeof(effect_param_t) + 8,
- &buf32,
- &size,
- &cmdStatus);
+ if (status == NO_ERROR) {
+ // Establish Buffer strategy
+ setInBuffer(mInBuffer);
+ setOutBuffer(mOutBuffer);
+
+ // Update visualizer latency
+ if (memcmp(&mDescriptor.type, SL_IID_VISUALIZATION, sizeof(effect_uuid_t)) == 0) {
+ uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
+ effect_param_t *p = (effect_param_t *)buf32;
+
+ p->psize = sizeof(uint32_t);
+ p->vsize = sizeof(uint32_t);
+ size = sizeof(int);
+ *(int32_t *)p->data = VISUALIZER_PARAM_LATENCY;
+
+ uint32_t latency = 0;
+ PlaybackThread *pbt = thread->mAudioFlinger->checkPlaybackThread_l(thread->mId);
+ if (pbt != NULL) {
+ latency = pbt->latency_l();
+ }
+
+ *((int32_t *)p->data + 1)= latency;
+ mEffectInterface->command(EFFECT_CMD_SET_PARAM,
+ sizeof(effect_param_t) + 8,
+ &buf32,
+ &size,
+ &cmdStatus);
+ }
}
mMaxDisableWaitCnt = (MAX_DISABLE_TIME_MS * mConfig.outputCfg.samplingRate) /
@@ -463,6 +585,7 @@
exit:
mStatus = status;
+ ALOGVV("configure ended");
return status;
}
@@ -774,6 +897,7 @@
}
void AudioFlinger::EffectModule::setInBuffer(const sp<EffectBufferHalInterface>& buffer) {
+ ALOGVV("setInBuffer %p",(&buffer));
if (buffer != 0) {
mConfig.inputCfg.buffer.raw = buffer->audioBuffer()->raw;
buffer->setFrameCount(mConfig.inputCfg.buffer.frameCount);
@@ -781,10 +905,43 @@
mConfig.inputCfg.buffer.raw = NULL;
}
mInBuffer = buffer;
- mEffectInterface->setInBuffer(buffer);
+ if (buffer != nullptr) { // FIXME: EffectHalHidl::setInBuffer should accept null input.
+ mEffectInterface->setInBuffer(buffer);
+ }
+
+#ifdef FLOAT_EFFECT_CHAIN
+ // aux effects do in place conversion to float - we don't allocate mInBuffer16 for them.
+ // Theoretically insert effects can also do in-place conversions (destroying
+ // the original buffer) when the output buffer is identical to the input buffer,
+ // but we don't optimize for it here.
+ const bool auxType = (mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY;
+ if (!auxType && !mSupportsFloat && mInBuffer.get() != nullptr) {
+ // we need to translate - create hidl shared buffer and intercept
+ const size_t inFrameCount = mConfig.inputCfg.buffer.frameCount;
+ const int inChannels = audio_channel_count_from_out_mask(mConfig.inputCfg.channels);
+ const size_t size = inChannels * inFrameCount * sizeof(int16_t);
+
+ ALOGV("%s: setInBuffer updating for inChannels:%d inFrameCount:%zu total size:%zu",
+ __func__, inChannels, inFrameCount, size);
+
+ if (size > 0 && (mInBuffer16.get() == nullptr || size > mInBuffer16->getSize())) {
+ mInBuffer16.clear();
+ ALOGV("%s: allocating mInBuffer16 %zu", __func__, size);
+ (void)EffectBufferHalInterface::allocate(size, &mInBuffer16);
+ }
+ if (mInBuffer16.get() != nullptr) {
+ // FIXME: confirm buffer has enough size.
+ mInBuffer16->setFrameCount(inFrameCount);
+ mEffectInterface->setInBuffer(mInBuffer16);
+ } else if (size > 0) {
+ ALOGE("%s cannot create mInBuffer16", __func__);
+ }
+ }
+#endif
}
void AudioFlinger::EffectModule::setOutBuffer(const sp<EffectBufferHalInterface>& buffer) {
+ ALOGVV("setOutBuffer %p",(&buffer));
if (buffer != 0) {
mConfig.outputCfg.buffer.raw = buffer->audioBuffer()->raw;
buffer->setFrameCount(mConfig.outputCfg.buffer.frameCount);
@@ -792,7 +949,34 @@
mConfig.outputCfg.buffer.raw = NULL;
}
mOutBuffer = buffer;
- mEffectInterface->setOutBuffer(buffer);
+ if (buffer != nullptr) {
+ mEffectInterface->setOutBuffer(buffer);
+ }
+
+#ifdef FLOAT_EFFECT_CHAIN
+ // Note: Any effect that does not accumulate does not need mOutBuffer16 and
+ // can do in-place conversion from int16_t to float. We don't optimize here.
+ if (!mSupportsFloat && mOutBuffer.get() != nullptr) {
+ const size_t outFrameCount = mConfig.outputCfg.buffer.frameCount;
+ const int outChannels = audio_channel_count_from_out_mask(mConfig.outputCfg.channels);
+ const size_t size = outChannels * outFrameCount * sizeof(int16_t);
+
+ ALOGV("%s: setOutBuffer updating for outChannels:%d outFrameCount:%zu total size:%zu",
+ __func__, outChannels, outFrameCount, size);
+
+ if (size > 0 && (mOutBuffer16.get() == nullptr || size > mOutBuffer16->getSize())) {
+ mOutBuffer16.clear();
+ ALOGV("%s: allocating mOutBuffer16 %zu", __func__, size);
+ (void)EffectBufferHalInterface::allocate(size, &mOutBuffer16);
+ }
+ if (mOutBuffer16.get() != nullptr) {
+ mOutBuffer16->setFrameCount(outFrameCount);
+ mEffectInterface->setOutBuffer(mOutBuffer16);
+ } else if (size > 0) {
+ ALOGE("%s cannot create mOutBuffer16", __func__);
+ }
+ }
+#endif
}
status_t AudioFlinger::EffectModule::setVolume(uint32_t *left, uint32_t *right, bool controller)
@@ -1126,6 +1310,22 @@
formatToString((audio_format_t)mConfig.outputCfg.format).c_str());
result.append(buffer);
+#ifdef FLOAT_EFFECT_CHAIN
+ if (!mSupportsFloat) {
+ int16_t* pIn16 = mInBuffer16 != 0 ? mInBuffer16->audioBuffer()->s16 : NULL;
+ int16_t* pOut16 = mOutBuffer16 != 0 ? mOutBuffer16->audioBuffer()->s16 : NULL;
+
+ result.append("\t\t- Float and int16 buffers\n");
+ result.append("\t\t\tIn_float In_int16 Out_float Out_int16\n");
+ snprintf(buffer, SIZE,"\t\t\t%p %p %p %p\n",
+ mConfig.inputCfg.buffer.raw,
+ pIn16,
+ pOut16,
+ mConfig.outputCfg.buffer.raw);
+ result.append(buffer);
+ }
+#endif
+
snprintf(buffer, SIZE, "\t\t%zu Clients:\n", mHandles.size());
result.append(buffer);
result.append("\t\t\t Pid Priority Ctrl Locked client server\n");
@@ -1602,8 +1802,11 @@
// and sample format changes for effects.
// Currently effects processing is only available for stereo, AUDIO_FORMAT_PCM_16_BIT
// (4 bytes frame size)
+
const size_t frameSize =
- audio_bytes_per_sample(AUDIO_FORMAT_PCM_16_BIT) * min(FCC_2, thread->channelCount());
+ audio_bytes_per_sample(EFFECT_BUFFER_FORMAT)
+ * std::min((uint32_t)FCC_2, thread->channelCount());
+
memset(mInBuffer->audioBuffer()->raw, 0, thread->frameCount() * frameSize);
mInBuffer->commit();
}
@@ -1718,8 +1921,13 @@
// calling the process in effect engine
size_t numSamples = thread->frameCount();
sp<EffectBufferHalInterface> halBuffer;
+#ifdef FLOAT_EFFECT_CHAIN
+ status_t result = EffectBufferHalInterface::allocate(
+ numSamples * sizeof(float), &halBuffer);
+#else
status_t result = EffectBufferHalInterface::allocate(
numSamples * sizeof(int32_t), &halBuffer);
+#endif
if (result != OK) return result;
effect->setInBuffer(halBuffer);
// auxiliary effects output samples to chain input buffer for further processing
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index e29798b..1864e0f 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -168,6 +168,12 @@
bool mSuspended; // effect is suspended: temporarily disabled by framework
bool mOffloaded; // effect is currently offloaded to the audio DSP
wp<AudioFlinger> mAudioFlinger;
+
+#ifdef FLOAT_EFFECT_CHAIN
+ bool mSupportsFloat; // effect supports float processing
+ sp<EffectBufferHalInterface> mInBuffer16; // Buffers for interacting with HAL at 16 bits
+ sp<EffectBufferHalInterface> mOutBuffer16;
+#endif
};
// The EffectHandle class implements the IEffect interface. It provides resources
@@ -308,14 +314,14 @@
void setInBuffer(const sp<EffectBufferHalInterface>& buffer) {
mInBuffer = buffer;
}
- int16_t *inBuffer() const {
- return mInBuffer != 0 ? reinterpret_cast<int16_t*>(mInBuffer->ptr()) : NULL;
+ effect_buffer_t *inBuffer() const {
+ return mInBuffer != 0 ? reinterpret_cast<effect_buffer_t*>(mInBuffer->ptr()) : NULL;
}
void setOutBuffer(const sp<EffectBufferHalInterface>& buffer) {
mOutBuffer = buffer;
}
- int16_t *outBuffer() const {
- return mOutBuffer != 0 ? reinterpret_cast<int16_t*>(mOutBuffer->ptr()) : NULL;
+ effect_buffer_t *outBuffer() const {
+ return mOutBuffer != 0 ? reinterpret_cast<effect_buffer_t*>(mOutBuffer->ptr()) : NULL;
}
void incTrackCnt() { android_atomic_inc(&mTrackCnt); }
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index 946d88f..e97bb06 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -68,8 +68,8 @@
status_t attachAuxEffect(int EffectId);
void setAuxBuffer(int EffectId, int32_t *buffer);
int32_t *auxBuffer() const { return mAuxBuffer; }
- void setMainBuffer(int16_t *buffer) { mMainBuffer = buffer; }
- int16_t *mainBuffer() const { return mMainBuffer; }
+ void setMainBuffer(effect_buffer_t *buffer) { mMainBuffer = buffer; }
+ effect_buffer_t *mainBuffer() const { return mMainBuffer; }
int auxEffectId() const { return mAuxEffectId; }
virtual status_t getTimestamp(AudioTimestamp& timestamp);
void signal();
@@ -150,7 +150,8 @@
// allocated statically at track creation time,
// and is even allocated (though unused) for fast tracks
// FIXME don't allocate track name for fast tracks
- int16_t *mMainBuffer;
+ effect_buffer_t *mMainBuffer;
+
int32_t *mAuxBuffer;
int mAuxEffectId;
bool mHasVolumeController;
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 8e6c720..b2a1e18 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -2537,7 +2537,7 @@
free(mEffectBuffer);
mEffectBuffer = NULL;
if (mEffectBufferEnabled) {
- mEffectBufferFormat = AUDIO_FORMAT_PCM_16_BIT; // Note: Effects support 16b only
+ mEffectBufferFormat = EFFECT_BUFFER_FORMAT;
mEffectBufferSize = mNormalFrameCount * mChannelCount
* audio_bytes_per_sample(mEffectBufferFormat);
(void)posix_memalign(&mEffectBuffer, 32, mEffectBufferSize);
@@ -2884,8 +2884,7 @@
&halInBuffer);
if (result != OK) return result;
halOutBuffer = halInBuffer;
- int16_t *buffer = reinterpret_cast<int16_t*>(halInBuffer->externalData());
-
+ effect_buffer_t *buffer = reinterpret_cast<effect_buffer_t*>(halInBuffer->externalData());
ALOGV("addEffectChain_l() %p on thread %p for session %d", chain.get(), this, session);
if (session > AUDIO_SESSION_OUTPUT_MIX) {
// Only one effect chain can be present in direct output thread and it uses
@@ -2893,10 +2892,14 @@
if (mType != DIRECT) {
size_t numSamples = mNormalFrameCount * mChannelCount;
status_t result = EffectBufferHalInterface::allocate(
- numSamples * sizeof(int16_t),
+ numSamples * sizeof(effect_buffer_t),
&halInBuffer);
if (result != OK) return result;
+#ifdef FLOAT_EFFECT_CHAIN
+ buffer = halInBuffer->audioBuffer()->f32;
+#else
buffer = halInBuffer->audioBuffer()->s16;
+#endif
ALOGV("addEffectChain_l() creating new input buffer %p session %d",
buffer, session);
}
@@ -2971,7 +2974,7 @@
for (size_t i = 0; i < mTracks.size(); ++i) {
sp<Track> track = mTracks[i];
if (session == track->sessionId()) {
- track->setMainBuffer(reinterpret_cast<int16_t*>(mSinkBuffer));
+ track->setMainBuffer(reinterpret_cast<effect_buffer_t*>(mSinkBuffer));
chain->decTrackCnt();
}
}
@@ -4554,7 +4557,7 @@
mAudioMixer->setParameter(
name,
AudioMixer::TRACK,
- AudioMixer::MIXER_FORMAT, (void *)AUDIO_FORMAT_PCM_16_BIT);
+ AudioMixer::MIXER_FORMAT, (void *)EFFECT_BUFFER_FORMAT);
mAudioMixer->setParameter(
name,
AudioMixer::TRACK,
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 2ca273f..c7b60d6 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -741,11 +741,10 @@
virtual String8 getParameters(const String8& keys);
virtual void ioConfigChanged(audio_io_config_event event, pid_t pid = 0);
status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames);
- // FIXME rename mixBuffer() to sinkBuffer() and remove int16_t* dependency.
// Consider also removing and passing an explicit mMainBuffer initialization
// parameter to AF::PlaybackThread::Track::Track().
- int16_t *mixBuffer() const {
- return reinterpret_cast<int16_t *>(mSinkBuffer); };
+ effect_buffer_t *sinkBuffer() const {
+ return reinterpret_cast<effect_buffer_t *>(mSinkBuffer); };
virtual void detachAuxEffect_l(int effectId);
status_t attachAuxEffect(const sp<AudioFlinger::PlaybackThread::Track>& track,
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 50c0e23..1445572 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -395,7 +395,7 @@
mSharedBuffer(sharedBuffer),
mStreamType(streamType),
mName(-1), // see note below
- mMainBuffer(thread->mixBuffer()),
+ mMainBuffer(thread->sinkBuffer()),
mAuxBuffer(NULL),
mAuxEffectId(0), mHasVolumeController(false),
mPresentationCompleteFrames(0),
diff --git a/services/oboeservice/AAudioMixer.cpp b/services/oboeservice/AAudioMixer.cpp
index 57241a1..b031888 100644
--- a/services/oboeservice/AAudioMixer.cpp
+++ b/services/oboeservice/AAudioMixer.cpp
@@ -49,7 +49,7 @@
memset(mOutputBuffer, 0, mBufferSizeInBytes);
}
-bool AAudioMixer::mix(int streamIndex, FifoBuffer *fifo, bool allowUnderflow) {
+int32_t AAudioMixer::mix(int streamIndex, FifoBuffer *fifo, bool allowUnderflow) {
WrappingBuffer wrappingBuffer;
float *destination = mOutputBuffer;
@@ -105,7 +105,7 @@
ATRACE_END();
#endif /* AAUDIO_MIXER_ATRACE_ENABLED */
- return (framesLeft > 0); // did not get all the frames we needed, ie. "underflow"
+ return (framesDesired - framesLeft); // framesRead
}
void AAudioMixer::mixPart(float *destination, float *source, int32_t numFrames) {
diff --git a/services/oboeservice/AAudioMixer.h b/services/oboeservice/AAudioMixer.h
index 5625d4d..d5abc5b 100644
--- a/services/oboeservice/AAudioMixer.h
+++ b/services/oboeservice/AAudioMixer.h
@@ -36,15 +36,17 @@
* @param streamIndex for marking stream variables in systrace
* @param fifo to read from
* @param allowUnderflow if true then allow mixer to advance read index past the write index
- * @return true if actually underflowed
+ * @return frames read from this stream
*/
- bool mix(int streamIndex, android::FifoBuffer *fifo, bool allowUnderflow);
-
- void mixPart(float *destination, float *source, int32_t numFrames);
+ int32_t mix(int streamIndex, android::FifoBuffer *fifo, bool allowUnderflow);
float *getOutputBuffer();
+ int32_t getFramesPerBurst() const { return mFramesPerBurst; }
+
private:
+ void mixPart(float *destination, float *source, int32_t numFrames);
+
float *mOutputBuffer = nullptr;
int32_t mSamplesPerFrame = 0;
int32_t mFramesPerBurst = 0;
diff --git a/services/oboeservice/AAudioServiceEndpointCapture.cpp b/services/oboeservice/AAudioServiceEndpointCapture.cpp
index f902bef..efac788 100644
--- a/services/oboeservice/AAudioServiceEndpointCapture.cpp
+++ b/services/oboeservice/AAudioServiceEndpointCapture.cpp
@@ -58,7 +58,6 @@
// Read data from the shared MMAP stream and then distribute it to the client streams.
void *AAudioServiceEndpointCapture::callbackLoop() {
ALOGD("callbackLoop() entering");
- int32_t underflowCount = 0;
aaudio_result_t result = AAUDIO_OK;
int64_t timeoutNanos = getStreamInternal()->calculateReasonableTimeout();
@@ -102,9 +101,10 @@
int64_t positionOffset = mmapFramesRead - clientFramesWritten;
streamShared->setTimestampPositionOffset(positionOffset);
+ // Is the buffer too full to write a burst?
if (fifo->getFifoControllerBase()->getEmptyFramesAvailable() <
- getFramesPerBurst()) {
- underflowCount++;
+ getFramesPerBurst()) {
+ streamShared->incrementXRunCount();
} else {
fifo->write(mDistributionBuffer, getFramesPerBurst());
}
@@ -125,6 +125,6 @@
}
}
- ALOGD("callbackLoop() exiting, %d underflows", underflowCount);
+ ALOGD("callbackLoop() exiting");
return NULL; // TODO review
}
diff --git a/services/oboeservice/AAudioServiceEndpointPlay.cpp b/services/oboeservice/AAudioServiceEndpointPlay.cpp
index c2feb6b..2601f3f 100644
--- a/services/oboeservice/AAudioServiceEndpointPlay.cpp
+++ b/services/oboeservice/AAudioServiceEndpointPlay.cpp
@@ -34,6 +34,7 @@
#include "AAudioServiceStreamShared.h"
#include "AAudioServiceEndpointPlay.h"
#include "AAudioServiceEndpointShared.h"
+#include "AAudioServiceStreamBase.h"
using namespace android; // TODO just import names needed
using namespace aaudio; // TODO just import names needed
@@ -108,9 +109,19 @@
int64_t positionOffset = mmapFramesWritten - clientFramesRead;
streamShared->setTimestampPositionOffset(positionOffset);
- bool underflowed = mMixer.mix(index, fifo, allowUnderflow);
- if (underflowed) {
- streamShared->incrementXRunCount();
+ int32_t framesMixed = mMixer.mix(index, fifo, allowUnderflow);
+
+ if (streamShared->isFlowing()) {
+ // Consider it an underflow if we got less than a burst
+ // after the data started flowing.
+ bool underflowed = allowUnderflow
+ && framesMixed < mMixer.getFramesPerBurst();
+ if (underflowed) {
+ streamShared->incrementXRunCount();
+ }
+ } else if (framesMixed > 0) {
+ // Mark beginning of data flow after a start.
+ streamShared->setFlowing(true);
}
clientFramesRead = fifo->getReadCounter();
}
diff --git a/services/oboeservice/AAudioServiceEndpointShared.cpp b/services/oboeservice/AAudioServiceEndpointShared.cpp
index 820ed28..6af9e7e 100644
--- a/services/oboeservice/AAudioServiceEndpointShared.cpp
+++ b/services/oboeservice/AAudioServiceEndpointShared.cpp
@@ -47,6 +47,7 @@
<< std::setfill('0') << std::setw(8)
<< std::hex << mStreamInternal->getServiceHandle()
<< std::dec << std::setfill(' ');
+ result << ", XRuns = " << mStreamInternal->getXRunCount();
result << "\n";
result << " Running Stream Count: " << mRunningStreamCount << "\n";
diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp
index 6652cc9..635b45c 100644
--- a/services/oboeservice/AAudioServiceStreamBase.cpp
+++ b/services/oboeservice/AAudioServiceStreamBase.cpp
@@ -172,6 +172,8 @@
goto error;
}
+ setFlowing(false);
+
// Start with fresh presentation timestamps.
mAtomicTimestamp.clear();
@@ -311,12 +313,19 @@
}
aaudio_result_t AAudioServiceStreamBase::sendServiceEvent(aaudio_service_event_t event,
- double dataDouble,
- int64_t dataLong) {
+ double dataDouble) {
AAudioServiceMessage command;
command.what = AAudioServiceMessage::code::EVENT;
command.event.event = event;
command.event.dataDouble = dataDouble;
+ return writeUpMessageQueue(&command);
+}
+
+aaudio_result_t AAudioServiceStreamBase::sendServiceEvent(aaudio_service_event_t event,
+ int64_t dataLong) {
+ AAudioServiceMessage command;
+ command.what = AAudioServiceMessage::code::EVENT;
+ command.event.event = event;
command.event.dataLong = dataLong;
return writeUpMessageQueue(&command);
}
@@ -336,6 +345,10 @@
}
}
+aaudio_result_t AAudioServiceStreamBase::sendXRunCount(int32_t xRunCount) {
+ return sendServiceEvent(AAUDIO_SERVICE_EVENT_XRUN, (int64_t) xRunCount);
+}
+
aaudio_result_t AAudioServiceStreamBase::sendCurrentTimestamp() {
AAudioServiceMessage command;
// Send a timestamp for the clock model.
diff --git a/services/oboeservice/AAudioServiceStreamBase.h b/services/oboeservice/AAudioServiceStreamBase.h
index af435b4..29987f6 100644
--- a/services/oboeservice/AAudioServiceStreamBase.h
+++ b/services/oboeservice/AAudioServiceStreamBase.h
@@ -129,11 +129,15 @@
// -------------------------------------------------------------------
/**
- * Send a message to the client.
+ * Send a message to the client with an int64_t data value.
*/
aaudio_result_t sendServiceEvent(aaudio_service_event_t event,
- double dataDouble = 0.0,
int64_t dataLong = 0);
+ /**
+ * Send a message to the client with an double data value.
+ */
+ aaudio_result_t sendServiceEvent(aaudio_service_event_t event,
+ double dataDouble);
/**
* Fill in a parcelable description of stream.
@@ -182,6 +186,19 @@
void onVolumeChanged(float volume);
+ /**
+ * Set false when the stream is started.
+ * Set true when data is first read from the stream.
+ * @param b
+ */
+ void setFlowing(bool b) {
+ mFlowing = b;
+ }
+
+ bool isFlowing() const {
+ return mFlowing;
+ }
+
protected:
/**
@@ -204,6 +221,8 @@
aaudio_result_t sendCurrentTimestamp();
+ aaudio_result_t sendXRunCount(int32_t xRunCount);
+
/**
* @param positionFrames
* @param timeNanos
@@ -237,6 +256,8 @@
private:
aaudio_handle_t mHandle = -1;
+
+ bool mFlowing = false;
};
} /* namespace aaudio */
diff --git a/services/oboeservice/AAudioServiceStreamShared.h b/services/oboeservice/AAudioServiceStreamShared.h
index 8499ea5..3b12e61 100644
--- a/services/oboeservice/AAudioServiceStreamShared.h
+++ b/services/oboeservice/AAudioServiceStreamShared.h
@@ -1,4 +1,4 @@
-/*
+ /*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -80,7 +80,7 @@
}
void incrementXRunCount() {
- mXRunCount++;
+ sendXRunCount(++mXRunCount);
}
int32_t getXRunCount() const {