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
19da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent#include <cutils/log.h>
20da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent#include <assert.h>
21da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent#include <stdlib.h>
22da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent#include <string.h>
23da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent#include <new>
24183dc7772d7eba127aab63829c7ca0359d817593Eric Laurent#include <time.h>
256d8b694d999e9be7d5dcc336535832a80fb6f61fEric Laurent#include <audio_effects/effect_visualizer.h>
26da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
27da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
28e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurentextern "C" {
29e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent
30e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent// effect_handle_t interface implementation for visualizer effect
31e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurentextern const struct effect_interface_s gVisualizerInterface;
32da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
33da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent// Google Visualizer UUID: d069d9e0-8329-11df-9168-0002a5d5c51b
34da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurentconst effect_descriptor_t gVisualizerDescriptor = {
35da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        {0xe46b26a0, 0xdddd, 0x11db, 0x8afd, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // type
36da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        {0xd069d9e0, 0x8329, 0x11df, 0x9168, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // uuid
37e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent        EFFECT_CONTROL_API_VERSION,
38da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST),
39da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        0, // TODO
40da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        1,
41da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        "Visualizer",
42e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent        "The Android Open Source Project",
43da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent};
44da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
45da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurentenum visualizer_state_e {
46da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    VISUALIZER_STATE_UNINITIALIZED,
47da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    VISUALIZER_STATE_INITIALIZED,
48da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    VISUALIZER_STATE_ACTIVE,
49da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent};
50da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
51183dc7772d7eba127aab63829c7ca0359d817593Eric Laurent// maximum time since last capture buffer update before resetting capture buffer. This means
523df40a093d8d3d211f693e0e3ef4076750cabfeaEric Laurent// that the framework has stopped playing audio and we must start returning silence
53183dc7772d7eba127aab63829c7ca0359d817593Eric Laurent#define MAX_STALL_TIME_MS 1000
543df40a093d8d3d211f693e0e3ef4076750cabfeaEric Laurent
55f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen#define CAPTURE_BUF_SIZE 65536 // "64k should be enough for everyone"
56f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen
57da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurentstruct VisualizerContext {
58da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    const struct effect_interface_s *mItfe;
59da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    effect_config_t mConfig;
60da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    uint32_t mCaptureIdx;
61da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    uint32_t mCaptureSize;
623476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi    uint32_t mScalingMode;
633df40a093d8d3d211f693e0e3ef4076750cabfeaEric Laurent    uint8_t mState;
64f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen    uint8_t mLastCaptureIdx;
65f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen    uint32_t mLatency;
66183dc7772d7eba127aab63829c7ca0359d817593Eric Laurent    struct timespec mBufferUpdateTime;
67f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen    uint8_t mCaptureBuf[CAPTURE_BUF_SIZE];
68da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent};
69da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
70da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//
71da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//--- Local functions
72da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//
73da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
74da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurentvoid Visualizer_reset(VisualizerContext *pContext)
75da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent{
76da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    pContext->mCaptureIdx = 0;
77f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen    pContext->mLastCaptureIdx = 0;
78183dc7772d7eba127aab63829c7ca0359d817593Eric Laurent    pContext->mBufferUpdateTime.tv_sec = 0;
79f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen    pContext->mLatency = 0;
80f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen    memset(pContext->mCaptureBuf, 0x80, CAPTURE_BUF_SIZE);
81da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent}
82da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
83da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//----------------------------------------------------------------------------
843d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent// Visualizer_setConfig()
85da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//----------------------------------------------------------------------------
86da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent// Purpose: Set input and output audio configuration.
87da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//
88da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent// Inputs:
89da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//  pContext:   effect engine context
90da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//  pConfig:    pointer to effect_config_t structure holding input and output
91da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//      configuration parameters
92da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//
93da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent// Outputs:
94da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//
95da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//----------------------------------------------------------------------------
96da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
973d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurentint Visualizer_setConfig(VisualizerContext *pContext, effect_config_t *pConfig)
98da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent{
993d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent    ALOGV("Visualizer_setConfig start");
100da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
101da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    if (pConfig->inputCfg.samplingRate != pConfig->outputCfg.samplingRate) return -EINVAL;
102da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    if (pConfig->inputCfg.channels != pConfig->outputCfg.channels) return -EINVAL;
103da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    if (pConfig->inputCfg.format != pConfig->outputCfg.format) return -EINVAL;
104e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    if (pConfig->inputCfg.channels != AUDIO_CHANNEL_OUT_STEREO) return -EINVAL;
105da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    if (pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_WRITE &&
106da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent            pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_ACCUMULATE) return -EINVAL;
107e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    if (pConfig->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) return -EINVAL;
108da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
109da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    memcpy(&pContext->mConfig, pConfig, sizeof(effect_config_t));
110da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
111da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    Visualizer_reset(pContext);
112da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
113da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    return 0;
114da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent}
115da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
116da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
117da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//----------------------------------------------------------------------------
1183d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent// Visualizer_getConfig()
1193d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent//----------------------------------------------------------------------------
1203d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent// Purpose: Get input and output audio configuration.
1213d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent//
1223d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent// Inputs:
1233d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent//  pContext:   effect engine context
1243d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent//  pConfig:    pointer to effect_config_t structure holding input and output
1253d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent//      configuration parameters
1263d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent//
1273d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent// Outputs:
1283d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent//
1293d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent//----------------------------------------------------------------------------
1303d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent
1313d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurentvoid Visualizer_getConfig(VisualizerContext *pContext, effect_config_t *pConfig)
1323d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent{
1333d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent    memcpy(pConfig, &pContext->mConfig, sizeof(effect_config_t));
1343d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent}
1353d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent
1363d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent
1373d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent//----------------------------------------------------------------------------
138da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent// Visualizer_init()
139da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//----------------------------------------------------------------------------
140da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent// Purpose: Initialize engine with default configuration.
141da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//
142da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent// Inputs:
143da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//  pContext:   effect engine context
144da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//
145da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent// Outputs:
146da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//
147da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//----------------------------------------------------------------------------
148da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
149da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurentint Visualizer_init(VisualizerContext *pContext)
150da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent{
151da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    pContext->mConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
152e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    pContext->mConfig.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
153e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    pContext->mConfig.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
154da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    pContext->mConfig.inputCfg.samplingRate = 44100;
155da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    pContext->mConfig.inputCfg.bufferProvider.getBuffer = NULL;
156da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    pContext->mConfig.inputCfg.bufferProvider.releaseBuffer = NULL;
157da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    pContext->mConfig.inputCfg.bufferProvider.cookie = NULL;
158da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    pContext->mConfig.inputCfg.mask = EFFECT_CONFIG_ALL;
159da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    pContext->mConfig.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE;
160e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    pContext->mConfig.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
161e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    pContext->mConfig.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
162da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    pContext->mConfig.outputCfg.samplingRate = 44100;
163da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    pContext->mConfig.outputCfg.bufferProvider.getBuffer = NULL;
164da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    pContext->mConfig.outputCfg.bufferProvider.releaseBuffer = NULL;
165da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    pContext->mConfig.outputCfg.bufferProvider.cookie = NULL;
166da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    pContext->mConfig.outputCfg.mask = EFFECT_CONFIG_ALL;
167da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
168da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    pContext->mCaptureSize = VISUALIZER_CAPTURE_SIZE_MAX;
1693476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi    pContext->mScalingMode = VISUALIZER_SCALING_MODE_NORMALIZED;
170da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
1713d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent    Visualizer_setConfig(pContext, &pContext->mConfig);
172da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
173da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    return 0;
174da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent}
175da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
176da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//
177da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//--- Effect Library Interface Implementation
178da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//
179da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
180e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurentint VisualizerLib_QueryNumberEffects(uint32_t *pNumEffects) {
181da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    *pNumEffects = 1;
182da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    return 0;
183da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent}
184da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
185e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurentint VisualizerLib_QueryEffect(uint32_t index,
186e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent                              effect_descriptor_t *pDescriptor) {
187da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    if (pDescriptor == NULL) {
188da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        return -EINVAL;
189da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    }
190da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    if (index > 0) {
191da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        return -EINVAL;
192da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    }
193da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    memcpy(pDescriptor, &gVisualizerDescriptor, sizeof(effect_descriptor_t));
194da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    return 0;
195da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent}
196da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
1975e92a7861196ddae14638d4b7a63fc4892b7ef59Glenn Kastenint VisualizerLib_Create(const effect_uuid_t *uuid,
198e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent                         int32_t sessionId,
199e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent                         int32_t ioId,
200e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent                         effect_handle_t *pHandle) {
201da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    int ret;
202da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    int i;
203da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
204e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    if (pHandle == NULL || uuid == NULL) {
205da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        return -EINVAL;
206da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    }
207da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
208da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    if (memcmp(uuid, &gVisualizerDescriptor.uuid, sizeof(effect_uuid_t)) != 0) {
209da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        return -EINVAL;
210da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    }
211da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
212da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    VisualizerContext *pContext = new VisualizerContext;
213da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
214da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    pContext->mItfe = &gVisualizerInterface;
215da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    pContext->mState = VISUALIZER_STATE_UNINITIALIZED;
216da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
217da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    ret = Visualizer_init(pContext);
218da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    if (ret < 0) {
2195ff1dd576bb93c45b44088a51544a18fc43ebf58Steve Block        ALOGW("VisualizerLib_Create() init failed");
220da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        delete pContext;
221da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        return ret;
222da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    }
223da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
224e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    *pHandle = (effect_handle_t)pContext;
225da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
226da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    pContext->mState = VISUALIZER_STATE_INITIALIZED;
227da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
2283856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("VisualizerLib_Create %p", pContext);
229da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
230da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    return 0;
231da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
232da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent}
233da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
234e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurentint VisualizerLib_Release(effect_handle_t handle) {
235e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    VisualizerContext * pContext = (VisualizerContext *)handle;
236da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
2373856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("VisualizerLib_Release %p", handle);
238da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    if (pContext == NULL) {
239da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        return -EINVAL;
240da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    }
241da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    pContext->mState = VISUALIZER_STATE_UNINITIALIZED;
242da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    delete pContext;
243da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
244da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    return 0;
245da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent}
246da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
2475e92a7861196ddae14638d4b7a63fc4892b7ef59Glenn Kastenint VisualizerLib_GetDescriptor(const effect_uuid_t *uuid,
248e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent                                effect_descriptor_t *pDescriptor) {
249e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent
250e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    if (pDescriptor == NULL || uuid == NULL){
2513856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("VisualizerLib_GetDescriptor() called with NULL pointer");
252e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent        return -EINVAL;
253e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    }
254e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent
255e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    if (memcmp(uuid, &gVisualizerDescriptor.uuid, sizeof(effect_uuid_t)) == 0) {
256e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent        memcpy(pDescriptor, &gVisualizerDescriptor, sizeof(effect_descriptor_t));
257e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent        return 0;
258e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    }
259e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent
260e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    return  -EINVAL;
261e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent} /* end VisualizerLib_GetDescriptor */
262e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent
263da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//
264da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//--- Effect Control Interface Implementation
265da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent//
266da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
267da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurentstatic inline int16_t clamp16(int32_t sample)
268da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent{
269da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    if ((sample>>15) ^ (sample>>31))
270da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        sample = 0x7FFF ^ (sample>>31);
271da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    return sample;
272da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent}
273da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
274e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurentint Visualizer_process(
275e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent        effect_handle_t self,audio_buffer_t *inBuffer, audio_buffer_t *outBuffer)
276da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent{
277e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    VisualizerContext * pContext = (VisualizerContext *)self;
278da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
279da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    if (pContext == NULL) {
280da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        return -EINVAL;
281da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    }
282da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
283da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    if (inBuffer == NULL || inBuffer->raw == NULL ||
284da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        outBuffer == NULL || outBuffer->raw == NULL ||
285da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        inBuffer->frameCount != outBuffer->frameCount ||
286da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        inBuffer->frameCount == 0) {
287da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        return -EINVAL;
288da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    }
289da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
290da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    // all code below assumes stereo 16 bit PCM output and input
2913476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi    int32_t shift;
2923476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi
2933476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi    if (pContext->mScalingMode == VISUALIZER_SCALING_MODE_NORMALIZED) {
2943476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        // derive capture scaling factor from peak value in current buffer
2953476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        // this gives more interesting captures for display.
2963476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        shift = 32;
2973476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        int len = inBuffer->frameCount * 2;
2983476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        for (int i = 0; i < len; i++) {
2993476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi            int32_t smp = inBuffer->s16[i];
3003476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi            if (smp < 0) smp = -smp - 1; // take care to keep the max negative in range
3013476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi            int32_t clz = __builtin_clz(smp);
3023476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi            if (shift > clz) shift = clz;
3033476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        }
3043476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        // A maximum amplitude signal will have 17 leading zeros, which we want to
3053476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        // translate to a shift of 8 (for converting 16 bit to 8 bit)
3063476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        shift = 25 - shift;
3073476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        // Never scale by less than 8 to avoid returning unaltered PCM signal.
3083476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        if (shift < 3) {
3093476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi            shift = 3;
3103476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        }
3113476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        // add one to combine the division by 2 needed after summing left and right channels below
3123476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        shift++;
3133476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi    } else {
3143476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        assert(pContext->mScalingMode == VISUALIZER_SCALING_MODE_AS_PLAYED);
3153476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        shift = 9;
3160e75f0f0147baeb6277c3dcc4403cf0201155a99Eric Laurent    }
3170e75f0f0147baeb6277c3dcc4403cf0201155a99Eric Laurent
318da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    uint32_t captIdx;
319da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    uint32_t inIdx;
320f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen    uint8_t *buf = pContext->mCaptureBuf;
321da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    for (inIdx = 0, captIdx = pContext->mCaptureIdx;
322f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen         inIdx < inBuffer->frameCount;
323da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent         inIdx++, captIdx++) {
324f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen        if (captIdx >= CAPTURE_BUF_SIZE) {
325f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen            // wrap around
326f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen            captIdx = 0;
327f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen        }
328da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        int32_t smp = inBuffer->s16[2 * inIdx] + inBuffer->s16[2 * inIdx + 1];
32964c3bdea8cba454d4404baded584ea0f0611b3eeMarco Nelissen        smp = smp >> shift;
330da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        buf[captIdx] = ((uint8_t)smp)^0x80;
331da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    }
332da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
333f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen    // XXX the following two should really be atomic, though it probably doesn't
334f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen    // matter much for visualization purposes
335f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen    pContext->mCaptureIdx = captIdx;
336f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen    // update last buffer update time stamp
337f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen    if (clock_gettime(CLOCK_MONOTONIC, &pContext->mBufferUpdateTime) < 0) {
338f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen        pContext->mBufferUpdateTime.tv_sec = 0;
339da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    }
340da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
341da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    if (inBuffer->raw != outBuffer->raw) {
342da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        if (pContext->mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
343da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent            for (size_t i = 0; i < outBuffer->frameCount*2; i++) {
344da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent                outBuffer->s16[i] = clamp16(outBuffer->s16[i] + inBuffer->s16[i]);
345da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent            }
346da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        } else {
347da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent            memcpy(outBuffer->raw, inBuffer->raw, outBuffer->frameCount * 2 * sizeof(int16_t));
348da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        }
349da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    }
350f997cabca292d70d078ae828e21c28e6df62995fEric Laurent    if (pContext->mState != VISUALIZER_STATE_ACTIVE) {
351f997cabca292d70d078ae828e21c28e6df62995fEric Laurent        return -ENODATA;
352f997cabca292d70d078ae828e21c28e6df62995fEric Laurent    }
353da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    return 0;
354da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent}   // end Visualizer_process
355da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
356e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurentint Visualizer_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
35725f4395b932fa9859a6e91ba77c5d20d009da64aEric Laurent        void *pCmdData, uint32_t *replySize, void *pReplyData) {
358da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
359e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    VisualizerContext * pContext = (VisualizerContext *)self;
360da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    int retsize;
361da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
362da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    if (pContext == NULL || pContext->mState == VISUALIZER_STATE_UNINITIALIZED) {
363da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        return -EINVAL;
364da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    }
365da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
3663856b090cd04ba5dd4a59a12430ed724d5995909Steve Block//    ALOGV("Visualizer_command command %d cmdSize %d",cmdCode, cmdSize);
367da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
368da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    switch (cmdCode) {
369da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    case EFFECT_CMD_INIT:
370da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        if (pReplyData == NULL || *replySize != sizeof(int)) {
371da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent            return -EINVAL;
372da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        }
373da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        *(int *) pReplyData = Visualizer_init(pContext);
374da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        break;
3753d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent    case EFFECT_CMD_SET_CONFIG:
376da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
377da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent                || pReplyData == NULL || *replySize != sizeof(int)) {
378da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent            return -EINVAL;
379da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        }
3803d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent        *(int *) pReplyData = Visualizer_setConfig(pContext,
381da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent                (effect_config_t *) pCmdData);
382da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        break;
3833d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent    case EFFECT_CMD_GET_CONFIG:
3843d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent        if (pReplyData == NULL ||
3853d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent            *replySize != sizeof(effect_config_t)) {
3863d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent            return -EINVAL;
3873d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent        }
3883d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent        Visualizer_getConfig(pContext, (effect_config_t *)pReplyData);
3893d5188bd6abe55898f10a0edf3c05aff8aa2ef67Eric Laurent        break;
390da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    case EFFECT_CMD_RESET:
391da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        Visualizer_reset(pContext);
392da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        break;
393da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    case EFFECT_CMD_ENABLE:
394da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        if (pReplyData == NULL || *replySize != sizeof(int)) {
395da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent            return -EINVAL;
396da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        }
397da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        if (pContext->mState != VISUALIZER_STATE_INITIALIZED) {
398da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent            return -ENOSYS;
399da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        }
400da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        pContext->mState = VISUALIZER_STATE_ACTIVE;
4013856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("EFFECT_CMD_ENABLE() OK");
402da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        *(int *)pReplyData = 0;
403da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        break;
404da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    case EFFECT_CMD_DISABLE:
405da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        if (pReplyData == NULL || *replySize != sizeof(int)) {
406da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent            return -EINVAL;
407da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        }
408da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        if (pContext->mState != VISUALIZER_STATE_ACTIVE) {
409da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent            return -ENOSYS;
410da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        }
411da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        pContext->mState = VISUALIZER_STATE_INITIALIZED;
4123856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("EFFECT_CMD_DISABLE() OK");
413da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        *(int *)pReplyData = 0;
414da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        break;
415da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    case EFFECT_CMD_GET_PARAM: {
416da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        if (pCmdData == NULL ||
417da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent            cmdSize != (int)(sizeof(effect_param_t) + sizeof(uint32_t)) ||
418da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent            pReplyData == NULL ||
419da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent            *replySize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint32_t))) {
420da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent            return -EINVAL;
421da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        }
422da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + sizeof(uint32_t));
423da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        effect_param_t *p = (effect_param_t *)pReplyData;
424da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        p->status = 0;
425da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        *replySize = sizeof(effect_param_t) + sizeof(uint32_t);
4263476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        if (p->psize != sizeof(uint32_t)) {
427da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent            p->status = -EINVAL;
428da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent            break;
429da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        }
4303476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        switch (*(uint32_t *)p->data) {
4313476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        case VISUALIZER_PARAM_CAPTURE_SIZE:
4323476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi            ALOGV("get mCaptureSize = %d", pContext->mCaptureSize);
4333476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi            *((uint32_t *)p->data + 1) = pContext->mCaptureSize;
4343476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi            p->vsize = sizeof(uint32_t);
4353476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi            *replySize += sizeof(uint32_t);
4363476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi            break;
4373476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        case VISUALIZER_PARAM_SCALING_MODE:
4383476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi            ALOGV("get mScalingMode = %d", pContext->mScalingMode);
4393476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi            *((uint32_t *)p->data + 1) = pContext->mScalingMode;
4403476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi            p->vsize = sizeof(uint32_t);
4413476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi            *replySize += sizeof(uint32_t);
4423476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi            break;
4433476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        default:
4443476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi            p->status = -EINVAL;
4453476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        }
446da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        } break;
447da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    case EFFECT_CMD_SET_PARAM: {
448da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        if (pCmdData == NULL ||
449da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent            cmdSize != (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint32_t)) ||
450da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent            pReplyData == NULL || *replySize != sizeof(int32_t)) {
451da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent            return -EINVAL;
452da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        }
453da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        *(int32_t *)pReplyData = 0;
454da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        effect_param_t *p = (effect_param_t *)pCmdData;
4553476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        if (p->psize != sizeof(uint32_t) || p->vsize != sizeof(uint32_t)) {
4563476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi            *(int32_t *)pReplyData = -EINVAL;
4573476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi            break;
4583476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        }
4593476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        switch (*(uint32_t *)p->data) {
4603476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        case VISUALIZER_PARAM_CAPTURE_SIZE:
4613476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi            pContext->mCaptureSize = *((uint32_t *)p->data + 1);
4623476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi            ALOGV("set mCaptureSize = %d", pContext->mCaptureSize);
4633476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi            break;
4643476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        case VISUALIZER_PARAM_SCALING_MODE:
4653476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi            pContext->mScalingMode = *((uint32_t *)p->data + 1);
4663476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi            ALOGV("set mScalingMode = %d", pContext->mScalingMode);
4673476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi            break;
468f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen        case VISUALIZER_PARAM_LATENCY:
469f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen            pContext->mLatency = *((uint32_t *)p->data + 1);
470f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen            ALOGV("set mLatency = %d", pContext->mLatency);
471f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen            break;
4723476de62fb10e76412452ef4c6bd71936c9f7db1Jean-Michel Trivi        default:
473da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent            *(int32_t *)pReplyData = -EINVAL;
474da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        }
475da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        } break;
476da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    case EFFECT_CMD_SET_DEVICE:
477da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    case EFFECT_CMD_SET_VOLUME:
478da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    case EFFECT_CMD_SET_AUDIO_MODE:
479da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        break;
480da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
481da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
4826d8b694d999e9be7d5dcc336535832a80fb6f61fEric Laurent    case VISUALIZER_CMD_CAPTURE:
4830e75f0f0147baeb6277c3dcc4403cf0201155a99Eric Laurent        if (pReplyData == NULL || *replySize != pContext->mCaptureSize) {
4843856b090cd04ba5dd4a59a12430ed724d5995909Steve Block            ALOGV("VISUALIZER_CMD_CAPTURE() error *replySize %d pContext->mCaptureSize %d",
485da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent                    *replySize, pContext->mCaptureSize);
486da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent            return -EINVAL;
487da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        }
488da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        if (pContext->mState == VISUALIZER_STATE_ACTIVE) {
489f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen            int32_t latencyMs = pContext->mLatency;
490f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen            uint32_t deltaMs = 0;
491f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen            if (pContext->mBufferUpdateTime.tv_sec != 0) {
492183dc7772d7eba127aab63829c7ca0359d817593Eric Laurent                struct timespec ts;
493183dc7772d7eba127aab63829c7ca0359d817593Eric Laurent                if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
494183dc7772d7eba127aab63829c7ca0359d817593Eric Laurent                    time_t secs = ts.tv_sec - pContext->mBufferUpdateTime.tv_sec;
495183dc7772d7eba127aab63829c7ca0359d817593Eric Laurent                    long nsec = ts.tv_nsec - pContext->mBufferUpdateTime.tv_nsec;
496183dc7772d7eba127aab63829c7ca0359d817593Eric Laurent                    if (nsec < 0) {
497183dc7772d7eba127aab63829c7ca0359d817593Eric Laurent                        --secs;
498183dc7772d7eba127aab63829c7ca0359d817593Eric Laurent                        nsec += 1000000000;
499183dc7772d7eba127aab63829c7ca0359d817593Eric Laurent                    }
500f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen                    deltaMs = secs * 1000 + nsec / 1000000;
501f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen                    latencyMs -= deltaMs;
502f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen                    if (latencyMs < 0) {
503f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen                        latencyMs = 0;
5043df40a093d8d3d211f693e0e3ef4076750cabfeaEric Laurent                    }
5053df40a093d8d3d211f693e0e3ef4076750cabfeaEric Laurent                }
5063df40a093d8d3d211f693e0e3ef4076750cabfeaEric Laurent            }
507f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen            uint32_t deltaSmpl = pContext->mConfig.inputCfg.samplingRate * latencyMs / 1000;
508f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen
509f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen            int32_t capturePoint = pContext->mCaptureIdx - pContext->mCaptureSize - deltaSmpl;
510f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen            int32_t captureSize = pContext->mCaptureSize;
511f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen            if (capturePoint < 0) {
512f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen                int32_t size = -capturePoint;
513f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen                if (size > captureSize) {
514f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen                    size = captureSize;
515f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen                }
516f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen                memcpy(pReplyData,
517f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen                       pContext->mCaptureBuf + CAPTURE_BUF_SIZE + capturePoint,
518f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen                       size);
519f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen                pReplyData += size;
520f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen                captureSize -= size;
521f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen                capturePoint = 0;
522f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen            }
523f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen            memcpy(pReplyData,
524f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen                   pContext->mCaptureBuf + capturePoint,
525f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen                   captureSize);
526f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen
527f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen
528f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen            // if audio framework has stopped playing audio although the effect is still
529f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen            // active we must clear the capture buffer to return silence
530f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen            if ((pContext->mLastCaptureIdx == pContext->mCaptureIdx) &&
531f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen                    (pContext->mBufferUpdateTime.tv_sec != 0)) {
532f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen                if (deltaMs > MAX_STALL_TIME_MS) {
533f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen                    ALOGV("capture going to idle");
534f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen                    pContext->mBufferUpdateTime.tv_sec = 0;
535f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen                    memset(pReplyData, 0x80, pContext->mCaptureSize);
536f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen                }
537f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen            }
538f06c2ed50e1db871ae9eb2bd15a196064f8c278cMarco Nelissen            pContext->mLastCaptureIdx = pContext->mCaptureIdx;
539da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        } else {
540da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent            memset(pReplyData, 0x80, pContext->mCaptureSize);
541da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        }
5423df40a093d8d3d211f693e0e3ef4076750cabfeaEric Laurent
543da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        break;
544da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
545da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    default:
5465ff1dd576bb93c45b44088a51544a18fc43ebf58Steve Block        ALOGW("Visualizer_command invalid command %d",cmdCode);
547da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        return -EINVAL;
548da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    }
549da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
550da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent    return 0;
551da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent}
552da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
553e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent/* Effect Control Interface Implementation: get_descriptor */
554e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurentint Visualizer_getDescriptor(effect_handle_t   self,
555e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent                                    effect_descriptor_t *pDescriptor)
556e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent{
557e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    VisualizerContext * pContext = (VisualizerContext *) self;
558e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent
559e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    if (pContext == NULL || pDescriptor == NULL) {
5603856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("Visualizer_getDescriptor() invalid param");
561e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent        return -EINVAL;
562e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    }
563e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent
564e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    memcpy(pDescriptor, &gVisualizerDescriptor, sizeof(effect_descriptor_t));
565e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent
566e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    return 0;
567e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent}   /* end Visualizer_getDescriptor */
568e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent
569e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent// effect_handle_t interface implementation for visualizer effect
570da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurentconst struct effect_interface_s gVisualizerInterface = {
571da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent        Visualizer_process,
572e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent        Visualizer_command,
573ba7b8f881a9b6b21803752326d2932a3bd42d7cfEric Laurent        Visualizer_getDescriptor,
574ba7b8f881a9b6b21803752326d2932a3bd42d7cfEric Laurent        NULL,
575da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent};
576da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
577da7581b7b61b84f15e8d671c86fd117c322b009eEric Laurent
578e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurentaudio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
579e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    tag : AUDIO_EFFECT_LIBRARY_TAG,
580e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    version : EFFECT_LIBRARY_API_VERSION,
581e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    name : "Visualizer Library",
582e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    implementor : "The Android Open Source Project",
583e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    query_num_effects : VisualizerLib_QueryNumberEffects,
584e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    query_effect : VisualizerLib_QueryEffect,
585e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    create_effect : VisualizerLib_Create,
586e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    release_effect : VisualizerLib_Release,
587e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    get_descriptor : VisualizerLib_GetDescriptor,
588e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent};
589e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent
590e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent}; // extern "C"
591