1da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent/*
2da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent * Copyright (C) 2010 The Android Open Source Project
3da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent *
4da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent * Licensed under the Apache License, Version 2.0 (the "License");
5da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent * you may not use this file except in compliance with the License.
6da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent * You may obtain a copy of the License at
7da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent *
8da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent *      http://www.apache.org/licenses/LICENSE-2.0
9da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent *
10da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent * Unless required by applicable law or agreed to in writing, software
11da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent * distributed under the License is distributed on an "AS IS" BASIS,
12da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent * See the License for the specific language governing permissions and
14da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent * limitations under the License.
15da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent */
16da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
173476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi#define LOG_TAG "EffectVisualizer"
18da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//#define LOG_NDEBUG 0
197cb0e733210c2ce7dd2a7c9d32f6d83c4dab9656Mark Salyzyn#include <log/log.h>
20da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent#include <assert.h>
217cb0e733210c2ce7dd2a7c9d32f6d83c4dab9656Mark Salyzyn#include <inttypes.h>
22da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent#include <stdlib.h>
23da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent#include <string.h>
24da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent#include <new>
25183dc7772d7eba127aab63829c7ca0359d817593Eric Laurent#include <time.h>
2609647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi#include <math.h>
276d8b694d999e9be7d5dcc336535832a80fb6f61fEric Laurent#include <audio_effects/effect_visualizer.h>
28da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
29da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
30e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurentextern "C" {
31e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent
32e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent// effect_handle_t interface implementation for visualizer effect
33e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurentextern const struct effect_interface_s gVisualizerInterface;
34da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
35da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent// Google Visualizer UUID: d069d9e0-8329-11df-9168-0002a5d5c51b
36da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurentconst effect_descriptor_t gVisualizerDescriptor = {
37da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        {0xe46b26a0, 0xdddd, 0x11db, 0x8afd, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // type
38da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        {0xd069d9e0, 0x8329, 0x11df, 0x9168, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // uuid
39e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent        EFFECT_CONTROL_API_VERSION,
40da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST),
41da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        0, // TODO
42da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        1,
43da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        "Visualizer",
44e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent        "The Android Open Source Project",
45da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent};
46da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
47da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurentenum visualizer_state_e {
48da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    VISUALIZER_STATE_UNINITIALIZED,
49da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    VISUALIZER_STATE_INITIALIZED,
50da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    VISUALIZER_STATE_ACTIVE,
51da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent};
52da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
53183dc7772d7eba127aab63829c7ca0359d817593Eric Laurent// maximum time since last capture buffer update before resetting capture buffer. This means
543df40a093d8d3d211f693e0e3ef4076750cabfeaEric Laurent// that the framework has stopped playing audio and we must start returning silence
55183dc7772d7eba127aab63829c7ca0359d817593Eric Laurent#define MAX_STALL_TIME_MS 1000
563df40a093d8d3d211f693e0e3ef4076750cabfeaEric Laurent
57f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen#define CAPTURE_BUF_SIZE 65536 // "64k should be enough for everyone"
58f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen
5909647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi#define DISCARD_MEASUREMENTS_TIME_MS 2000 // discard measurements older than this number of ms
6009647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi
6109647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi// maximum number of buffers for which we keep track of the measurements
626fbc9ef121b081f888163190bb13cbac31599900Jean-Michel Trivi#define MEASUREMENT_WINDOW_MAX_SIZE_IN_BUFFERS 25 // note: buffer index is stored in uint8_t
6309647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi
6409647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi
6509647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivistruct BufferStats {
6609647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi    bool mIsValid;
6709647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi    uint16_t mPeakU16; // the positive peak of the absolute value of the samples in a buffer
6809647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi    float mRmsSquared; // the average square of the samples in a buffer
6909647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi};
7009647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi
71da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurentstruct VisualizerContext {
72da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    const struct effect_interface_s *mItfe;
73da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    effect_config_t mConfig;
74da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    uint32_t mCaptureIdx;
75da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    uint32_t mCaptureSize;
763476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi    uint32_t mScalingMode;
773df40a093d8d3d211f693e0e3ef4076750cabfeaEric Laurent    uint8_t mState;
785baf2af52cd186633b7173196c1e4a4cd3435f22Eric Laurent    uint32_t mLastCaptureIdx;
79f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen    uint32_t mLatency;
80183dc7772d7eba127aab63829c7ca0359d817593Eric Laurent    struct timespec mBufferUpdateTime;
81f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen    uint8_t mCaptureBuf[CAPTURE_BUF_SIZE];
8209647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi    // for measurements
8309647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi    uint8_t mChannelCount; // to avoid recomputing it every time a buffer is processed
8409647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi    uint32_t mMeasurementMode;
8509647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi    uint8_t mMeasurementWindowSizeInBuffers;
8609647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi    uint8_t mMeasurementBufferIdx;
8709647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi    BufferStats mPastMeasurements[MEASUREMENT_WINDOW_MAX_SIZE_IN_BUFFERS];
88da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent};
89da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
90da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//
91da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//--- Local functions
92da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//
9309647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Triviuint32_t Visualizer_getDeltaTimeMsFromUpdatedTime(VisualizerContext* pContext) {
9409647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi    uint32_t deltaMs = 0;
9509647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi    if (pContext->mBufferUpdateTime.tv_sec != 0) {
9609647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi        struct timespec ts;
9709647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi        if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
9809647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi            time_t secs = ts.tv_sec - pContext->mBufferUpdateTime.tv_sec;
9909647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi            long nsec = ts.tv_nsec - pContext->mBufferUpdateTime.tv_nsec;
10009647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi            if (nsec < 0) {
10109647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi                --secs;
10209647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi                nsec += 1000000000;
10309647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi            }
10409647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi            deltaMs = secs * 1000 + nsec / 1000000;
10509647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi        }
10609647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi    }
10709647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi    return deltaMs;
10809647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi}
10909647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi
110da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
111da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurentvoid Visualizer_reset(VisualizerContext *pContext)
112da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent{
113da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    pContext->mCaptureIdx = 0;
114f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen    pContext->mLastCaptureIdx = 0;
115183dc7772d7eba127aab63829c7ca0359d817593Eric Laurent    pContext->mBufferUpdateTime.tv_sec = 0;
116f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen    pContext->mLatency = 0;
117f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen    memset(pContext->mCaptureBuf, 0x80, CAPTURE_BUF_SIZE);
118da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent}
119da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
120da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//----------------------------------------------------------------------------
1213d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent// Visualizer_setConfig()
122da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//----------------------------------------------------------------------------
123da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent// Purpose: Set input and output audio configuration.
124da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//
125da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent// Inputs:
126da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//  pContext:   effect engine context
127da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//  pConfig:    pointer to effect_config_t structure holding input and output
128da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//      configuration parameters
129da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//
130da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent// Outputs:
131da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//
132da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//----------------------------------------------------------------------------
133da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
1343d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurentint Visualizer_setConfig(VisualizerContext *pContext, effect_config_t *pConfig)
135da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent{
1363d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent    ALOGV("Visualizer_setConfig start");
137da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
138da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    if (pConfig->inputCfg.samplingRate != pConfig->outputCfg.samplingRate) return -EINVAL;
139da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    if (pConfig->inputCfg.channels != pConfig->outputCfg.channels) return -EINVAL;
140da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    if (pConfig->inputCfg.format != pConfig->outputCfg.format) return -EINVAL;
141e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    if (pConfig->inputCfg.channels != AUDIO_CHANNEL_OUT_STEREO) return -EINVAL;
142da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    if (pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_WRITE &&
143da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent            pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_ACCUMULATE) return -EINVAL;
144e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    if (pConfig->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) return -EINVAL;
145da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
146a189a6883ee55cf62da1d7bf5bf5a8ab501938a4Glenn Kasten    pContext->mConfig = *pConfig;
147da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
148da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    Visualizer_reset(pContext);
149da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
150da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    return 0;
151da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent}
152da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
153da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
154da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//----------------------------------------------------------------------------
1553d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent// Visualizer_getConfig()
1563d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent//----------------------------------------------------------------------------
1573d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent// Purpose: Get input and output audio configuration.
1583d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent//
1593d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent// Inputs:
1603d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent//  pContext:   effect engine context
1613d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent//  pConfig:    pointer to effect_config_t structure holding input and output
1623d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent//      configuration parameters
1633d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent//
1643d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent// Outputs:
1653d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent//
1663d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent//----------------------------------------------------------------------------
1673d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent
1683d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurentvoid Visualizer_getConfig(VisualizerContext *pContext, effect_config_t *pConfig)
1693d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent{
170a189a6883ee55cf62da1d7bf5bf5a8ab501938a4Glenn Kasten    *pConfig = pContext->mConfig;
1713d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent}
1723d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent
1733d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent
1743d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent//----------------------------------------------------------------------------
175da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent// Visualizer_init()
176da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//----------------------------------------------------------------------------
177da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent// Purpose: Initialize engine with default configuration.
178da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//
179da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent// Inputs:
180da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//  pContext:   effect engine context
181da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//
182da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent// Outputs:
183da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//
184da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//----------------------------------------------------------------------------
185da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
186da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurentint Visualizer_init(VisualizerContext *pContext)
187da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent{
188da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    pContext->mConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
189e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    pContext->mConfig.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
190e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    pContext->mConfig.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
191da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    pContext->mConfig.inputCfg.samplingRate = 44100;
192da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    pContext->mConfig.inputCfg.bufferProvider.getBuffer = NULL;
193da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    pContext->mConfig.inputCfg.bufferProvider.releaseBuffer = NULL;
194da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    pContext->mConfig.inputCfg.bufferProvider.cookie = NULL;
195da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    pContext->mConfig.inputCfg.mask = EFFECT_CONFIG_ALL;
196da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    pContext->mConfig.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE;
197e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    pContext->mConfig.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
198e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    pContext->mConfig.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
199da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    pContext->mConfig.outputCfg.samplingRate = 44100;
200da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    pContext->mConfig.outputCfg.bufferProvider.getBuffer = NULL;
201da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    pContext->mConfig.outputCfg.bufferProvider.releaseBuffer = NULL;
202da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    pContext->mConfig.outputCfg.bufferProvider.cookie = NULL;
203da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    pContext->mConfig.outputCfg.mask = EFFECT_CONFIG_ALL;
204da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
20509647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi    // visualization initialization
206da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    pContext->mCaptureSize = VISUALIZER_CAPTURE_SIZE_MAX;
2073476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi    pContext->mScalingMode = VISUALIZER_SCALING_MODE_NORMALIZED;
208da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
20909647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi    // measurement initialization
210e541269be94f3a1072932d51537905b120ef4733Andy Hung    pContext->mChannelCount =
211e541269be94f3a1072932d51537905b120ef4733Andy Hung            audio_channel_count_from_out_mask(pContext->mConfig.inputCfg.channels);
21209647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi    pContext->mMeasurementMode = MEASUREMENT_MODE_NONE;
21309647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi    pContext->mMeasurementWindowSizeInBuffers = MEASUREMENT_WINDOW_MAX_SIZE_IN_BUFFERS;
21409647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi    pContext->mMeasurementBufferIdx = 0;
2156fbc9ef121b081f888163190bb13cbac31599900Jean-Michel Trivi    for (uint32_t i=0 ; i<pContext->mMeasurementWindowSizeInBuffers ; i++) {
21609647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi        pContext->mPastMeasurements[i].mIsValid = false;
21709647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi        pContext->mPastMeasurements[i].mPeakU16 = 0;
21809647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi        pContext->mPastMeasurements[i].mRmsSquared = 0;
21909647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi    }
22009647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi
2213d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent    Visualizer_setConfig(pContext, &pContext->mConfig);
222da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
223da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    return 0;
224da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent}
225da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
226da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//
227da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//--- Effect Library Interface Implementation
228da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//
229da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
2305e92a7861196ddae14638d4b7a63fc4892b7ef59Glenn Kastenint VisualizerLib_Create(const effect_uuid_t *uuid,
2317cb0e733210c2ce7dd2a7c9d32f6d83c4dab9656Mark Salyzyn                         int32_t /*sessionId*/,
2327cb0e733210c2ce7dd2a7c9d32f6d83c4dab9656Mark Salyzyn                         int32_t /*ioId*/,
233e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent                         effect_handle_t *pHandle) {
234da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    int ret;
235da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    int i;
236da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
237e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    if (pHandle == NULL || uuid == NULL) {
238da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        return -EINVAL;
239da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    }
240da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
241da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    if (memcmp(uuid, &gVisualizerDescriptor.uuid, sizeof(effect_uuid_t)) != 0) {
242da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        return -EINVAL;
243da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    }
244da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
245da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    VisualizerContext *pContext = new VisualizerContext;
246da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
247da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    pContext->mItfe = &gVisualizerInterface;
248da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    pContext->mState = VISUALIZER_STATE_UNINITIALIZED;
249da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
250da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    ret = Visualizer_init(pContext);
251da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    if (ret < 0) {
2525ff1dd576bb93c45b44088a51544a18fc43ebf58Steve Block        ALOGW("VisualizerLib_Create() init failed");
253da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        delete pContext;
254da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        return ret;
255da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    }
256da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
257e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    *pHandle = (effect_handle_t)pContext;
258da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
259da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    pContext->mState = VISUALIZER_STATE_INITIALIZED;
260da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
2613856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("VisualizerLib_Create %p", pContext);
262da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
263da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    return 0;
264da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
265da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent}
266da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
267e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurentint VisualizerLib_Release(effect_handle_t handle) {
268e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    VisualizerContext * pContext = (VisualizerContext *)handle;
269da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
2703856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("VisualizerLib_Release %p", handle);
271da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    if (pContext == NULL) {
272da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        return -EINVAL;
273da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    }
274da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    pContext->mState = VISUALIZER_STATE_UNINITIALIZED;
275da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    delete pContext;
276da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
277da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    return 0;
278da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent}
279da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
2805e92a7861196ddae14638d4b7a63fc4892b7ef59Glenn Kastenint VisualizerLib_GetDescriptor(const effect_uuid_t *uuid,
281e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent                                effect_descriptor_t *pDescriptor) {
282e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent
283e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    if (pDescriptor == NULL || uuid == NULL){
2843856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("VisualizerLib_GetDescriptor() called with NULL pointer");
285e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent        return -EINVAL;
286e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    }
287e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent
288e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    if (memcmp(uuid, &gVisualizerDescriptor.uuid, sizeof(effect_uuid_t)) == 0) {
289a189a6883ee55cf62da1d7bf5bf5a8ab501938a4Glenn Kasten        *pDescriptor = gVisualizerDescriptor;
290e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent        return 0;
291e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    }
292e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent
293e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    return  -EINVAL;
294e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent} /* end VisualizerLib_GetDescriptor */
295e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent
296da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//
297da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//--- Effect Control Interface Implementation
298da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//
299da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
300da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurentstatic inline int16_t clamp16(int32_t sample)
301da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent{
302da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    if ((sample>>15) ^ (sample>>31))
303da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        sample = 0x7FFF ^ (sample>>31);
304da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    return sample;
305da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent}
306da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
307e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurentint Visualizer_process(
308e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent        effect_handle_t self,audio_buffer_t *inBuffer, audio_buffer_t *outBuffer)
309da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent{
310e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    VisualizerContext * pContext = (VisualizerContext *)self;
311da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
312da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    if (pContext == NULL) {
313da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        return -EINVAL;
314da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    }
315da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
316da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    if (inBuffer == NULL || inBuffer->raw == NULL ||
317da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        outBuffer == NULL || outBuffer->raw == NULL ||
318da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        inBuffer->frameCount != outBuffer->frameCount ||
319da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        inBuffer->frameCount == 0) {
320da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        return -EINVAL;
321da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    }
322da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
32309647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi    // perform measurements if needed
32409647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi    if (pContext->mMeasurementMode & MEASUREMENT_MODE_PEAK_RMS) {
32509647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi        // find the peak and RMS squared for the new buffer
32609647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi        uint32_t inIdx;
32709647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi        int16_t maxSample = 0;
32809647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi        float rmsSqAcc = 0;
32909647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi        for (inIdx = 0 ; inIdx < inBuffer->frameCount * pContext->mChannelCount ; inIdx++) {
33009647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi            if (inBuffer->s16[inIdx] > maxSample) {
33109647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi                maxSample = inBuffer->s16[inIdx];
33209647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi            } else if (-inBuffer->s16[inIdx] > maxSample) {
33309647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi                maxSample = -inBuffer->s16[inIdx];
33409647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi            }
33509647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi            rmsSqAcc += (inBuffer->s16[inIdx] * inBuffer->s16[inIdx]);
33609647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi        }
33709647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi        // store the measurement
33809647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi        pContext->mPastMeasurements[pContext->mMeasurementBufferIdx].mPeakU16 = (uint16_t)maxSample;
33909647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi        pContext->mPastMeasurements[pContext->mMeasurementBufferIdx].mRmsSquared =
34009647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi                rmsSqAcc / (inBuffer->frameCount * pContext->mChannelCount);
34109647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi        pContext->mPastMeasurements[pContext->mMeasurementBufferIdx].mIsValid = true;
34209647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi        if (++pContext->mMeasurementBufferIdx >= pContext->mMeasurementWindowSizeInBuffers) {
34309647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi            pContext->mMeasurementBufferIdx = 0;
34409647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi        }
34509647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi    }
34609647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi
347da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    // all code below assumes stereo 16 bit PCM output and input
3483476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi    int32_t shift;
3493476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi
3503476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi    if (pContext->mScalingMode == VISUALIZER_SCALING_MODE_NORMALIZED) {
3513476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        // derive capture scaling factor from peak value in current buffer
3523476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        // this gives more interesting captures for display.
3533476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        shift = 32;
3543476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        int len = inBuffer->frameCount * 2;
3553476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        for (int i = 0; i < len; i++) {
3563476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi            int32_t smp = inBuffer->s16[i];
3573476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi            if (smp < 0) smp = -smp - 1; // take care to keep the max negative in range
3583476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi            int32_t clz = __builtin_clz(smp);
3593476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi            if (shift > clz) shift = clz;
3603476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        }
3613476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        // A maximum amplitude signal will have 17 leading zeros, which we want to
3623476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        // translate to a shift of 8 (for converting 16 bit to 8 bit)
3633476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        shift = 25 - shift;
3643476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        // Never scale by less than 8 to avoid returning unaltered PCM signal.
3653476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        if (shift < 3) {
3663476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi            shift = 3;
3673476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        }
3683476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        // add one to combine the division by 2 needed after summing left and right channels below
3693476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        shift++;
3703476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi    } else {
3713476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        assert(pContext->mScalingMode == VISUALIZER_SCALING_MODE_AS_PLAYED);
3723476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        shift = 9;
3730e75f0f0147baeb6277c3dcc4403cf0201155a99Eric Laurent    }
3740e75f0f0147baeb6277c3dcc4403cf0201155a99Eric Laurent
375da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    uint32_t captIdx;
376da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    uint32_t inIdx;
377f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen    uint8_t *buf = pContext->mCaptureBuf;
378da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    for (inIdx = 0, captIdx = pContext->mCaptureIdx;
379f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen         inIdx < inBuffer->frameCount;
380da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent         inIdx++, captIdx++) {
381f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen        if (captIdx >= CAPTURE_BUF_SIZE) {
382f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen            // wrap around
383f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen            captIdx = 0;
384f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen        }
385da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        int32_t smp = inBuffer->s16[2 * inIdx] + inBuffer->s16[2 * inIdx + 1];
38664c3bdea8cba454d4404baded584ea0f0611b3eeMarco Nelissen        smp = smp >> shift;
387da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        buf[captIdx] = ((uint8_t)smp)^0x80;
388da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    }
389da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
390f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen    // XXX the following two should really be atomic, though it probably doesn't
391f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen    // matter much for visualization purposes
392f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen    pContext->mCaptureIdx = captIdx;
393f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen    // update last buffer update time stamp
394f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen    if (clock_gettime(CLOCK_MONOTONIC, &pContext->mBufferUpdateTime) < 0) {
395f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen        pContext->mBufferUpdateTime.tv_sec = 0;
396da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    }
397da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
398da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    if (inBuffer->raw != outBuffer->raw) {
399da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        if (pContext->mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
400da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent            for (size_t i = 0; i < outBuffer->frameCount*2; i++) {
401da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent                outBuffer->s16[i] = clamp16(outBuffer->s16[i] + inBuffer->s16[i]);
402da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent            }
403da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        } else {
404da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent            memcpy(outBuffer->raw, inBuffer->raw, outBuffer->frameCount * 2 * sizeof(int16_t));
405da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        }
406da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    }
407f997cabca292d70d078ae828e21c28e6df62995fEric Laurent    if (pContext->mState != VISUALIZER_STATE_ACTIVE) {
408f997cabca292d70d078ae828e21c28e6df62995fEric Laurent        return -ENODATA;
409f997cabca292d70d078ae828e21c28e6df62995fEric Laurent    }
410da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    return 0;
411da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent}   // end Visualizer_process
412da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
413e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurentint Visualizer_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
41425f4395b932fa9859a6e91ba77c5d20d009da64aEric Laurent        void *pCmdData, uint32_t *replySize, void *pReplyData) {
415da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
416e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    VisualizerContext * pContext = (VisualizerContext *)self;
417da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    int retsize;
418da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
419da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    if (pContext == NULL || pContext->mState == VISUALIZER_STATE_UNINITIALIZED) {
420da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        return -EINVAL;
421da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    }
422da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
4237cb0e733210c2ce7dd2a7c9d32f6d83c4dab9656Mark Salyzyn//    ALOGV("Visualizer_command command %" PRIu32 " cmdSize %" PRIu32, cmdCode, cmdSize);
424da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
425da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    switch (cmdCode) {
426da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    case EFFECT_CMD_INIT:
427da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        if (pReplyData == NULL || *replySize != sizeof(int)) {
428da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent            return -EINVAL;
429da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        }
430da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        *(int *) pReplyData = Visualizer_init(pContext);
431da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        break;
4323d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent    case EFFECT_CMD_SET_CONFIG:
433da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
434da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent                || pReplyData == NULL || *replySize != sizeof(int)) {
435da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent            return -EINVAL;
436da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        }
4373d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent        *(int *) pReplyData = Visualizer_setConfig(pContext,
438da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent                (effect_config_t *) pCmdData);
439da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        break;
4403d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent    case EFFECT_CMD_GET_CONFIG:
4413d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent        if (pReplyData == NULL ||
4423d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent            *replySize != sizeof(effect_config_t)) {
4433d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent            return -EINVAL;
4443d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent        }
4453d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent        Visualizer_getConfig(pContext, (effect_config_t *)pReplyData);
4463d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent        break;
447da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    case EFFECT_CMD_RESET:
448da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        Visualizer_reset(pContext);
449da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        break;
450da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    case EFFECT_CMD_ENABLE:
451da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        if (pReplyData == NULL || *replySize != sizeof(int)) {
452da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent            return -EINVAL;
453da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        }
454da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        if (pContext->mState != VISUALIZER_STATE_INITIALIZED) {
455da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent            return -ENOSYS;
456da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        }
457da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        pContext->mState = VISUALIZER_STATE_ACTIVE;
4583856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("EFFECT_CMD_ENABLE() OK");
459da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        *(int *)pReplyData = 0;
460da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        break;
461da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    case EFFECT_CMD_DISABLE:
462da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        if (pReplyData == NULL || *replySize != sizeof(int)) {
463da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent            return -EINVAL;
464da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        }
465da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        if (pContext->mState != VISUALIZER_STATE_ACTIVE) {
466da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent            return -ENOSYS;
467da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        }
468da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        pContext->mState = VISUALIZER_STATE_INITIALIZED;
4693856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("EFFECT_CMD_DISABLE() OK");
470da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        *(int *)pReplyData = 0;
471da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        break;
472da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    case EFFECT_CMD_GET_PARAM: {
473da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        if (pCmdData == NULL ||
474da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent            cmdSize != (int)(sizeof(effect_param_t) + sizeof(uint32_t)) ||
475da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent            pReplyData == NULL ||
476da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent            *replySize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint32_t))) {
477da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent            return -EINVAL;
478da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        }
479da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + sizeof(uint32_t));
480da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        effect_param_t *p = (effect_param_t *)pReplyData;
481da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        p->status = 0;
482da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        *replySize = sizeof(effect_param_t) + sizeof(uint32_t);
4833476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        if (p->psize != sizeof(uint32_t)) {
484da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent            p->status = -EINVAL;
485da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent            break;
486da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        }
4873476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        switch (*(uint32_t *)p->data) {
4883476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        case VISUALIZER_PARAM_CAPTURE_SIZE:
4897cb0e733210c2ce7dd2a7c9d32f6d83c4dab9656Mark Salyzyn            ALOGV("get mCaptureSize = %" PRIu32, pContext->mCaptureSize);
4903476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi            *((uint32_t *)p->data + 1) = pContext->mCaptureSize;
4913476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi            p->vsize = sizeof(uint32_t);
4923476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi            *replySize += sizeof(uint32_t);
4933476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi            break;
4943476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        case VISUALIZER_PARAM_SCALING_MODE:
4957cb0e733210c2ce7dd2a7c9d32f6d83c4dab9656Mark Salyzyn            ALOGV("get mScalingMode = %" PRIu32, pContext->mScalingMode);
4963476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi            *((uint32_t *)p->data + 1) = pContext->mScalingMode;
4973476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi            p->vsize = sizeof(uint32_t);
4983476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi            *replySize += sizeof(uint32_t);
4993476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi            break;
50009647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi        case VISUALIZER_PARAM_MEASUREMENT_MODE:
5017cb0e733210c2ce7dd2a7c9d32f6d83c4dab9656Mark Salyzyn            ALOGV("get mMeasurementMode = %" PRIu32, pContext->mMeasurementMode);
50209647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi            *((uint32_t *)p->data + 1) = pContext->mMeasurementMode;
50309647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi            p->vsize = sizeof(uint32_t);
50409647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi            *replySize += sizeof(uint32_t);
50509647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi            break;
5063476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        default:
5073476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi            p->status = -EINVAL;
5083476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        }
509da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        } break;
510da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    case EFFECT_CMD_SET_PARAM: {
511da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        if (pCmdData == NULL ||
512da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent            cmdSize != (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint32_t)) ||
513da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent            pReplyData == NULL || *replySize != sizeof(int32_t)) {
514da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent            return -EINVAL;
515da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        }
516da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        *(int32_t *)pReplyData = 0;
517da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        effect_param_t *p = (effect_param_t *)pCmdData;
5183476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        if (p->psize != sizeof(uint32_t) || p->vsize != sizeof(uint32_t)) {
5193476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi            *(int32_t *)pReplyData = -EINVAL;
5203476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi            break;
5213476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        }
5223476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        switch (*(uint32_t *)p->data) {
5233476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        case VISUALIZER_PARAM_CAPTURE_SIZE:
5243476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi            pContext->mCaptureSize = *((uint32_t *)p->data + 1);
5257cb0e733210c2ce7dd2a7c9d32f6d83c4dab9656Mark Salyzyn            ALOGV("set mCaptureSize = %" PRIu32, pContext->mCaptureSize);
5263476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi            break;
5273476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        case VISUALIZER_PARAM_SCALING_MODE:
5283476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi            pContext->mScalingMode = *((uint32_t *)p->data + 1);
5297cb0e733210c2ce7dd2a7c9d32f6d83c4dab9656Mark Salyzyn            ALOGV("set mScalingMode = %" PRIu32, pContext->mScalingMode);
5303476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi            break;
531f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen        case VISUALIZER_PARAM_LATENCY:
532f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen            pContext->mLatency = *((uint32_t *)p->data + 1);
5337cb0e733210c2ce7dd2a7c9d32f6d83c4dab9656Mark Salyzyn            ALOGV("set mLatency = %" PRIu32, pContext->mLatency);
534f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen            break;
53509647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi        case VISUALIZER_PARAM_MEASUREMENT_MODE:
53609647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi            pContext->mMeasurementMode = *((uint32_t *)p->data + 1);
5377cb0e733210c2ce7dd2a7c9d32f6d83c4dab9656Mark Salyzyn            ALOGV("set mMeasurementMode = %" PRIu32, pContext->mMeasurementMode);
53809647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi            break;
5393476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        default:
540da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent            *(int32_t *)pReplyData = -EINVAL;
541da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        }
542da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        } break;
543da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    case EFFECT_CMD_SET_DEVICE:
544da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    case EFFECT_CMD_SET_VOLUME:
545da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    case EFFECT_CMD_SET_AUDIO_MODE:
546da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        break;
547da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
548da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
549abb7b17613fff41433cda94207eb535c9fed8fbaRyszard Grzesica    case VISUALIZER_CMD_CAPTURE: {
5507cb0e733210c2ce7dd2a7c9d32f6d83c4dab9656Mark Salyzyn        uint32_t captureSize = pContext->mCaptureSize;
551abb7b17613fff41433cda94207eb535c9fed8fbaRyszard Grzesica        if (pReplyData == NULL || *replySize != captureSize) {
5527cb0e733210c2ce7dd2a7c9d32f6d83c4dab9656Mark Salyzyn            ALOGV("VISUALIZER_CMD_CAPTURE() error *replySize %" PRIu32 " captureSize %" PRIu32,
553abb7b17613fff41433cda94207eb535c9fed8fbaRyszard Grzesica                    *replySize, captureSize);
554da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent            return -EINVAL;
555da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        }
556da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        if (pContext->mState == VISUALIZER_STATE_ACTIVE) {
55709647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi            const uint32_t deltaMs = Visualizer_getDeltaTimeMsFromUpdatedTime(pContext);
558f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen
559f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen            // if audio framework has stopped playing audio although the effect is still
560f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen            // active we must clear the capture buffer to return silence
561f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen            if ((pContext->mLastCaptureIdx == pContext->mCaptureIdx) &&
562abb7b17613fff41433cda94207eb535c9fed8fbaRyszard Grzesica                    (pContext->mBufferUpdateTime.tv_sec != 0) &&
563abb7b17613fff41433cda94207eb535c9fed8fbaRyszard Grzesica                    (deltaMs > MAX_STALL_TIME_MS)) {
564f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen                    ALOGV("capture going to idle");
565f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen                    pContext->mBufferUpdateTime.tv_sec = 0;
566abb7b17613fff41433cda94207eb535c9fed8fbaRyszard Grzesica                    memset(pReplyData, 0x80, captureSize);
567abb7b17613fff41433cda94207eb535c9fed8fbaRyszard Grzesica            } else {
568abb7b17613fff41433cda94207eb535c9fed8fbaRyszard Grzesica                int32_t latencyMs = pContext->mLatency;
569abb7b17613fff41433cda94207eb535c9fed8fbaRyszard Grzesica                latencyMs -= deltaMs;
570abb7b17613fff41433cda94207eb535c9fed8fbaRyszard Grzesica                if (latencyMs < 0) {
571abb7b17613fff41433cda94207eb535c9fed8fbaRyszard Grzesica                    latencyMs = 0;
572f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen                }
573abb7b17613fff41433cda94207eb535c9fed8fbaRyszard Grzesica                const uint32_t deltaSmpl =
574abb7b17613fff41433cda94207eb535c9fed8fbaRyszard Grzesica                    pContext->mConfig.inputCfg.samplingRate * latencyMs / 1000;
575abb7b17613fff41433cda94207eb535c9fed8fbaRyszard Grzesica                int32_t capturePoint = pContext->mCaptureIdx - captureSize - deltaSmpl;
576abb7b17613fff41433cda94207eb535c9fed8fbaRyszard Grzesica
577abb7b17613fff41433cda94207eb535c9fed8fbaRyszard Grzesica                if (capturePoint < 0) {
5787cb0e733210c2ce7dd2a7c9d32f6d83c4dab9656Mark Salyzyn                    uint32_t size = -capturePoint;
579abb7b17613fff41433cda94207eb535c9fed8fbaRyszard Grzesica                    if (size > captureSize) {
580abb7b17613fff41433cda94207eb535c9fed8fbaRyszard Grzesica                        size = captureSize;
581abb7b17613fff41433cda94207eb535c9fed8fbaRyszard Grzesica                    }
582abb7b17613fff41433cda94207eb535c9fed8fbaRyszard Grzesica                    memcpy(pReplyData,
583abb7b17613fff41433cda94207eb535c9fed8fbaRyszard Grzesica                           pContext->mCaptureBuf + CAPTURE_BUF_SIZE + capturePoint,
584abb7b17613fff41433cda94207eb535c9fed8fbaRyszard Grzesica                           size);
585abb7b17613fff41433cda94207eb535c9fed8fbaRyszard Grzesica                    pReplyData = (char *)pReplyData + size;
586abb7b17613fff41433cda94207eb535c9fed8fbaRyszard Grzesica                    captureSize -= size;
587abb7b17613fff41433cda94207eb535c9fed8fbaRyszard Grzesica                    capturePoint = 0;
588abb7b17613fff41433cda94207eb535c9fed8fbaRyszard Grzesica                }
589abb7b17613fff41433cda94207eb535c9fed8fbaRyszard Grzesica                memcpy(pReplyData,
590abb7b17613fff41433cda94207eb535c9fed8fbaRyszard Grzesica                       pContext->mCaptureBuf + capturePoint,
591abb7b17613fff41433cda94207eb535c9fed8fbaRyszard Grzesica                       captureSize);
592f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen            }
593abb7b17613fff41433cda94207eb535c9fed8fbaRyszard Grzesica
594f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen            pContext->mLastCaptureIdx = pContext->mCaptureIdx;
595da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        } else {
596abb7b17613fff41433cda94207eb535c9fed8fbaRyszard Grzesica            memset(pReplyData, 0x80, captureSize);
597da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        }
5983df40a093d8d3d211f693e0e3ef4076750cabfeaEric Laurent
599abb7b17613fff41433cda94207eb535c9fed8fbaRyszard Grzesica        } break;
600da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
60109647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi    case VISUALIZER_CMD_MEASURE: {
60209647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi        uint16_t peakU16 = 0;
60309647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi        float sumRmsSquared = 0.0f;
60409647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi        uint8_t nbValidMeasurements = 0;
60509647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi        // reset measurements if last measurement was too long ago (which implies stored
60609647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi        // measurements aren't relevant anymore and shouldn't bias the new one)
60709647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi        const int32_t delayMs = Visualizer_getDeltaTimeMsFromUpdatedTime(pContext);
60809647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi        if (delayMs > DISCARD_MEASUREMENTS_TIME_MS) {
6097cb0e733210c2ce7dd2a7c9d32f6d83c4dab9656Mark Salyzyn            ALOGV("Discarding measurements, last measurement is %" PRId32 "ms old", delayMs);
6106fbc9ef121b081f888163190bb13cbac31599900Jean-Michel Trivi            for (uint32_t i=0 ; i<pContext->mMeasurementWindowSizeInBuffers ; i++) {
61109647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi                pContext->mPastMeasurements[i].mIsValid = false;
61209647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi                pContext->mPastMeasurements[i].mPeakU16 = 0;
61309647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi                pContext->mPastMeasurements[i].mRmsSquared = 0;
61409647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi            }
61509647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi            pContext->mMeasurementBufferIdx = 0;
61609647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi        } else {
61709647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi            // only use actual measurements, otherwise the first RMS measure happening before
61809647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi            // MEASUREMENT_WINDOW_MAX_SIZE_IN_BUFFERS have been played will always be artificially
61909647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi            // low
6206fbc9ef121b081f888163190bb13cbac31599900Jean-Michel Trivi            for (uint32_t i=0 ; i < pContext->mMeasurementWindowSizeInBuffers ; i++) {
62109647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi                if (pContext->mPastMeasurements[i].mIsValid) {
62209647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi                    if (pContext->mPastMeasurements[i].mPeakU16 > peakU16) {
62309647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi                        peakU16 = pContext->mPastMeasurements[i].mPeakU16;
62409647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi                    }
6256fbc9ef121b081f888163190bb13cbac31599900Jean-Michel Trivi                    sumRmsSquared += pContext->mPastMeasurements[i].mRmsSquared;
62609647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi                    nbValidMeasurements++;
62709647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi                }
62809647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi            }
62909647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi        }
63009647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi        float rms = nbValidMeasurements == 0 ? 0.0f : sqrtf(sumRmsSquared / nbValidMeasurements);
63109647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi        int32_t* pIntReplyData = (int32_t*)pReplyData;
63209647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi        // convert from I16 sample values to mB and write results
63309647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi        if (rms < 0.000016f) {
63409647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi            pIntReplyData[MEASUREMENT_IDX_RMS] = -9600; //-96dB
63509647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi        } else {
63609647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi            pIntReplyData[MEASUREMENT_IDX_RMS] = (int32_t) (2000 * log10(rms / 32767.0f));
63709647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi        }
63809647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi        if (peakU16 == 0) {
63909647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi            pIntReplyData[MEASUREMENT_IDX_PEAK] = -9600; //-96dB
64009647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi        } else {
64109647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi            pIntReplyData[MEASUREMENT_IDX_PEAK] = (int32_t) (2000 * log10(peakU16 / 32767.0f));
64209647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi        }
6437cb0e733210c2ce7dd2a7c9d32f6d83c4dab9656Mark Salyzyn        ALOGV("VISUALIZER_CMD_MEASURE peak=%" PRIu16 " (%" PRId32 "mB), rms=%.1f (%" PRId32 "mB)",
64409647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi                peakU16, pIntReplyData[MEASUREMENT_IDX_PEAK],
64509647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi                rms, pIntReplyData[MEASUREMENT_IDX_RMS]);
64609647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi        }
64709647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi        break;
64809647d29eaf429ce88c9c9709ff63dee62f2147aJean-Michel Trivi
649da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    default:
6507cb0e733210c2ce7dd2a7c9d32f6d83c4dab9656Mark Salyzyn        ALOGW("Visualizer_command invalid command %" PRIu32, cmdCode);
651da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        return -EINVAL;
652da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    }
653da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
654da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    return 0;
655da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent}
656da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
657e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent/* Effect Control Interface Implementation: get_descriptor */
658e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurentint Visualizer_getDescriptor(effect_handle_t   self,
659e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent                                    effect_descriptor_t *pDescriptor)
660e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent{
661e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    VisualizerContext * pContext = (VisualizerContext *) self;
662e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent
663e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    if (pContext == NULL || pDescriptor == NULL) {
6643856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("Visualizer_getDescriptor() invalid param");
665e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent        return -EINVAL;
666e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    }
667e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent
668a189a6883ee55cf62da1d7bf5bf5a8ab501938a4Glenn Kasten    *pDescriptor = gVisualizerDescriptor;
669e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent
670e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    return 0;
671e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent}   /* end Visualizer_getDescriptor */
672e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent
673e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent// effect_handle_t interface implementation for visualizer effect
674da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurentconst struct effect_interface_s gVisualizerInterface = {
675da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        Visualizer_process,
676e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent        Visualizer_command,
677ba7b8f881a9b6b21803752326d2932a3bd42d7cfEric Laurent        Visualizer_getDescriptor,
678ba7b8f881a9b6b21803752326d2932a3bd42d7cfEric Laurent        NULL,
679da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent};
680da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
6817f16b197c76fbae9399242f055a7ee16dcd0fd6dMarco Nelissen// This is the only symbol that needs to be exported
6827f16b197c76fbae9399242f055a7ee16dcd0fd6dMarco Nelissen__attribute__ ((visibility ("default")))
683e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurentaudio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
684c9d8ea7f8f9a1ca8ecd266695e3cac423790b2f9synergydev    .tag = AUDIO_EFFECT_LIBRARY_TAG,
685c9d8ea7f8f9a1ca8ecd266695e3cac423790b2f9synergydev    .version = EFFECT_LIBRARY_API_VERSION,
686c9d8ea7f8f9a1ca8ecd266695e3cac423790b2f9synergydev    .name = "Visualizer Library",
687c9d8ea7f8f9a1ca8ecd266695e3cac423790b2f9synergydev    .implementor = "The Android Open Source Project",
688c9d8ea7f8f9a1ca8ecd266695e3cac423790b2f9synergydev    .create_effect = VisualizerLib_Create,
689c9d8ea7f8f9a1ca8ecd266695e3cac423790b2f9synergydev    .release_effect = VisualizerLib_Release,
690c9d8ea7f8f9a1ca8ecd266695e3cac423790b2f9synergydev    .get_descriptor = VisualizerLib_GetDescriptor,
691e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent};
692e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent
693e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent}; // extern "C"
694