blob: bdb1a1cd969c1e668445f29155fd24a4a49381e8 [file] [log] [blame]
Eric Laurentda7581b2010-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 Laurent183dc772012-03-23 15:35:48 -070024#include <time.h>
Eric Laurent6d8b6942011-06-24 07:01:31 -070025#include <audio_effects/effect_visualizer.h>
Eric Laurentda7581b2010-07-02 08:12:41 -070026
Eric Laurentda7581b2010-07-02 08:12:41 -070027
Eric Laurente1315cf2011-05-17 19:16:02 -070028extern "C" {
29
30// effect_handle_t interface implementation for visualizer effect
31extern const struct effect_interface_s gVisualizerInterface;
Eric Laurentda7581b2010-07-02 08:12:41 -070032
33// Google Visualizer UUID: d069d9e0-8329-11df-9168-0002a5d5c51b
34const effect_descriptor_t gVisualizerDescriptor = {
35 {0xe46b26a0, 0xdddd, 0x11db, 0x8afd, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // type
36 {0xd069d9e0, 0x8329, 0x11df, 0x9168, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // uuid
Eric Laurente1315cf2011-05-17 19:16:02 -070037 EFFECT_CONTROL_API_VERSION,
Eric Laurentda7581b2010-07-02 08:12:41 -070038 (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST),
39 0, // TODO
40 1,
41 "Visualizer",
Eric Laurente1315cf2011-05-17 19:16:02 -070042 "The Android Open Source Project",
Eric Laurentda7581b2010-07-02 08:12:41 -070043};
44
45enum visualizer_state_e {
46 VISUALIZER_STATE_UNINITIALIZED,
47 VISUALIZER_STATE_INITIALIZED,
48 VISUALIZER_STATE_ACTIVE,
49};
50
Eric Laurent183dc772012-03-23 15:35:48 -070051// maximum time since last capture buffer update before resetting capture buffer. This means
Eric Laurent3df40a02011-11-10 10:02:18 -080052// that the framework has stopped playing audio and we must start returning silence
Eric Laurent183dc772012-03-23 15:35:48 -070053#define MAX_STALL_TIME_MS 1000
Eric Laurent3df40a02011-11-10 10:02:18 -080054
Eric Laurentda7581b2010-07-02 08:12:41 -070055struct VisualizerContext {
56 const struct effect_interface_s *mItfe;
57 effect_config_t mConfig;
Eric Laurentda7581b2010-07-02 08:12:41 -070058 uint32_t mCaptureIdx;
59 uint32_t mCaptureSize;
Eric Laurent3df40a02011-11-10 10:02:18 -080060 uint8_t mState;
61 uint8_t mCurrentBuf;
62 uint8_t mLastBuf;
Eric Laurent183dc772012-03-23 15:35:48 -070063 struct timespec mBufferUpdateTime;
Eric Laurentda7581b2010-07-02 08:12:41 -070064 uint8_t mCaptureBuf[2][VISUALIZER_CAPTURE_SIZE_MAX];
65};
66
Eric Laurentda7581b2010-07-02 08:12:41 -070067//
68//--- Local functions
69//
70
71void Visualizer_reset(VisualizerContext *pContext)
72{
73 pContext->mCaptureIdx = 0;
74 pContext->mCurrentBuf = 0;
Eric Laurent3df40a02011-11-10 10:02:18 -080075 pContext->mLastBuf = 1;
Eric Laurent183dc772012-03-23 15:35:48 -070076 pContext->mBufferUpdateTime.tv_sec = 0;
Eric Laurent0fa449c2010-09-24 11:52:04 -070077 memset(pContext->mCaptureBuf[0], 0x80, VISUALIZER_CAPTURE_SIZE_MAX);
78 memset(pContext->mCaptureBuf[1], 0x80, VISUALIZER_CAPTURE_SIZE_MAX);
Eric Laurentda7581b2010-07-02 08:12:41 -070079}
80
81//----------------------------------------------------------------------------
Eric Laurent3d5188b2011-12-16 15:30:36 -080082// Visualizer_setConfig()
Eric Laurentda7581b2010-07-02 08:12:41 -070083//----------------------------------------------------------------------------
84// Purpose: Set input and output audio configuration.
85//
86// Inputs:
87// pContext: effect engine context
88// pConfig: pointer to effect_config_t structure holding input and output
89// configuration parameters
90//
91// Outputs:
92//
93//----------------------------------------------------------------------------
94
Eric Laurent3d5188b2011-12-16 15:30:36 -080095int Visualizer_setConfig(VisualizerContext *pContext, effect_config_t *pConfig)
Eric Laurentda7581b2010-07-02 08:12:41 -070096{
Eric Laurent3d5188b2011-12-16 15:30:36 -080097 ALOGV("Visualizer_setConfig start");
Eric Laurentda7581b2010-07-02 08:12:41 -070098
99 if (pConfig->inputCfg.samplingRate != pConfig->outputCfg.samplingRate) return -EINVAL;
100 if (pConfig->inputCfg.channels != pConfig->outputCfg.channels) return -EINVAL;
101 if (pConfig->inputCfg.format != pConfig->outputCfg.format) return -EINVAL;
Eric Laurente1315cf2011-05-17 19:16:02 -0700102 if (pConfig->inputCfg.channels != AUDIO_CHANNEL_OUT_STEREO) return -EINVAL;
Eric Laurentda7581b2010-07-02 08:12:41 -0700103 if (pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_WRITE &&
104 pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_ACCUMULATE) return -EINVAL;
Eric Laurente1315cf2011-05-17 19:16:02 -0700105 if (pConfig->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) return -EINVAL;
Eric Laurentda7581b2010-07-02 08:12:41 -0700106
107 memcpy(&pContext->mConfig, pConfig, sizeof(effect_config_t));
108
109 Visualizer_reset(pContext);
110
111 return 0;
112}
113
114
115//----------------------------------------------------------------------------
Eric Laurent3d5188b2011-12-16 15:30:36 -0800116// Visualizer_getConfig()
117//----------------------------------------------------------------------------
118// Purpose: Get input and output audio configuration.
119//
120// Inputs:
121// pContext: effect engine context
122// pConfig: pointer to effect_config_t structure holding input and output
123// configuration parameters
124//
125// Outputs:
126//
127//----------------------------------------------------------------------------
128
129void Visualizer_getConfig(VisualizerContext *pContext, effect_config_t *pConfig)
130{
131 memcpy(pConfig, &pContext->mConfig, sizeof(effect_config_t));
132}
133
134
135//----------------------------------------------------------------------------
Eric Laurentda7581b2010-07-02 08:12:41 -0700136// Visualizer_init()
137//----------------------------------------------------------------------------
138// Purpose: Initialize engine with default configuration.
139//
140// Inputs:
141// pContext: effect engine context
142//
143// Outputs:
144//
145//----------------------------------------------------------------------------
146
147int Visualizer_init(VisualizerContext *pContext)
148{
149 pContext->mConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
Eric Laurente1315cf2011-05-17 19:16:02 -0700150 pContext->mConfig.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
151 pContext->mConfig.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
Eric Laurentda7581b2010-07-02 08:12:41 -0700152 pContext->mConfig.inputCfg.samplingRate = 44100;
153 pContext->mConfig.inputCfg.bufferProvider.getBuffer = NULL;
154 pContext->mConfig.inputCfg.bufferProvider.releaseBuffer = NULL;
155 pContext->mConfig.inputCfg.bufferProvider.cookie = NULL;
156 pContext->mConfig.inputCfg.mask = EFFECT_CONFIG_ALL;
157 pContext->mConfig.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE;
Eric Laurente1315cf2011-05-17 19:16:02 -0700158 pContext->mConfig.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
159 pContext->mConfig.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
Eric Laurentda7581b2010-07-02 08:12:41 -0700160 pContext->mConfig.outputCfg.samplingRate = 44100;
161 pContext->mConfig.outputCfg.bufferProvider.getBuffer = NULL;
162 pContext->mConfig.outputCfg.bufferProvider.releaseBuffer = NULL;
163 pContext->mConfig.outputCfg.bufferProvider.cookie = NULL;
164 pContext->mConfig.outputCfg.mask = EFFECT_CONFIG_ALL;
165
166 pContext->mCaptureSize = VISUALIZER_CAPTURE_SIZE_MAX;
167
Eric Laurent3d5188b2011-12-16 15:30:36 -0800168 Visualizer_setConfig(pContext, &pContext->mConfig);
Eric Laurentda7581b2010-07-02 08:12:41 -0700169
170 return 0;
171}
172
173//
174//--- Effect Library Interface Implementation
175//
176
Eric Laurente1315cf2011-05-17 19:16:02 -0700177int VisualizerLib_QueryNumberEffects(uint32_t *pNumEffects) {
Eric Laurentda7581b2010-07-02 08:12:41 -0700178 *pNumEffects = 1;
179 return 0;
180}
181
Eric Laurente1315cf2011-05-17 19:16:02 -0700182int VisualizerLib_QueryEffect(uint32_t index,
183 effect_descriptor_t *pDescriptor) {
Eric Laurentda7581b2010-07-02 08:12:41 -0700184 if (pDescriptor == NULL) {
185 return -EINVAL;
186 }
187 if (index > 0) {
188 return -EINVAL;
189 }
190 memcpy(pDescriptor, &gVisualizerDescriptor, sizeof(effect_descriptor_t));
191 return 0;
192}
193
Glenn Kasten5e92a782012-01-30 07:40:52 -0800194int VisualizerLib_Create(const effect_uuid_t *uuid,
Eric Laurente1315cf2011-05-17 19:16:02 -0700195 int32_t sessionId,
196 int32_t ioId,
197 effect_handle_t *pHandle) {
Eric Laurentda7581b2010-07-02 08:12:41 -0700198 int ret;
199 int i;
200
Eric Laurente1315cf2011-05-17 19:16:02 -0700201 if (pHandle == NULL || uuid == NULL) {
Eric Laurentda7581b2010-07-02 08:12:41 -0700202 return -EINVAL;
203 }
204
205 if (memcmp(uuid, &gVisualizerDescriptor.uuid, sizeof(effect_uuid_t)) != 0) {
206 return -EINVAL;
207 }
208
209 VisualizerContext *pContext = new VisualizerContext;
210
211 pContext->mItfe = &gVisualizerInterface;
212 pContext->mState = VISUALIZER_STATE_UNINITIALIZED;
213
214 ret = Visualizer_init(pContext);
215 if (ret < 0) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000216 ALOGW("VisualizerLib_Create() init failed");
Eric Laurentda7581b2010-07-02 08:12:41 -0700217 delete pContext;
218 return ret;
219 }
220
Eric Laurente1315cf2011-05-17 19:16:02 -0700221 *pHandle = (effect_handle_t)pContext;
Eric Laurentda7581b2010-07-02 08:12:41 -0700222
223 pContext->mState = VISUALIZER_STATE_INITIALIZED;
224
Steve Block3856b092011-10-20 11:56:00 +0100225 ALOGV("VisualizerLib_Create %p", pContext);
Eric Laurentda7581b2010-07-02 08:12:41 -0700226
227 return 0;
228
229}
230
Eric Laurente1315cf2011-05-17 19:16:02 -0700231int VisualizerLib_Release(effect_handle_t handle) {
232 VisualizerContext * pContext = (VisualizerContext *)handle;
Eric Laurentda7581b2010-07-02 08:12:41 -0700233
Steve Block3856b092011-10-20 11:56:00 +0100234 ALOGV("VisualizerLib_Release %p", handle);
Eric Laurentda7581b2010-07-02 08:12:41 -0700235 if (pContext == NULL) {
236 return -EINVAL;
237 }
238 pContext->mState = VISUALIZER_STATE_UNINITIALIZED;
239 delete pContext;
240
241 return 0;
242}
243
Glenn Kasten5e92a782012-01-30 07:40:52 -0800244int VisualizerLib_GetDescriptor(const effect_uuid_t *uuid,
Eric Laurente1315cf2011-05-17 19:16:02 -0700245 effect_descriptor_t *pDescriptor) {
246
247 if (pDescriptor == NULL || uuid == NULL){
Steve Block3856b092011-10-20 11:56:00 +0100248 ALOGV("VisualizerLib_GetDescriptor() called with NULL pointer");
Eric Laurente1315cf2011-05-17 19:16:02 -0700249 return -EINVAL;
250 }
251
252 if (memcmp(uuid, &gVisualizerDescriptor.uuid, sizeof(effect_uuid_t)) == 0) {
253 memcpy(pDescriptor, &gVisualizerDescriptor, sizeof(effect_descriptor_t));
254 return 0;
255 }
256
257 return -EINVAL;
258} /* end VisualizerLib_GetDescriptor */
259
Eric Laurentda7581b2010-07-02 08:12:41 -0700260//
261//--- Effect Control Interface Implementation
262//
263
264static inline int16_t clamp16(int32_t sample)
265{
266 if ((sample>>15) ^ (sample>>31))
267 sample = 0x7FFF ^ (sample>>31);
268 return sample;
269}
270
Eric Laurente1315cf2011-05-17 19:16:02 -0700271int Visualizer_process(
272 effect_handle_t self,audio_buffer_t *inBuffer, audio_buffer_t *outBuffer)
Eric Laurentda7581b2010-07-02 08:12:41 -0700273{
Eric Laurente1315cf2011-05-17 19:16:02 -0700274 VisualizerContext * pContext = (VisualizerContext *)self;
Eric Laurentda7581b2010-07-02 08:12:41 -0700275
276 if (pContext == NULL) {
277 return -EINVAL;
278 }
Eric Laurentda7581b2010-07-02 08:12:41 -0700279
280 if (inBuffer == NULL || inBuffer->raw == NULL ||
281 outBuffer == NULL || outBuffer->raw == NULL ||
282 inBuffer->frameCount != outBuffer->frameCount ||
283 inBuffer->frameCount == 0) {
284 return -EINVAL;
285 }
286
287 // all code below assumes stereo 16 bit PCM output and input
Eric Laurent0e75f0f2010-09-21 14:52:01 -0700288
289 // derive capture scaling factor from peak value in current buffer
290 // this gives more interesting captures for display.
291 int32_t shift = 32;
Marco Nelissen64c3bde2010-10-27 09:06:01 -0700292 int len = inBuffer->frameCount * 2;
Eric Laurente1315cf2011-05-17 19:16:02 -0700293 for (int i = 0; i < len; i++) {
Eric Laurent0e75f0f2010-09-21 14:52:01 -0700294 int32_t smp = inBuffer->s16[i];
Marco Nelissen64c3bde2010-10-27 09:06:01 -0700295 if (smp < 0) smp = -smp - 1; // take care to keep the max negative in range
Eric Laurent0e75f0f2010-09-21 14:52:01 -0700296 int32_t clz = __builtin_clz(smp);
297 if (shift > clz) shift = clz;
298 }
Marco Nelissen64c3bde2010-10-27 09:06:01 -0700299 // A maximum amplitude signal will have 17 leading zeros, which we want to
300 // translate to a shift of 8 (for converting 16 bit to 8 bit)
301 shift = 25 - shift;
302 // Never scale by less than 8 to avoid returning unaltered PCM signal.
303 if (shift < 3) {
304 shift = 3;
Eric Laurent0e75f0f2010-09-21 14:52:01 -0700305 }
Marco Nelissen64c3bde2010-10-27 09:06:01 -0700306 // add one to combine the division by 2 needed after summing left and right channels below
307 shift++;
Eric Laurent0e75f0f2010-09-21 14:52:01 -0700308
Eric Laurentda7581b2010-07-02 08:12:41 -0700309 uint32_t captIdx;
310 uint32_t inIdx;
311 uint8_t *buf = pContext->mCaptureBuf[pContext->mCurrentBuf];
312 for (inIdx = 0, captIdx = pContext->mCaptureIdx;
313 inIdx < inBuffer->frameCount && captIdx < pContext->mCaptureSize;
314 inIdx++, captIdx++) {
315 int32_t smp = inBuffer->s16[2 * inIdx] + inBuffer->s16[2 * inIdx + 1];
Marco Nelissen64c3bde2010-10-27 09:06:01 -0700316 smp = smp >> shift;
Eric Laurentda7581b2010-07-02 08:12:41 -0700317 buf[captIdx] = ((uint8_t)smp)^0x80;
318 }
319 pContext->mCaptureIdx = captIdx;
320
321 // go to next buffer when buffer full
322 if (pContext->mCaptureIdx == pContext->mCaptureSize) {
323 pContext->mCurrentBuf ^= 1;
324 pContext->mCaptureIdx = 0;
Eric Laurent183dc772012-03-23 15:35:48 -0700325
326 // update last buffer update time stamp
327 if (clock_gettime(CLOCK_MONOTONIC, &pContext->mBufferUpdateTime) < 0) {
328 pContext->mBufferUpdateTime.tv_sec = 0;
329 }
Eric Laurentda7581b2010-07-02 08:12:41 -0700330 }
331
332 if (inBuffer->raw != outBuffer->raw) {
333 if (pContext->mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
334 for (size_t i = 0; i < outBuffer->frameCount*2; i++) {
335 outBuffer->s16[i] = clamp16(outBuffer->s16[i] + inBuffer->s16[i]);
336 }
337 } else {
338 memcpy(outBuffer->raw, inBuffer->raw, outBuffer->frameCount * 2 * sizeof(int16_t));
339 }
340 }
Eric Laurentf997cab2010-07-19 06:24:46 -0700341 if (pContext->mState != VISUALIZER_STATE_ACTIVE) {
342 return -ENODATA;
343 }
Eric Laurentda7581b2010-07-02 08:12:41 -0700344 return 0;
345} // end Visualizer_process
346
Eric Laurente1315cf2011-05-17 19:16:02 -0700347int Visualizer_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
Eric Laurent25f43952010-07-28 05:40:18 -0700348 void *pCmdData, uint32_t *replySize, void *pReplyData) {
Eric Laurentda7581b2010-07-02 08:12:41 -0700349
Eric Laurente1315cf2011-05-17 19:16:02 -0700350 VisualizerContext * pContext = (VisualizerContext *)self;
Eric Laurentda7581b2010-07-02 08:12:41 -0700351 int retsize;
352
353 if (pContext == NULL || pContext->mState == VISUALIZER_STATE_UNINITIALIZED) {
354 return -EINVAL;
355 }
356
Steve Block3856b092011-10-20 11:56:00 +0100357// ALOGV("Visualizer_command command %d cmdSize %d",cmdCode, cmdSize);
Eric Laurentda7581b2010-07-02 08:12:41 -0700358
359 switch (cmdCode) {
360 case EFFECT_CMD_INIT:
361 if (pReplyData == NULL || *replySize != sizeof(int)) {
362 return -EINVAL;
363 }
364 *(int *) pReplyData = Visualizer_init(pContext);
365 break;
Eric Laurent3d5188b2011-12-16 15:30:36 -0800366 case EFFECT_CMD_SET_CONFIG:
Eric Laurentda7581b2010-07-02 08:12:41 -0700367 if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
368 || pReplyData == NULL || *replySize != sizeof(int)) {
369 return -EINVAL;
370 }
Eric Laurent3d5188b2011-12-16 15:30:36 -0800371 *(int *) pReplyData = Visualizer_setConfig(pContext,
Eric Laurentda7581b2010-07-02 08:12:41 -0700372 (effect_config_t *) pCmdData);
373 break;
Eric Laurent3d5188b2011-12-16 15:30:36 -0800374 case EFFECT_CMD_GET_CONFIG:
375 if (pReplyData == NULL ||
376 *replySize != sizeof(effect_config_t)) {
377 return -EINVAL;
378 }
379 Visualizer_getConfig(pContext, (effect_config_t *)pReplyData);
380 break;
Eric Laurentda7581b2010-07-02 08:12:41 -0700381 case EFFECT_CMD_RESET:
382 Visualizer_reset(pContext);
383 break;
384 case EFFECT_CMD_ENABLE:
385 if (pReplyData == NULL || *replySize != sizeof(int)) {
386 return -EINVAL;
387 }
388 if (pContext->mState != VISUALIZER_STATE_INITIALIZED) {
389 return -ENOSYS;
390 }
391 pContext->mState = VISUALIZER_STATE_ACTIVE;
Steve Block3856b092011-10-20 11:56:00 +0100392 ALOGV("EFFECT_CMD_ENABLE() OK");
Eric Laurentda7581b2010-07-02 08:12:41 -0700393 *(int *)pReplyData = 0;
394 break;
395 case EFFECT_CMD_DISABLE:
396 if (pReplyData == NULL || *replySize != sizeof(int)) {
397 return -EINVAL;
398 }
399 if (pContext->mState != VISUALIZER_STATE_ACTIVE) {
400 return -ENOSYS;
401 }
402 pContext->mState = VISUALIZER_STATE_INITIALIZED;
Steve Block3856b092011-10-20 11:56:00 +0100403 ALOGV("EFFECT_CMD_DISABLE() OK");
Eric Laurentda7581b2010-07-02 08:12:41 -0700404 *(int *)pReplyData = 0;
405 break;
406 case EFFECT_CMD_GET_PARAM: {
407 if (pCmdData == NULL ||
408 cmdSize != (int)(sizeof(effect_param_t) + sizeof(uint32_t)) ||
409 pReplyData == NULL ||
410 *replySize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint32_t))) {
411 return -EINVAL;
412 }
413 memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + sizeof(uint32_t));
414 effect_param_t *p = (effect_param_t *)pReplyData;
415 p->status = 0;
416 *replySize = sizeof(effect_param_t) + sizeof(uint32_t);
417 if (p->psize != sizeof(uint32_t) ||
Eric Laurent6d8b6942011-06-24 07:01:31 -0700418 *(uint32_t *)p->data != VISUALIZER_PARAM_CAPTURE_SIZE) {
Eric Laurentda7581b2010-07-02 08:12:41 -0700419 p->status = -EINVAL;
420 break;
421 }
Steve Block3856b092011-10-20 11:56:00 +0100422 ALOGV("get mCaptureSize = %d", pContext->mCaptureSize);
Eric Laurentda7581b2010-07-02 08:12:41 -0700423 *((uint32_t *)p->data + 1) = pContext->mCaptureSize;
424 p->vsize = sizeof(uint32_t);
425 *replySize += sizeof(uint32_t);
426 } break;
427 case EFFECT_CMD_SET_PARAM: {
428 if (pCmdData == NULL ||
429 cmdSize != (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint32_t)) ||
430 pReplyData == NULL || *replySize != sizeof(int32_t)) {
431 return -EINVAL;
432 }
433 *(int32_t *)pReplyData = 0;
434 effect_param_t *p = (effect_param_t *)pCmdData;
435 if (p->psize != sizeof(uint32_t) ||
436 p->vsize != sizeof(uint32_t) ||
Eric Laurent6d8b6942011-06-24 07:01:31 -0700437 *(uint32_t *)p->data != VISUALIZER_PARAM_CAPTURE_SIZE) {
Eric Laurentda7581b2010-07-02 08:12:41 -0700438 *(int32_t *)pReplyData = -EINVAL;
439 break;;
440 }
441 pContext->mCaptureSize = *((uint32_t *)p->data + 1);
Steve Block3856b092011-10-20 11:56:00 +0100442 ALOGV("set mCaptureSize = %d", pContext->mCaptureSize);
Eric Laurentda7581b2010-07-02 08:12:41 -0700443 } break;
444 case EFFECT_CMD_SET_DEVICE:
445 case EFFECT_CMD_SET_VOLUME:
446 case EFFECT_CMD_SET_AUDIO_MODE:
447 break;
448
449
Eric Laurent6d8b6942011-06-24 07:01:31 -0700450 case VISUALIZER_CMD_CAPTURE:
Eric Laurent0e75f0f2010-09-21 14:52:01 -0700451 if (pReplyData == NULL || *replySize != pContext->mCaptureSize) {
Steve Block3856b092011-10-20 11:56:00 +0100452 ALOGV("VISUALIZER_CMD_CAPTURE() error *replySize %d pContext->mCaptureSize %d",
Eric Laurentda7581b2010-07-02 08:12:41 -0700453 *replySize, pContext->mCaptureSize);
454 return -EINVAL;
455 }
456 if (pContext->mState == VISUALIZER_STATE_ACTIVE) {
457 memcpy(pReplyData,
458 pContext->mCaptureBuf[pContext->mCurrentBuf ^ 1],
459 pContext->mCaptureSize);
Eric Laurent3df40a02011-11-10 10:02:18 -0800460 // if audio framework has stopped playing audio although the effect is still
461 // active we must clear the capture buffer to return silence
Eric Laurent183dc772012-03-23 15:35:48 -0700462 if ((pContext->mLastBuf == pContext->mCurrentBuf) &&
463 (pContext->mBufferUpdateTime.tv_sec != 0)) {
464 struct timespec ts;
465 if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
466 time_t secs = ts.tv_sec - pContext->mBufferUpdateTime.tv_sec;
467 long nsec = ts.tv_nsec - pContext->mBufferUpdateTime.tv_nsec;
468 if (nsec < 0) {
469 --secs;
470 nsec += 1000000000;
471 }
472 uint32_t deltaMs = secs * 1000 + nsec / 1000000;
473 if (deltaMs > MAX_STALL_TIME_MS) {
474 ALOGV("capture going to idle");
475 pContext->mBufferUpdateTime.tv_sec = 0;
Eric Laurent3df40a02011-11-10 10:02:18 -0800476 memset(pContext->mCaptureBuf[pContext->mCurrentBuf ^ 1],
477 0x80,
478 pContext->mCaptureSize);
479 }
480 }
Eric Laurent3df40a02011-11-10 10:02:18 -0800481 }
482 pContext->mLastBuf = pContext->mCurrentBuf;
Eric Laurentda7581b2010-07-02 08:12:41 -0700483 } else {
484 memset(pReplyData, 0x80, pContext->mCaptureSize);
485 }
Eric Laurent3df40a02011-11-10 10:02:18 -0800486
Eric Laurentda7581b2010-07-02 08:12:41 -0700487 break;
488
489 default:
Steve Block5ff1dd52012-01-05 23:22:43 +0000490 ALOGW("Visualizer_command invalid command %d",cmdCode);
Eric Laurentda7581b2010-07-02 08:12:41 -0700491 return -EINVAL;
492 }
493
494 return 0;
495}
496
Eric Laurente1315cf2011-05-17 19:16:02 -0700497/* Effect Control Interface Implementation: get_descriptor */
498int Visualizer_getDescriptor(effect_handle_t self,
499 effect_descriptor_t *pDescriptor)
500{
501 VisualizerContext * pContext = (VisualizerContext *) self;
502
503 if (pContext == NULL || pDescriptor == NULL) {
Steve Block3856b092011-10-20 11:56:00 +0100504 ALOGV("Visualizer_getDescriptor() invalid param");
Eric Laurente1315cf2011-05-17 19:16:02 -0700505 return -EINVAL;
506 }
507
508 memcpy(pDescriptor, &gVisualizerDescriptor, sizeof(effect_descriptor_t));
509
510 return 0;
511} /* end Visualizer_getDescriptor */
512
513// effect_handle_t interface implementation for visualizer effect
Eric Laurentda7581b2010-07-02 08:12:41 -0700514const struct effect_interface_s gVisualizerInterface = {
515 Visualizer_process,
Eric Laurente1315cf2011-05-17 19:16:02 -0700516 Visualizer_command,
Eric Laurentba7b8f82011-06-17 18:54:16 -0700517 Visualizer_getDescriptor,
518 NULL,
Eric Laurentda7581b2010-07-02 08:12:41 -0700519};
520
Eric Laurentda7581b2010-07-02 08:12:41 -0700521
Eric Laurente1315cf2011-05-17 19:16:02 -0700522audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
523 tag : AUDIO_EFFECT_LIBRARY_TAG,
524 version : EFFECT_LIBRARY_API_VERSION,
525 name : "Visualizer Library",
526 implementor : "The Android Open Source Project",
527 query_num_effects : VisualizerLib_QueryNumberEffects,
528 query_effect : VisualizerLib_QueryEffect,
529 create_effect : VisualizerLib_Create,
530 release_effect : VisualizerLib_Release,
531 get_descriptor : VisualizerLib_GetDescriptor,
532};
533
534}; // extern "C"