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/visualizer/EffectVisualizer.cpp | 19 ------------------- 1 file changed, 19 deletions(-) (limited to 'media/libeffects/visualizer/EffectVisualizer.cpp') 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/visualizer/EffectVisualizer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'media/libeffects/visualizer/EffectVisualizer.cpp') 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 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/visualizer/EffectVisualizer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'media/libeffects/visualizer/EffectVisualizer.cpp') 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/visualizer/EffectVisualizer.cpp') 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 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/visualizer/EffectVisualizer.cpp') 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