blob: 44d05cd120454469071f8151a7f882dd75b5c073 [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
Jean-Michel Trivi3476de62012-04-15 17:15:07 -070017#define LOG_TAG "EffectVisualizer"
Eric Laurentda7581b2010-07-02 08:12:41 -070018//#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;
Jean-Michel Trivi3476de62012-04-15 17:15:07 -070060 uint32_t mScalingMode;
Eric Laurent3df40a02011-11-10 10:02:18 -080061 uint8_t mState;
62 uint8_t mCurrentBuf;
63 uint8_t mLastBuf;
Eric Laurent183dc772012-03-23 15:35:48 -070064 struct timespec mBufferUpdateTime;
Eric Laurentda7581b2010-07-02 08:12:41 -070065 uint8_t mCaptureBuf[2][VISUALIZER_CAPTURE_SIZE_MAX];
66};
67
Eric Laurentda7581b2010-07-02 08:12:41 -070068//
69//--- Local functions
70//
71
72void Visualizer_reset(VisualizerContext *pContext)
73{
74 pContext->mCaptureIdx = 0;
75 pContext->mCurrentBuf = 0;
Eric Laurent3df40a02011-11-10 10:02:18 -080076 pContext->mLastBuf = 1;
Eric Laurent183dc772012-03-23 15:35:48 -070077 pContext->mBufferUpdateTime.tv_sec = 0;
Eric Laurent0fa449c2010-09-24 11:52:04 -070078 memset(pContext->mCaptureBuf[0], 0x80, VISUALIZER_CAPTURE_SIZE_MAX);
79 memset(pContext->mCaptureBuf[1], 0x80, VISUALIZER_CAPTURE_SIZE_MAX);
Eric Laurentda7581b2010-07-02 08:12:41 -070080}
81
82//----------------------------------------------------------------------------
Eric Laurent3d5188b2011-12-16 15:30:36 -080083// Visualizer_setConfig()
Eric Laurentda7581b2010-07-02 08:12:41 -070084//----------------------------------------------------------------------------
85// Purpose: Set input and output audio configuration.
86//
87// Inputs:
88// pContext: effect engine context
89// pConfig: pointer to effect_config_t structure holding input and output
90// configuration parameters
91//
92// Outputs:
93//
94//----------------------------------------------------------------------------
95
Eric Laurent3d5188b2011-12-16 15:30:36 -080096int Visualizer_setConfig(VisualizerContext *pContext, effect_config_t *pConfig)
Eric Laurentda7581b2010-07-02 08:12:41 -070097{
Eric Laurent3d5188b2011-12-16 15:30:36 -080098 ALOGV("Visualizer_setConfig start");
Eric Laurentda7581b2010-07-02 08:12:41 -070099
100 if (pConfig->inputCfg.samplingRate != pConfig->outputCfg.samplingRate) return -EINVAL;
101 if (pConfig->inputCfg.channels != pConfig->outputCfg.channels) return -EINVAL;
102 if (pConfig->inputCfg.format != pConfig->outputCfg.format) return -EINVAL;
Eric Laurente1315cf2011-05-17 19:16:02 -0700103 if (pConfig->inputCfg.channels != AUDIO_CHANNEL_OUT_STEREO) return -EINVAL;
Eric Laurentda7581b2010-07-02 08:12:41 -0700104 if (pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_WRITE &&
105 pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_ACCUMULATE) return -EINVAL;
Eric Laurente1315cf2011-05-17 19:16:02 -0700106 if (pConfig->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) return -EINVAL;
Eric Laurentda7581b2010-07-02 08:12:41 -0700107
108 memcpy(&pContext->mConfig, pConfig, sizeof(effect_config_t));
109
110 Visualizer_reset(pContext);
111
112 return 0;
113}
114
115
116//----------------------------------------------------------------------------
Eric Laurent3d5188b2011-12-16 15:30:36 -0800117// Visualizer_getConfig()
118//----------------------------------------------------------------------------
119// Purpose: Get input and output audio configuration.
120//
121// Inputs:
122// pContext: effect engine context
123// pConfig: pointer to effect_config_t structure holding input and output
124// configuration parameters
125//
126// Outputs:
127//
128//----------------------------------------------------------------------------
129
130void Visualizer_getConfig(VisualizerContext *pContext, effect_config_t *pConfig)
131{
132 memcpy(pConfig, &pContext->mConfig, sizeof(effect_config_t));
133}
134
135
136//----------------------------------------------------------------------------
Eric Laurentda7581b2010-07-02 08:12:41 -0700137// Visualizer_init()
138//----------------------------------------------------------------------------
139// Purpose: Initialize engine with default configuration.
140//
141// Inputs:
142// pContext: effect engine context
143//
144// Outputs:
145//
146//----------------------------------------------------------------------------
147
148int Visualizer_init(VisualizerContext *pContext)
149{
150 pContext->mConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
Eric Laurente1315cf2011-05-17 19:16:02 -0700151 pContext->mConfig.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
152 pContext->mConfig.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
Eric Laurentda7581b2010-07-02 08:12:41 -0700153 pContext->mConfig.inputCfg.samplingRate = 44100;
154 pContext->mConfig.inputCfg.bufferProvider.getBuffer = NULL;
155 pContext->mConfig.inputCfg.bufferProvider.releaseBuffer = NULL;
156 pContext->mConfig.inputCfg.bufferProvider.cookie = NULL;
157 pContext->mConfig.inputCfg.mask = EFFECT_CONFIG_ALL;
158 pContext->mConfig.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE;
Eric Laurente1315cf2011-05-17 19:16:02 -0700159 pContext->mConfig.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
160 pContext->mConfig.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
Eric Laurentda7581b2010-07-02 08:12:41 -0700161 pContext->mConfig.outputCfg.samplingRate = 44100;
162 pContext->mConfig.outputCfg.bufferProvider.getBuffer = NULL;
163 pContext->mConfig.outputCfg.bufferProvider.releaseBuffer = NULL;
164 pContext->mConfig.outputCfg.bufferProvider.cookie = NULL;
165 pContext->mConfig.outputCfg.mask = EFFECT_CONFIG_ALL;
166
167 pContext->mCaptureSize = VISUALIZER_CAPTURE_SIZE_MAX;
Jean-Michel Trivi3476de62012-04-15 17:15:07 -0700168 pContext->mScalingMode = VISUALIZER_SCALING_MODE_NORMALIZED;
Eric Laurentda7581b2010-07-02 08:12:41 -0700169
Eric Laurent3d5188b2011-12-16 15:30:36 -0800170 Visualizer_setConfig(pContext, &pContext->mConfig);
Eric Laurentda7581b2010-07-02 08:12:41 -0700171
172 return 0;
173}
174
175//
176//--- Effect Library Interface Implementation
177//
178
Eric Laurente1315cf2011-05-17 19:16:02 -0700179int VisualizerLib_QueryNumberEffects(uint32_t *pNumEffects) {
Eric Laurentda7581b2010-07-02 08:12:41 -0700180 *pNumEffects = 1;
181 return 0;
182}
183
Eric Laurente1315cf2011-05-17 19:16:02 -0700184int VisualizerLib_QueryEffect(uint32_t index,
185 effect_descriptor_t *pDescriptor) {
Eric Laurentda7581b2010-07-02 08:12:41 -0700186 if (pDescriptor == NULL) {
187 return -EINVAL;
188 }
189 if (index > 0) {
190 return -EINVAL;
191 }
192 memcpy(pDescriptor, &gVisualizerDescriptor, sizeof(effect_descriptor_t));
193 return 0;
194}
195
Glenn Kasten5e92a782012-01-30 07:40:52 -0800196int VisualizerLib_Create(const effect_uuid_t *uuid,
Eric Laurente1315cf2011-05-17 19:16:02 -0700197 int32_t sessionId,
198 int32_t ioId,
199 effect_handle_t *pHandle) {
Eric Laurentda7581b2010-07-02 08:12:41 -0700200 int ret;
201 int i;
202
Eric Laurente1315cf2011-05-17 19:16:02 -0700203 if (pHandle == NULL || uuid == NULL) {
Eric Laurentda7581b2010-07-02 08:12:41 -0700204 return -EINVAL;
205 }
206
207 if (memcmp(uuid, &gVisualizerDescriptor.uuid, sizeof(effect_uuid_t)) != 0) {
208 return -EINVAL;
209 }
210
211 VisualizerContext *pContext = new VisualizerContext;
212
213 pContext->mItfe = &gVisualizerInterface;
214 pContext->mState = VISUALIZER_STATE_UNINITIALIZED;
215
216 ret = Visualizer_init(pContext);
217 if (ret < 0) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000218 ALOGW("VisualizerLib_Create() init failed");
Eric Laurentda7581b2010-07-02 08:12:41 -0700219 delete pContext;
220 return ret;
221 }
222
Eric Laurente1315cf2011-05-17 19:16:02 -0700223 *pHandle = (effect_handle_t)pContext;
Eric Laurentda7581b2010-07-02 08:12:41 -0700224
225 pContext->mState = VISUALIZER_STATE_INITIALIZED;
226
Steve Block3856b092011-10-20 11:56:00 +0100227 ALOGV("VisualizerLib_Create %p", pContext);
Eric Laurentda7581b2010-07-02 08:12:41 -0700228
229 return 0;
230
231}
232
Eric Laurente1315cf2011-05-17 19:16:02 -0700233int VisualizerLib_Release(effect_handle_t handle) {
234 VisualizerContext * pContext = (VisualizerContext *)handle;
Eric Laurentda7581b2010-07-02 08:12:41 -0700235
Steve Block3856b092011-10-20 11:56:00 +0100236 ALOGV("VisualizerLib_Release %p", handle);
Eric Laurentda7581b2010-07-02 08:12:41 -0700237 if (pContext == NULL) {
238 return -EINVAL;
239 }
240 pContext->mState = VISUALIZER_STATE_UNINITIALIZED;
241 delete pContext;
242
243 return 0;
244}
245
Glenn Kasten5e92a782012-01-30 07:40:52 -0800246int VisualizerLib_GetDescriptor(const effect_uuid_t *uuid,
Eric Laurente1315cf2011-05-17 19:16:02 -0700247 effect_descriptor_t *pDescriptor) {
248
249 if (pDescriptor == NULL || uuid == NULL){
Steve Block3856b092011-10-20 11:56:00 +0100250 ALOGV("VisualizerLib_GetDescriptor() called with NULL pointer");
Eric Laurente1315cf2011-05-17 19:16:02 -0700251 return -EINVAL;
252 }
253
254 if (memcmp(uuid, &gVisualizerDescriptor.uuid, sizeof(effect_uuid_t)) == 0) {
255 memcpy(pDescriptor, &gVisualizerDescriptor, sizeof(effect_descriptor_t));
256 return 0;
257 }
258
259 return -EINVAL;
260} /* end VisualizerLib_GetDescriptor */
261
Eric Laurentda7581b2010-07-02 08:12:41 -0700262//
263//--- Effect Control Interface Implementation
264//
265
266static inline int16_t clamp16(int32_t sample)
267{
268 if ((sample>>15) ^ (sample>>31))
269 sample = 0x7FFF ^ (sample>>31);
270 return sample;
271}
272
Eric Laurente1315cf2011-05-17 19:16:02 -0700273int Visualizer_process(
274 effect_handle_t self,audio_buffer_t *inBuffer, audio_buffer_t *outBuffer)
Eric Laurentda7581b2010-07-02 08:12:41 -0700275{
Eric Laurente1315cf2011-05-17 19:16:02 -0700276 VisualizerContext * pContext = (VisualizerContext *)self;
Eric Laurentda7581b2010-07-02 08:12:41 -0700277
278 if (pContext == NULL) {
279 return -EINVAL;
280 }
Eric Laurentda7581b2010-07-02 08:12:41 -0700281
282 if (inBuffer == NULL || inBuffer->raw == NULL ||
283 outBuffer == NULL || outBuffer->raw == NULL ||
284 inBuffer->frameCount != outBuffer->frameCount ||
285 inBuffer->frameCount == 0) {
286 return -EINVAL;
287 }
288
289 // all code below assumes stereo 16 bit PCM output and input
Jean-Michel Trivi3476de62012-04-15 17:15:07 -0700290 int32_t shift;
Eric Laurent0e75f0f2010-09-21 14:52:01 -0700291
Jean-Michel Trivi3476de62012-04-15 17:15:07 -0700292 if (pContext->mScalingMode == VISUALIZER_SCALING_MODE_NORMALIZED) {
293 // derive capture scaling factor from peak value in current buffer
294 // this gives more interesting captures for display.
295 shift = 32;
296 int len = inBuffer->frameCount * 2;
297 for (int i = 0; i < len; i++) {
298 int32_t smp = inBuffer->s16[i];
299 if (smp < 0) smp = -smp - 1; // take care to keep the max negative in range
300 int32_t clz = __builtin_clz(smp);
301 if (shift > clz) shift = clz;
302 }
303 // A maximum amplitude signal will have 17 leading zeros, which we want to
304 // translate to a shift of 8 (for converting 16 bit to 8 bit)
305 shift = 25 - shift;
306 // Never scale by less than 8 to avoid returning unaltered PCM signal.
307 if (shift < 3) {
308 shift = 3;
309 }
310 // add one to combine the division by 2 needed after summing left and right channels below
311 shift++;
312 } else {
313 assert(pContext->mScalingMode == VISUALIZER_SCALING_MODE_AS_PLAYED);
314 shift = 9;
Eric Laurent0e75f0f2010-09-21 14:52:01 -0700315 }
Eric Laurent0e75f0f2010-09-21 14:52:01 -0700316
Eric Laurentda7581b2010-07-02 08:12:41 -0700317 uint32_t captIdx;
318 uint32_t inIdx;
319 uint8_t *buf = pContext->mCaptureBuf[pContext->mCurrentBuf];
320 for (inIdx = 0, captIdx = pContext->mCaptureIdx;
321 inIdx < inBuffer->frameCount && captIdx < pContext->mCaptureSize;
322 inIdx++, captIdx++) {
323 int32_t smp = inBuffer->s16[2 * inIdx] + inBuffer->s16[2 * inIdx + 1];
Marco Nelissen64c3bde2010-10-27 09:06:01 -0700324 smp = smp >> shift;
Eric Laurentda7581b2010-07-02 08:12:41 -0700325 buf[captIdx] = ((uint8_t)smp)^0x80;
326 }
327 pContext->mCaptureIdx = captIdx;
328
329 // go to next buffer when buffer full
330 if (pContext->mCaptureIdx == pContext->mCaptureSize) {
331 pContext->mCurrentBuf ^= 1;
332 pContext->mCaptureIdx = 0;
Eric Laurent183dc772012-03-23 15:35:48 -0700333
334 // update last buffer update time stamp
335 if (clock_gettime(CLOCK_MONOTONIC, &pContext->mBufferUpdateTime) < 0) {
336 pContext->mBufferUpdateTime.tv_sec = 0;
337 }
Eric Laurentda7581b2010-07-02 08:12:41 -0700338 }
339
340 if (inBuffer->raw != outBuffer->raw) {
341 if (pContext->mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
342 for (size_t i = 0; i < outBuffer->frameCount*2; i++) {
343 outBuffer->s16[i] = clamp16(outBuffer->s16[i] + inBuffer->s16[i]);
344 }
345 } else {
346 memcpy(outBuffer->raw, inBuffer->raw, outBuffer->frameCount * 2 * sizeof(int16_t));
347 }
348 }
Eric Laurentf997cab2010-07-19 06:24:46 -0700349 if (pContext->mState != VISUALIZER_STATE_ACTIVE) {
350 return -ENODATA;
351 }
Eric Laurentda7581b2010-07-02 08:12:41 -0700352 return 0;
353} // end Visualizer_process
354
Eric Laurente1315cf2011-05-17 19:16:02 -0700355int Visualizer_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
Eric Laurent25f43952010-07-28 05:40:18 -0700356 void *pCmdData, uint32_t *replySize, void *pReplyData) {
Eric Laurentda7581b2010-07-02 08:12:41 -0700357
Eric Laurente1315cf2011-05-17 19:16:02 -0700358 VisualizerContext * pContext = (VisualizerContext *)self;
Eric Laurentda7581b2010-07-02 08:12:41 -0700359 int retsize;
360
361 if (pContext == NULL || pContext->mState == VISUALIZER_STATE_UNINITIALIZED) {
362 return -EINVAL;
363 }
364
Steve Block3856b092011-10-20 11:56:00 +0100365// ALOGV("Visualizer_command command %d cmdSize %d",cmdCode, cmdSize);
Eric Laurentda7581b2010-07-02 08:12:41 -0700366
367 switch (cmdCode) {
368 case EFFECT_CMD_INIT:
369 if (pReplyData == NULL || *replySize != sizeof(int)) {
370 return -EINVAL;
371 }
372 *(int *) pReplyData = Visualizer_init(pContext);
373 break;
Eric Laurent3d5188b2011-12-16 15:30:36 -0800374 case EFFECT_CMD_SET_CONFIG:
Eric Laurentda7581b2010-07-02 08:12:41 -0700375 if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
376 || pReplyData == NULL || *replySize != sizeof(int)) {
377 return -EINVAL;
378 }
Eric Laurent3d5188b2011-12-16 15:30:36 -0800379 *(int *) pReplyData = Visualizer_setConfig(pContext,
Eric Laurentda7581b2010-07-02 08:12:41 -0700380 (effect_config_t *) pCmdData);
381 break;
Eric Laurent3d5188b2011-12-16 15:30:36 -0800382 case EFFECT_CMD_GET_CONFIG:
383 if (pReplyData == NULL ||
384 *replySize != sizeof(effect_config_t)) {
385 return -EINVAL;
386 }
387 Visualizer_getConfig(pContext, (effect_config_t *)pReplyData);
388 break;
Eric Laurentda7581b2010-07-02 08:12:41 -0700389 case EFFECT_CMD_RESET:
390 Visualizer_reset(pContext);
391 break;
392 case EFFECT_CMD_ENABLE:
393 if (pReplyData == NULL || *replySize != sizeof(int)) {
394 return -EINVAL;
395 }
396 if (pContext->mState != VISUALIZER_STATE_INITIALIZED) {
397 return -ENOSYS;
398 }
399 pContext->mState = VISUALIZER_STATE_ACTIVE;
Steve Block3856b092011-10-20 11:56:00 +0100400 ALOGV("EFFECT_CMD_ENABLE() OK");
Eric Laurentda7581b2010-07-02 08:12:41 -0700401 *(int *)pReplyData = 0;
402 break;
403 case EFFECT_CMD_DISABLE:
404 if (pReplyData == NULL || *replySize != sizeof(int)) {
405 return -EINVAL;
406 }
407 if (pContext->mState != VISUALIZER_STATE_ACTIVE) {
408 return -ENOSYS;
409 }
410 pContext->mState = VISUALIZER_STATE_INITIALIZED;
Steve Block3856b092011-10-20 11:56:00 +0100411 ALOGV("EFFECT_CMD_DISABLE() OK");
Eric Laurentda7581b2010-07-02 08:12:41 -0700412 *(int *)pReplyData = 0;
413 break;
414 case EFFECT_CMD_GET_PARAM: {
415 if (pCmdData == NULL ||
416 cmdSize != (int)(sizeof(effect_param_t) + sizeof(uint32_t)) ||
417 pReplyData == NULL ||
418 *replySize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint32_t))) {
419 return -EINVAL;
420 }
421 memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + sizeof(uint32_t));
422 effect_param_t *p = (effect_param_t *)pReplyData;
423 p->status = 0;
424 *replySize = sizeof(effect_param_t) + sizeof(uint32_t);
Jean-Michel Trivi3476de62012-04-15 17:15:07 -0700425 if (p->psize != sizeof(uint32_t)) {
Eric Laurentda7581b2010-07-02 08:12:41 -0700426 p->status = -EINVAL;
427 break;
428 }
Jean-Michel Trivi3476de62012-04-15 17:15:07 -0700429 switch (*(uint32_t *)p->data) {
430 case VISUALIZER_PARAM_CAPTURE_SIZE:
431 ALOGV("get mCaptureSize = %d", pContext->mCaptureSize);
432 *((uint32_t *)p->data + 1) = pContext->mCaptureSize;
433 p->vsize = sizeof(uint32_t);
434 *replySize += sizeof(uint32_t);
435 break;
436 case VISUALIZER_PARAM_SCALING_MODE:
437 ALOGV("get mScalingMode = %d", pContext->mScalingMode);
438 *((uint32_t *)p->data + 1) = pContext->mScalingMode;
439 p->vsize = sizeof(uint32_t);
440 *replySize += sizeof(uint32_t);
441 break;
442 default:
443 p->status = -EINVAL;
444 }
Eric Laurentda7581b2010-07-02 08:12:41 -0700445 } break;
446 case EFFECT_CMD_SET_PARAM: {
447 if (pCmdData == NULL ||
448 cmdSize != (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint32_t)) ||
449 pReplyData == NULL || *replySize != sizeof(int32_t)) {
450 return -EINVAL;
451 }
452 *(int32_t *)pReplyData = 0;
453 effect_param_t *p = (effect_param_t *)pCmdData;
Jean-Michel Trivi3476de62012-04-15 17:15:07 -0700454 if (p->psize != sizeof(uint32_t) || p->vsize != sizeof(uint32_t)) {
Eric Laurentda7581b2010-07-02 08:12:41 -0700455 *(int32_t *)pReplyData = -EINVAL;
Jean-Michel Trivi3476de62012-04-15 17:15:07 -0700456 break;
Eric Laurentda7581b2010-07-02 08:12:41 -0700457 }
Jean-Michel Trivi3476de62012-04-15 17:15:07 -0700458 switch (*(uint32_t *)p->data) {
459 case VISUALIZER_PARAM_CAPTURE_SIZE:
460 pContext->mCaptureSize = *((uint32_t *)p->data + 1);
461 ALOGV("set mCaptureSize = %d", pContext->mCaptureSize);
462 break;
463 case VISUALIZER_PARAM_SCALING_MODE:
464 pContext->mScalingMode = *((uint32_t *)p->data + 1);
465 ALOGV("set mScalingMode = %d", pContext->mScalingMode);
466 break;
467 default:
468 *(int32_t *)pReplyData = -EINVAL;
469 }
Eric Laurentda7581b2010-07-02 08:12:41 -0700470 } break;
471 case EFFECT_CMD_SET_DEVICE:
472 case EFFECT_CMD_SET_VOLUME:
473 case EFFECT_CMD_SET_AUDIO_MODE:
474 break;
475
476
Eric Laurent6d8b6942011-06-24 07:01:31 -0700477 case VISUALIZER_CMD_CAPTURE:
Eric Laurent0e75f0f2010-09-21 14:52:01 -0700478 if (pReplyData == NULL || *replySize != pContext->mCaptureSize) {
Steve Block3856b092011-10-20 11:56:00 +0100479 ALOGV("VISUALIZER_CMD_CAPTURE() error *replySize %d pContext->mCaptureSize %d",
Eric Laurentda7581b2010-07-02 08:12:41 -0700480 *replySize, pContext->mCaptureSize);
481 return -EINVAL;
482 }
483 if (pContext->mState == VISUALIZER_STATE_ACTIVE) {
484 memcpy(pReplyData,
485 pContext->mCaptureBuf[pContext->mCurrentBuf ^ 1],
486 pContext->mCaptureSize);
Eric Laurent3df40a02011-11-10 10:02:18 -0800487 // if audio framework has stopped playing audio although the effect is still
488 // active we must clear the capture buffer to return silence
Eric Laurent183dc772012-03-23 15:35:48 -0700489 if ((pContext->mLastBuf == pContext->mCurrentBuf) &&
490 (pContext->mBufferUpdateTime.tv_sec != 0)) {
491 struct timespec ts;
492 if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
493 time_t secs = ts.tv_sec - pContext->mBufferUpdateTime.tv_sec;
494 long nsec = ts.tv_nsec - pContext->mBufferUpdateTime.tv_nsec;
495 if (nsec < 0) {
496 --secs;
497 nsec += 1000000000;
498 }
499 uint32_t deltaMs = secs * 1000 + nsec / 1000000;
500 if (deltaMs > MAX_STALL_TIME_MS) {
501 ALOGV("capture going to idle");
502 pContext->mBufferUpdateTime.tv_sec = 0;
Eric Laurent3df40a02011-11-10 10:02:18 -0800503 memset(pContext->mCaptureBuf[pContext->mCurrentBuf ^ 1],
504 0x80,
505 pContext->mCaptureSize);
506 }
507 }
Eric Laurent3df40a02011-11-10 10:02:18 -0800508 }
509 pContext->mLastBuf = pContext->mCurrentBuf;
Eric Laurentda7581b2010-07-02 08:12:41 -0700510 } else {
511 memset(pReplyData, 0x80, pContext->mCaptureSize);
512 }
Eric Laurent3df40a02011-11-10 10:02:18 -0800513
Eric Laurentda7581b2010-07-02 08:12:41 -0700514 break;
515
516 default:
Steve Block5ff1dd52012-01-05 23:22:43 +0000517 ALOGW("Visualizer_command invalid command %d",cmdCode);
Eric Laurentda7581b2010-07-02 08:12:41 -0700518 return -EINVAL;
519 }
520
521 return 0;
522}
523
Eric Laurente1315cf2011-05-17 19:16:02 -0700524/* Effect Control Interface Implementation: get_descriptor */
525int Visualizer_getDescriptor(effect_handle_t self,
526 effect_descriptor_t *pDescriptor)
527{
528 VisualizerContext * pContext = (VisualizerContext *) self;
529
530 if (pContext == NULL || pDescriptor == NULL) {
Steve Block3856b092011-10-20 11:56:00 +0100531 ALOGV("Visualizer_getDescriptor() invalid param");
Eric Laurente1315cf2011-05-17 19:16:02 -0700532 return -EINVAL;
533 }
534
535 memcpy(pDescriptor, &gVisualizerDescriptor, sizeof(effect_descriptor_t));
536
537 return 0;
538} /* end Visualizer_getDescriptor */
539
540// effect_handle_t interface implementation for visualizer effect
Eric Laurentda7581b2010-07-02 08:12:41 -0700541const struct effect_interface_s gVisualizerInterface = {
542 Visualizer_process,
Eric Laurente1315cf2011-05-17 19:16:02 -0700543 Visualizer_command,
Eric Laurentba7b8f82011-06-17 18:54:16 -0700544 Visualizer_getDescriptor,
545 NULL,
Eric Laurentda7581b2010-07-02 08:12:41 -0700546};
547
Eric Laurentda7581b2010-07-02 08:12:41 -0700548
Eric Laurente1315cf2011-05-17 19:16:02 -0700549audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
550 tag : AUDIO_EFFECT_LIBRARY_TAG,
551 version : EFFECT_LIBRARY_API_VERSION,
552 name : "Visualizer Library",
553 implementor : "The Android Open Source Project",
554 query_num_effects : VisualizerLib_QueryNumberEffects,
555 query_effect : VisualizerLib_QueryEffect,
556 create_effect : VisualizerLib_Create,
557 release_effect : VisualizerLib_Release,
558 get_descriptor : VisualizerLib_GetDescriptor,
559};
560
561}; // extern "C"