blob: b2a7a35cf568bba1cfaee8549029f5e210518ea1 [file] [log] [blame]
Eric Laurentdf9b81c2010-07-02 08:12:41 -07001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "Visualizer"
18//#define LOG_NDEBUG 0
19#include <cutils/log.h>
20#include <assert.h>
21#include <stdlib.h>
22#include <string.h>
23#include <new>
Eric Laurent5cc05262011-06-24 07:01:31 -070024#include <audio_effects/effect_visualizer.h>
Eric Laurentdf9b81c2010-07-02 08:12:41 -070025
Eric Laurentdf9b81c2010-07-02 08:12:41 -070026
Eric Laurent0fb66c22011-05-17 19:16:02 -070027extern "C" {
28
29// effect_handle_t interface implementation for visualizer effect
30extern const struct effect_interface_s gVisualizerInterface;
Eric Laurentdf9b81c2010-07-02 08:12:41 -070031
32// Google Visualizer UUID: d069d9e0-8329-11df-9168-0002a5d5c51b
33const effect_descriptor_t gVisualizerDescriptor = {
34 {0xe46b26a0, 0xdddd, 0x11db, 0x8afd, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // type
35 {0xd069d9e0, 0x8329, 0x11df, 0x9168, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // uuid
Eric Laurent0fb66c22011-05-17 19:16:02 -070036 EFFECT_CONTROL_API_VERSION,
Eric Laurentdf9b81c2010-07-02 08:12:41 -070037 (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST),
38 0, // TODO
39 1,
40 "Visualizer",
Eric Laurent0fb66c22011-05-17 19:16:02 -070041 "The Android Open Source Project",
Eric Laurentdf9b81c2010-07-02 08:12:41 -070042};
43
44enum visualizer_state_e {
45 VISUALIZER_STATE_UNINITIALIZED,
46 VISUALIZER_STATE_INITIALIZED,
47 VISUALIZER_STATE_ACTIVE,
48};
49
Eric Laurentdf8ab512011-11-10 10:02:18 -080050// maximum number of reads from same buffer before resetting capture buffer. This means
51// that the framework has stopped playing audio and we must start returning silence
52#define MAX_STALL_COUNT 10
53
Eric Laurentdf9b81c2010-07-02 08:12:41 -070054struct VisualizerContext {
55 const struct effect_interface_s *mItfe;
56 effect_config_t mConfig;
Eric Laurentdf9b81c2010-07-02 08:12:41 -070057 uint32_t mCaptureIdx;
58 uint32_t mCaptureSize;
Eric Laurentdf8ab512011-11-10 10:02:18 -080059 uint8_t mState;
60 uint8_t mCurrentBuf;
61 uint8_t mLastBuf;
62 uint8_t mStallCount;
Eric Laurentdf9b81c2010-07-02 08:12:41 -070063 uint8_t mCaptureBuf[2][VISUALIZER_CAPTURE_SIZE_MAX];
64};
65
Eric Laurentdf9b81c2010-07-02 08:12:41 -070066//
67//--- Local functions
68//
69
70void Visualizer_reset(VisualizerContext *pContext)
71{
72 pContext->mCaptureIdx = 0;
73 pContext->mCurrentBuf = 0;
Eric Laurentdf8ab512011-11-10 10:02:18 -080074 pContext->mLastBuf = 1;
75 pContext->mStallCount = 0;
Eric Laurent4d3fb502010-09-24 11:52:04 -070076 memset(pContext->mCaptureBuf[0], 0x80, VISUALIZER_CAPTURE_SIZE_MAX);
77 memset(pContext->mCaptureBuf[1], 0x80, VISUALIZER_CAPTURE_SIZE_MAX);
Eric Laurentdf9b81c2010-07-02 08:12:41 -070078}
79
80//----------------------------------------------------------------------------
Eric Laurent4abf8822011-12-16 15:30:36 -080081// Visualizer_setConfig()
Eric Laurentdf9b81c2010-07-02 08:12:41 -070082//----------------------------------------------------------------------------
83// Purpose: Set input and output audio configuration.
84//
85// Inputs:
86// pContext: effect engine context
87// pConfig: pointer to effect_config_t structure holding input and output
88// configuration parameters
89//
90// Outputs:
91//
92//----------------------------------------------------------------------------
93
Eric Laurent4abf8822011-12-16 15:30:36 -080094int Visualizer_setConfig(VisualizerContext *pContext, effect_config_t *pConfig)
Eric Laurentdf9b81c2010-07-02 08:12:41 -070095{
Eric Laurent4abf8822011-12-16 15:30:36 -080096 ALOGV("Visualizer_setConfig start");
Eric Laurentdf9b81c2010-07-02 08:12:41 -070097
98 if (pConfig->inputCfg.samplingRate != pConfig->outputCfg.samplingRate) return -EINVAL;
99 if (pConfig->inputCfg.channels != pConfig->outputCfg.channels) return -EINVAL;
100 if (pConfig->inputCfg.format != pConfig->outputCfg.format) return -EINVAL;
Eric Laurent0fb66c22011-05-17 19:16:02 -0700101 if (pConfig->inputCfg.channels != AUDIO_CHANNEL_OUT_STEREO) return -EINVAL;
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700102 if (pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_WRITE &&
103 pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_ACCUMULATE) return -EINVAL;
Eric Laurent0fb66c22011-05-17 19:16:02 -0700104 if (pConfig->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) return -EINVAL;
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700105
106 memcpy(&pContext->mConfig, pConfig, sizeof(effect_config_t));
107
108 Visualizer_reset(pContext);
109
110 return 0;
111}
112
113
114//----------------------------------------------------------------------------
Eric Laurent4abf8822011-12-16 15:30:36 -0800115// Visualizer_getConfig()
116//----------------------------------------------------------------------------
117// Purpose: Get input and output audio configuration.
118//
119// Inputs:
120// pContext: effect engine context
121// pConfig: pointer to effect_config_t structure holding input and output
122// configuration parameters
123//
124// Outputs:
125//
126//----------------------------------------------------------------------------
127
128void Visualizer_getConfig(VisualizerContext *pContext, effect_config_t *pConfig)
129{
130 memcpy(pConfig, &pContext->mConfig, sizeof(effect_config_t));
131}
132
133
134//----------------------------------------------------------------------------
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700135// Visualizer_init()
136//----------------------------------------------------------------------------
137// Purpose: Initialize engine with default configuration.
138//
139// Inputs:
140// pContext: effect engine context
141//
142// Outputs:
143//
144//----------------------------------------------------------------------------
145
146int Visualizer_init(VisualizerContext *pContext)
147{
148 pContext->mConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
Eric Laurent0fb66c22011-05-17 19:16:02 -0700149 pContext->mConfig.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
150 pContext->mConfig.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700151 pContext->mConfig.inputCfg.samplingRate = 44100;
152 pContext->mConfig.inputCfg.bufferProvider.getBuffer = NULL;
153 pContext->mConfig.inputCfg.bufferProvider.releaseBuffer = NULL;
154 pContext->mConfig.inputCfg.bufferProvider.cookie = NULL;
155 pContext->mConfig.inputCfg.mask = EFFECT_CONFIG_ALL;
156 pContext->mConfig.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE;
Eric Laurent0fb66c22011-05-17 19:16:02 -0700157 pContext->mConfig.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
158 pContext->mConfig.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700159 pContext->mConfig.outputCfg.samplingRate = 44100;
160 pContext->mConfig.outputCfg.bufferProvider.getBuffer = NULL;
161 pContext->mConfig.outputCfg.bufferProvider.releaseBuffer = NULL;
162 pContext->mConfig.outputCfg.bufferProvider.cookie = NULL;
163 pContext->mConfig.outputCfg.mask = EFFECT_CONFIG_ALL;
164
165 pContext->mCaptureSize = VISUALIZER_CAPTURE_SIZE_MAX;
166
Eric Laurent4abf8822011-12-16 15:30:36 -0800167 Visualizer_setConfig(pContext, &pContext->mConfig);
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700168
169 return 0;
170}
171
172//
173//--- Effect Library Interface Implementation
174//
175
Eric Laurent0fb66c22011-05-17 19:16:02 -0700176int VisualizerLib_QueryNumberEffects(uint32_t *pNumEffects) {
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700177 *pNumEffects = 1;
178 return 0;
179}
180
Eric Laurent0fb66c22011-05-17 19:16:02 -0700181int VisualizerLib_QueryEffect(uint32_t index,
182 effect_descriptor_t *pDescriptor) {
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700183 if (pDescriptor == NULL) {
184 return -EINVAL;
185 }
186 if (index > 0) {
187 return -EINVAL;
188 }
189 memcpy(pDescriptor, &gVisualizerDescriptor, sizeof(effect_descriptor_t));
190 return 0;
191}
192
Eric Laurent0fb66c22011-05-17 19:16:02 -0700193int VisualizerLib_Create(effect_uuid_t *uuid,
194 int32_t sessionId,
195 int32_t ioId,
196 effect_handle_t *pHandle) {
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700197 int ret;
198 int i;
199
Eric Laurent0fb66c22011-05-17 19:16:02 -0700200 if (pHandle == NULL || uuid == NULL) {
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700201 return -EINVAL;
202 }
203
204 if (memcmp(uuid, &gVisualizerDescriptor.uuid, sizeof(effect_uuid_t)) != 0) {
205 return -EINVAL;
206 }
207
208 VisualizerContext *pContext = new VisualizerContext;
209
210 pContext->mItfe = &gVisualizerInterface;
211 pContext->mState = VISUALIZER_STATE_UNINITIALIZED;
212
213 ret = Visualizer_init(pContext);
214 if (ret < 0) {
Eric Laurent0fb66c22011-05-17 19:16:02 -0700215 LOGW("VisualizerLib_Create() init failed");
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700216 delete pContext;
217 return ret;
218 }
219
Eric Laurent0fb66c22011-05-17 19:16:02 -0700220 *pHandle = (effect_handle_t)pContext;
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700221
222 pContext->mState = VISUALIZER_STATE_INITIALIZED;
223
Steve Block71f2cf12011-10-20 11:56:00 +0100224 ALOGV("VisualizerLib_Create %p", pContext);
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700225
226 return 0;
227
228}
229
Eric Laurent0fb66c22011-05-17 19:16:02 -0700230int VisualizerLib_Release(effect_handle_t handle) {
231 VisualizerContext * pContext = (VisualizerContext *)handle;
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700232
Steve Block71f2cf12011-10-20 11:56:00 +0100233 ALOGV("VisualizerLib_Release %p", handle);
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700234 if (pContext == NULL) {
235 return -EINVAL;
236 }
237 pContext->mState = VISUALIZER_STATE_UNINITIALIZED;
238 delete pContext;
239
240 return 0;
241}
242
Eric Laurent0fb66c22011-05-17 19:16:02 -0700243int VisualizerLib_GetDescriptor(effect_uuid_t *uuid,
244 effect_descriptor_t *pDescriptor) {
245
246 if (pDescriptor == NULL || uuid == NULL){
Steve Block71f2cf12011-10-20 11:56:00 +0100247 ALOGV("VisualizerLib_GetDescriptor() called with NULL pointer");
Eric Laurent0fb66c22011-05-17 19:16:02 -0700248 return -EINVAL;
249 }
250
251 if (memcmp(uuid, &gVisualizerDescriptor.uuid, sizeof(effect_uuid_t)) == 0) {
252 memcpy(pDescriptor, &gVisualizerDescriptor, sizeof(effect_descriptor_t));
253 return 0;
254 }
255
256 return -EINVAL;
257} /* end VisualizerLib_GetDescriptor */
258
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700259//
260//--- Effect Control Interface Implementation
261//
262
263static inline int16_t clamp16(int32_t sample)
264{
265 if ((sample>>15) ^ (sample>>31))
266 sample = 0x7FFF ^ (sample>>31);
267 return sample;
268}
269
Eric Laurent0fb66c22011-05-17 19:16:02 -0700270int Visualizer_process(
271 effect_handle_t self,audio_buffer_t *inBuffer, audio_buffer_t *outBuffer)
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700272{
Eric Laurent0fb66c22011-05-17 19:16:02 -0700273 VisualizerContext * pContext = (VisualizerContext *)self;
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700274
275 if (pContext == NULL) {
276 return -EINVAL;
277 }
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700278
279 if (inBuffer == NULL || inBuffer->raw == NULL ||
280 outBuffer == NULL || outBuffer->raw == NULL ||
281 inBuffer->frameCount != outBuffer->frameCount ||
282 inBuffer->frameCount == 0) {
283 return -EINVAL;
284 }
285
286 // all code below assumes stereo 16 bit PCM output and input
Eric Laurent672c0dc2010-09-21 14:52:01 -0700287
288 // derive capture scaling factor from peak value in current buffer
289 // this gives more interesting captures for display.
290 int32_t shift = 32;
Marco Nelissenf514bdc2010-10-27 09:06:01 -0700291 int len = inBuffer->frameCount * 2;
Eric Laurent0fb66c22011-05-17 19:16:02 -0700292 for (int i = 0; i < len; i++) {
Eric Laurent672c0dc2010-09-21 14:52:01 -0700293 int32_t smp = inBuffer->s16[i];
Marco Nelissenf514bdc2010-10-27 09:06:01 -0700294 if (smp < 0) smp = -smp - 1; // take care to keep the max negative in range
Eric Laurent672c0dc2010-09-21 14:52:01 -0700295 int32_t clz = __builtin_clz(smp);
296 if (shift > clz) shift = clz;
297 }
Marco Nelissenf514bdc2010-10-27 09:06:01 -0700298 // A maximum amplitude signal will have 17 leading zeros, which we want to
299 // translate to a shift of 8 (for converting 16 bit to 8 bit)
300 shift = 25 - shift;
301 // Never scale by less than 8 to avoid returning unaltered PCM signal.
302 if (shift < 3) {
303 shift = 3;
Eric Laurent672c0dc2010-09-21 14:52:01 -0700304 }
Marco Nelissenf514bdc2010-10-27 09:06:01 -0700305 // add one to combine the division by 2 needed after summing left and right channels below
306 shift++;
Eric Laurent672c0dc2010-09-21 14:52:01 -0700307
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700308 uint32_t captIdx;
309 uint32_t inIdx;
310 uint8_t *buf = pContext->mCaptureBuf[pContext->mCurrentBuf];
311 for (inIdx = 0, captIdx = pContext->mCaptureIdx;
312 inIdx < inBuffer->frameCount && captIdx < pContext->mCaptureSize;
313 inIdx++, captIdx++) {
314 int32_t smp = inBuffer->s16[2 * inIdx] + inBuffer->s16[2 * inIdx + 1];
Marco Nelissenf514bdc2010-10-27 09:06:01 -0700315 smp = smp >> shift;
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700316 buf[captIdx] = ((uint8_t)smp)^0x80;
317 }
318 pContext->mCaptureIdx = captIdx;
319
320 // go to next buffer when buffer full
321 if (pContext->mCaptureIdx == pContext->mCaptureSize) {
322 pContext->mCurrentBuf ^= 1;
323 pContext->mCaptureIdx = 0;
324 }
325
326 if (inBuffer->raw != outBuffer->raw) {
327 if (pContext->mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
328 for (size_t i = 0; i < outBuffer->frameCount*2; i++) {
329 outBuffer->s16[i] = clamp16(outBuffer->s16[i] + inBuffer->s16[i]);
330 }
331 } else {
332 memcpy(outBuffer->raw, inBuffer->raw, outBuffer->frameCount * 2 * sizeof(int16_t));
333 }
334 }
Eric Laurent0d7e0482010-07-19 06:24:46 -0700335 if (pContext->mState != VISUALIZER_STATE_ACTIVE) {
336 return -ENODATA;
337 }
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700338 return 0;
339} // end Visualizer_process
340
Eric Laurent0fb66c22011-05-17 19:16:02 -0700341int Visualizer_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
Eric Laurenta4c72ac2010-07-28 05:40:18 -0700342 void *pCmdData, uint32_t *replySize, void *pReplyData) {
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700343
Eric Laurent0fb66c22011-05-17 19:16:02 -0700344 VisualizerContext * pContext = (VisualizerContext *)self;
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700345 int retsize;
346
347 if (pContext == NULL || pContext->mState == VISUALIZER_STATE_UNINITIALIZED) {
348 return -EINVAL;
349 }
350
Steve Block71f2cf12011-10-20 11:56:00 +0100351// ALOGV("Visualizer_command command %d cmdSize %d",cmdCode, cmdSize);
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700352
353 switch (cmdCode) {
354 case EFFECT_CMD_INIT:
355 if (pReplyData == NULL || *replySize != sizeof(int)) {
356 return -EINVAL;
357 }
358 *(int *) pReplyData = Visualizer_init(pContext);
359 break;
Eric Laurent4abf8822011-12-16 15:30:36 -0800360 case EFFECT_CMD_SET_CONFIG:
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700361 if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
362 || pReplyData == NULL || *replySize != sizeof(int)) {
363 return -EINVAL;
364 }
Eric Laurent4abf8822011-12-16 15:30:36 -0800365 *(int *) pReplyData = Visualizer_setConfig(pContext,
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700366 (effect_config_t *) pCmdData);
367 break;
Eric Laurent4abf8822011-12-16 15:30:36 -0800368 case EFFECT_CMD_GET_CONFIG:
369 if (pReplyData == NULL ||
370 *replySize != sizeof(effect_config_t)) {
371 return -EINVAL;
372 }
373 Visualizer_getConfig(pContext, (effect_config_t *)pReplyData);
374 break;
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700375 case EFFECT_CMD_RESET:
376 Visualizer_reset(pContext);
377 break;
378 case EFFECT_CMD_ENABLE:
379 if (pReplyData == NULL || *replySize != sizeof(int)) {
380 return -EINVAL;
381 }
382 if (pContext->mState != VISUALIZER_STATE_INITIALIZED) {
383 return -ENOSYS;
384 }
385 pContext->mState = VISUALIZER_STATE_ACTIVE;
Steve Block71f2cf12011-10-20 11:56:00 +0100386 ALOGV("EFFECT_CMD_ENABLE() OK");
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700387 *(int *)pReplyData = 0;
388 break;
389 case EFFECT_CMD_DISABLE:
390 if (pReplyData == NULL || *replySize != sizeof(int)) {
391 return -EINVAL;
392 }
393 if (pContext->mState != VISUALIZER_STATE_ACTIVE) {
394 return -ENOSYS;
395 }
396 pContext->mState = VISUALIZER_STATE_INITIALIZED;
Steve Block71f2cf12011-10-20 11:56:00 +0100397 ALOGV("EFFECT_CMD_DISABLE() OK");
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700398 *(int *)pReplyData = 0;
399 break;
400 case EFFECT_CMD_GET_PARAM: {
401 if (pCmdData == NULL ||
402 cmdSize != (int)(sizeof(effect_param_t) + sizeof(uint32_t)) ||
403 pReplyData == NULL ||
404 *replySize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint32_t))) {
405 return -EINVAL;
406 }
407 memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + sizeof(uint32_t));
408 effect_param_t *p = (effect_param_t *)pReplyData;
409 p->status = 0;
410 *replySize = sizeof(effect_param_t) + sizeof(uint32_t);
411 if (p->psize != sizeof(uint32_t) ||
Eric Laurent5cc05262011-06-24 07:01:31 -0700412 *(uint32_t *)p->data != VISUALIZER_PARAM_CAPTURE_SIZE) {
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700413 p->status = -EINVAL;
414 break;
415 }
Steve Block71f2cf12011-10-20 11:56:00 +0100416 ALOGV("get mCaptureSize = %d", pContext->mCaptureSize);
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700417 *((uint32_t *)p->data + 1) = pContext->mCaptureSize;
418 p->vsize = sizeof(uint32_t);
419 *replySize += sizeof(uint32_t);
420 } break;
421 case EFFECT_CMD_SET_PARAM: {
422 if (pCmdData == NULL ||
423 cmdSize != (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint32_t)) ||
424 pReplyData == NULL || *replySize != sizeof(int32_t)) {
425 return -EINVAL;
426 }
427 *(int32_t *)pReplyData = 0;
428 effect_param_t *p = (effect_param_t *)pCmdData;
429 if (p->psize != sizeof(uint32_t) ||
430 p->vsize != sizeof(uint32_t) ||
Eric Laurent5cc05262011-06-24 07:01:31 -0700431 *(uint32_t *)p->data != VISUALIZER_PARAM_CAPTURE_SIZE) {
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700432 *(int32_t *)pReplyData = -EINVAL;
433 break;;
434 }
435 pContext->mCaptureSize = *((uint32_t *)p->data + 1);
Steve Block71f2cf12011-10-20 11:56:00 +0100436 ALOGV("set mCaptureSize = %d", pContext->mCaptureSize);
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700437 } break;
438 case EFFECT_CMD_SET_DEVICE:
439 case EFFECT_CMD_SET_VOLUME:
440 case EFFECT_CMD_SET_AUDIO_MODE:
441 break;
442
443
Eric Laurent5cc05262011-06-24 07:01:31 -0700444 case VISUALIZER_CMD_CAPTURE:
Eric Laurent672c0dc2010-09-21 14:52:01 -0700445 if (pReplyData == NULL || *replySize != pContext->mCaptureSize) {
Steve Block71f2cf12011-10-20 11:56:00 +0100446 ALOGV("VISUALIZER_CMD_CAPTURE() error *replySize %d pContext->mCaptureSize %d",
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700447 *replySize, pContext->mCaptureSize);
448 return -EINVAL;
449 }
450 if (pContext->mState == VISUALIZER_STATE_ACTIVE) {
451 memcpy(pReplyData,
452 pContext->mCaptureBuf[pContext->mCurrentBuf ^ 1],
453 pContext->mCaptureSize);
Eric Laurentdf8ab512011-11-10 10:02:18 -0800454 // if audio framework has stopped playing audio although the effect is still
455 // active we must clear the capture buffer to return silence
456 if (pContext->mLastBuf == pContext->mCurrentBuf) {
457 if (pContext->mStallCount < MAX_STALL_COUNT) {
458 if (++pContext->mStallCount == MAX_STALL_COUNT) {
459 memset(pContext->mCaptureBuf[pContext->mCurrentBuf ^ 1],
460 0x80,
461 pContext->mCaptureSize);
462 }
463 }
464 } else {
465 pContext->mStallCount = 0;
466 }
467 pContext->mLastBuf = pContext->mCurrentBuf;
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700468 } else {
469 memset(pReplyData, 0x80, pContext->mCaptureSize);
470 }
Eric Laurentdf8ab512011-11-10 10:02:18 -0800471
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700472 break;
473
474 default:
475 LOGW("Visualizer_command invalid command %d",cmdCode);
476 return -EINVAL;
477 }
478
479 return 0;
480}
481
Eric Laurent0fb66c22011-05-17 19:16:02 -0700482/* Effect Control Interface Implementation: get_descriptor */
483int Visualizer_getDescriptor(effect_handle_t self,
484 effect_descriptor_t *pDescriptor)
485{
486 VisualizerContext * pContext = (VisualizerContext *) self;
487
488 if (pContext == NULL || pDescriptor == NULL) {
Steve Block71f2cf12011-10-20 11:56:00 +0100489 ALOGV("Visualizer_getDescriptor() invalid param");
Eric Laurent0fb66c22011-05-17 19:16:02 -0700490 return -EINVAL;
491 }
492
493 memcpy(pDescriptor, &gVisualizerDescriptor, sizeof(effect_descriptor_t));
494
495 return 0;
496} /* end Visualizer_getDescriptor */
497
498// effect_handle_t interface implementation for visualizer effect
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700499const struct effect_interface_s gVisualizerInterface = {
500 Visualizer_process,
Eric Laurent0fb66c22011-05-17 19:16:02 -0700501 Visualizer_command,
Eric Laurent325b8e82011-06-17 18:54:16 -0700502 Visualizer_getDescriptor,
503 NULL,
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700504};
505
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700506
Eric Laurent0fb66c22011-05-17 19:16:02 -0700507audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
508 tag : AUDIO_EFFECT_LIBRARY_TAG,
509 version : EFFECT_LIBRARY_API_VERSION,
510 name : "Visualizer Library",
511 implementor : "The Android Open Source Project",
512 query_num_effects : VisualizerLib_QueryNumberEffects,
513 query_effect : VisualizerLib_QueryEffect,
514 create_effect : VisualizerLib_Create,
515 release_effect : VisualizerLib_Release,
516 get_descriptor : VisualizerLib_GetDescriptor,
517};
518
519}; // extern "C"