blob: dc1937ec642a614cbb2547d137953d1400c6196d [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
Marco Nelissenf06c2ed2012-06-06 09:52:31 -070055#define CAPTURE_BUF_SIZE 65536 // "64k should be enough for everyone"
56
Eric Laurentda7581b2010-07-02 08:12:41 -070057struct VisualizerContext {
58 const struct effect_interface_s *mItfe;
59 effect_config_t mConfig;
Eric Laurentda7581b2010-07-02 08:12:41 -070060 uint32_t mCaptureIdx;
61 uint32_t mCaptureSize;
Jean-Michel Trivi3476de62012-04-15 17:15:07 -070062 uint32_t mScalingMode;
Eric Laurent3df40a02011-11-10 10:02:18 -080063 uint8_t mState;
Marco Nelissenf06c2ed2012-06-06 09:52:31 -070064 uint8_t mLastCaptureIdx;
65 uint32_t mLatency;
Eric Laurent183dc772012-03-23 15:35:48 -070066 struct timespec mBufferUpdateTime;
Marco Nelissenf06c2ed2012-06-06 09:52:31 -070067 uint8_t mCaptureBuf[CAPTURE_BUF_SIZE];
Eric Laurentda7581b2010-07-02 08:12:41 -070068};
69
Eric Laurentda7581b2010-07-02 08:12:41 -070070//
71//--- Local functions
72//
73
74void Visualizer_reset(VisualizerContext *pContext)
75{
76 pContext->mCaptureIdx = 0;
Marco Nelissenf06c2ed2012-06-06 09:52:31 -070077 pContext->mLastCaptureIdx = 0;
Eric Laurent183dc772012-03-23 15:35:48 -070078 pContext->mBufferUpdateTime.tv_sec = 0;
Marco Nelissenf06c2ed2012-06-06 09:52:31 -070079 pContext->mLatency = 0;
80 memset(pContext->mCaptureBuf, 0x80, CAPTURE_BUF_SIZE);
Eric Laurentda7581b2010-07-02 08:12:41 -070081}
82
83//----------------------------------------------------------------------------
Eric Laurent3d5188b2011-12-16 15:30:36 -080084// Visualizer_setConfig()
Eric Laurentda7581b2010-07-02 08:12:41 -070085//----------------------------------------------------------------------------
86// Purpose: Set input and output audio configuration.
87//
88// Inputs:
89// pContext: effect engine context
90// pConfig: pointer to effect_config_t structure holding input and output
91// configuration parameters
92//
93// Outputs:
94//
95//----------------------------------------------------------------------------
96
Eric Laurent3d5188b2011-12-16 15:30:36 -080097int Visualizer_setConfig(VisualizerContext *pContext, effect_config_t *pConfig)
Eric Laurentda7581b2010-07-02 08:12:41 -070098{
Eric Laurent3d5188b2011-12-16 15:30:36 -080099 ALOGV("Visualizer_setConfig start");
Eric Laurentda7581b2010-07-02 08:12:41 -0700100
101 if (pConfig->inputCfg.samplingRate != pConfig->outputCfg.samplingRate) return -EINVAL;
102 if (pConfig->inputCfg.channels != pConfig->outputCfg.channels) return -EINVAL;
103 if (pConfig->inputCfg.format != pConfig->outputCfg.format) return -EINVAL;
Eric Laurente1315cf2011-05-17 19:16:02 -0700104 if (pConfig->inputCfg.channels != AUDIO_CHANNEL_OUT_STEREO) return -EINVAL;
Eric Laurentda7581b2010-07-02 08:12:41 -0700105 if (pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_WRITE &&
106 pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_ACCUMULATE) return -EINVAL;
Eric Laurente1315cf2011-05-17 19:16:02 -0700107 if (pConfig->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) return -EINVAL;
Eric Laurentda7581b2010-07-02 08:12:41 -0700108
Glenn Kastena189a682012-02-20 12:16:30 -0800109 pContext->mConfig = *pConfig;
Eric Laurentda7581b2010-07-02 08:12:41 -0700110
111 Visualizer_reset(pContext);
112
113 return 0;
114}
115
116
117//----------------------------------------------------------------------------
Eric Laurent3d5188b2011-12-16 15:30:36 -0800118// Visualizer_getConfig()
119//----------------------------------------------------------------------------
120// Purpose: Get input and output audio configuration.
121//
122// Inputs:
123// pContext: effect engine context
124// pConfig: pointer to effect_config_t structure holding input and output
125// configuration parameters
126//
127// Outputs:
128//
129//----------------------------------------------------------------------------
130
131void Visualizer_getConfig(VisualizerContext *pContext, effect_config_t *pConfig)
132{
Glenn Kastena189a682012-02-20 12:16:30 -0800133 *pConfig = pContext->mConfig;
Eric Laurent3d5188b2011-12-16 15:30:36 -0800134}
135
136
137//----------------------------------------------------------------------------
Eric Laurentda7581b2010-07-02 08:12:41 -0700138// Visualizer_init()
139//----------------------------------------------------------------------------
140// Purpose: Initialize engine with default configuration.
141//
142// Inputs:
143// pContext: effect engine context
144//
145// Outputs:
146//
147//----------------------------------------------------------------------------
148
149int Visualizer_init(VisualizerContext *pContext)
150{
151 pContext->mConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
Eric Laurente1315cf2011-05-17 19:16:02 -0700152 pContext->mConfig.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
153 pContext->mConfig.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
Eric Laurentda7581b2010-07-02 08:12:41 -0700154 pContext->mConfig.inputCfg.samplingRate = 44100;
155 pContext->mConfig.inputCfg.bufferProvider.getBuffer = NULL;
156 pContext->mConfig.inputCfg.bufferProvider.releaseBuffer = NULL;
157 pContext->mConfig.inputCfg.bufferProvider.cookie = NULL;
158 pContext->mConfig.inputCfg.mask = EFFECT_CONFIG_ALL;
159 pContext->mConfig.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE;
Eric Laurente1315cf2011-05-17 19:16:02 -0700160 pContext->mConfig.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
161 pContext->mConfig.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
Eric Laurentda7581b2010-07-02 08:12:41 -0700162 pContext->mConfig.outputCfg.samplingRate = 44100;
163 pContext->mConfig.outputCfg.bufferProvider.getBuffer = NULL;
164 pContext->mConfig.outputCfg.bufferProvider.releaseBuffer = NULL;
165 pContext->mConfig.outputCfg.bufferProvider.cookie = NULL;
166 pContext->mConfig.outputCfg.mask = EFFECT_CONFIG_ALL;
167
168 pContext->mCaptureSize = VISUALIZER_CAPTURE_SIZE_MAX;
Jean-Michel Trivi3476de62012-04-15 17:15:07 -0700169 pContext->mScalingMode = VISUALIZER_SCALING_MODE_NORMALIZED;
Eric Laurentda7581b2010-07-02 08:12:41 -0700170
Eric Laurent3d5188b2011-12-16 15:30:36 -0800171 Visualizer_setConfig(pContext, &pContext->mConfig);
Eric Laurentda7581b2010-07-02 08:12:41 -0700172
173 return 0;
174}
175
176//
177//--- Effect Library Interface Implementation
178//
179
Glenn Kasten5e92a782012-01-30 07:40:52 -0800180int VisualizerLib_Create(const effect_uuid_t *uuid,
Eric Laurente1315cf2011-05-17 19:16:02 -0700181 int32_t sessionId,
182 int32_t ioId,
183 effect_handle_t *pHandle) {
Eric Laurentda7581b2010-07-02 08:12:41 -0700184 int ret;
185 int i;
186
Eric Laurente1315cf2011-05-17 19:16:02 -0700187 if (pHandle == NULL || uuid == NULL) {
Eric Laurentda7581b2010-07-02 08:12:41 -0700188 return -EINVAL;
189 }
190
191 if (memcmp(uuid, &gVisualizerDescriptor.uuid, sizeof(effect_uuid_t)) != 0) {
192 return -EINVAL;
193 }
194
195 VisualizerContext *pContext = new VisualizerContext;
196
197 pContext->mItfe = &gVisualizerInterface;
198 pContext->mState = VISUALIZER_STATE_UNINITIALIZED;
199
200 ret = Visualizer_init(pContext);
201 if (ret < 0) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000202 ALOGW("VisualizerLib_Create() init failed");
Eric Laurentda7581b2010-07-02 08:12:41 -0700203 delete pContext;
204 return ret;
205 }
206
Eric Laurente1315cf2011-05-17 19:16:02 -0700207 *pHandle = (effect_handle_t)pContext;
Eric Laurentda7581b2010-07-02 08:12:41 -0700208
209 pContext->mState = VISUALIZER_STATE_INITIALIZED;
210
Steve Block3856b092011-10-20 11:56:00 +0100211 ALOGV("VisualizerLib_Create %p", pContext);
Eric Laurentda7581b2010-07-02 08:12:41 -0700212
213 return 0;
214
215}
216
Eric Laurente1315cf2011-05-17 19:16:02 -0700217int VisualizerLib_Release(effect_handle_t handle) {
218 VisualizerContext * pContext = (VisualizerContext *)handle;
Eric Laurentda7581b2010-07-02 08:12:41 -0700219
Steve Block3856b092011-10-20 11:56:00 +0100220 ALOGV("VisualizerLib_Release %p", handle);
Eric Laurentda7581b2010-07-02 08:12:41 -0700221 if (pContext == NULL) {
222 return -EINVAL;
223 }
224 pContext->mState = VISUALIZER_STATE_UNINITIALIZED;
225 delete pContext;
226
227 return 0;
228}
229
Glenn Kasten5e92a782012-01-30 07:40:52 -0800230int VisualizerLib_GetDescriptor(const effect_uuid_t *uuid,
Eric Laurente1315cf2011-05-17 19:16:02 -0700231 effect_descriptor_t *pDescriptor) {
232
233 if (pDescriptor == NULL || uuid == NULL){
Steve Block3856b092011-10-20 11:56:00 +0100234 ALOGV("VisualizerLib_GetDescriptor() called with NULL pointer");
Eric Laurente1315cf2011-05-17 19:16:02 -0700235 return -EINVAL;
236 }
237
238 if (memcmp(uuid, &gVisualizerDescriptor.uuid, sizeof(effect_uuid_t)) == 0) {
Glenn Kastena189a682012-02-20 12:16:30 -0800239 *pDescriptor = gVisualizerDescriptor;
Eric Laurente1315cf2011-05-17 19:16:02 -0700240 return 0;
241 }
242
243 return -EINVAL;
244} /* end VisualizerLib_GetDescriptor */
245
Eric Laurentda7581b2010-07-02 08:12:41 -0700246//
247//--- Effect Control Interface Implementation
248//
249
250static inline int16_t clamp16(int32_t sample)
251{
252 if ((sample>>15) ^ (sample>>31))
253 sample = 0x7FFF ^ (sample>>31);
254 return sample;
255}
256
Eric Laurente1315cf2011-05-17 19:16:02 -0700257int Visualizer_process(
258 effect_handle_t self,audio_buffer_t *inBuffer, audio_buffer_t *outBuffer)
Eric Laurentda7581b2010-07-02 08:12:41 -0700259{
Eric Laurente1315cf2011-05-17 19:16:02 -0700260 VisualizerContext * pContext = (VisualizerContext *)self;
Eric Laurentda7581b2010-07-02 08:12:41 -0700261
262 if (pContext == NULL) {
263 return -EINVAL;
264 }
Eric Laurentda7581b2010-07-02 08:12:41 -0700265
266 if (inBuffer == NULL || inBuffer->raw == NULL ||
267 outBuffer == NULL || outBuffer->raw == NULL ||
268 inBuffer->frameCount != outBuffer->frameCount ||
269 inBuffer->frameCount == 0) {
270 return -EINVAL;
271 }
272
273 // all code below assumes stereo 16 bit PCM output and input
Jean-Michel Trivi3476de62012-04-15 17:15:07 -0700274 int32_t shift;
Eric Laurent0e75f0f2010-09-21 14:52:01 -0700275
Jean-Michel Trivi3476de62012-04-15 17:15:07 -0700276 if (pContext->mScalingMode == VISUALIZER_SCALING_MODE_NORMALIZED) {
277 // derive capture scaling factor from peak value in current buffer
278 // this gives more interesting captures for display.
279 shift = 32;
280 int len = inBuffer->frameCount * 2;
281 for (int i = 0; i < len; i++) {
282 int32_t smp = inBuffer->s16[i];
283 if (smp < 0) smp = -smp - 1; // take care to keep the max negative in range
284 int32_t clz = __builtin_clz(smp);
285 if (shift > clz) shift = clz;
286 }
287 // A maximum amplitude signal will have 17 leading zeros, which we want to
288 // translate to a shift of 8 (for converting 16 bit to 8 bit)
289 shift = 25 - shift;
290 // Never scale by less than 8 to avoid returning unaltered PCM signal.
291 if (shift < 3) {
292 shift = 3;
293 }
294 // add one to combine the division by 2 needed after summing left and right channels below
295 shift++;
296 } else {
297 assert(pContext->mScalingMode == VISUALIZER_SCALING_MODE_AS_PLAYED);
298 shift = 9;
Eric Laurent0e75f0f2010-09-21 14:52:01 -0700299 }
Eric Laurent0e75f0f2010-09-21 14:52:01 -0700300
Eric Laurentda7581b2010-07-02 08:12:41 -0700301 uint32_t captIdx;
302 uint32_t inIdx;
Marco Nelissenf06c2ed2012-06-06 09:52:31 -0700303 uint8_t *buf = pContext->mCaptureBuf;
Eric Laurentda7581b2010-07-02 08:12:41 -0700304 for (inIdx = 0, captIdx = pContext->mCaptureIdx;
Marco Nelissenf06c2ed2012-06-06 09:52:31 -0700305 inIdx < inBuffer->frameCount;
Eric Laurentda7581b2010-07-02 08:12:41 -0700306 inIdx++, captIdx++) {
Marco Nelissenf06c2ed2012-06-06 09:52:31 -0700307 if (captIdx >= CAPTURE_BUF_SIZE) {
308 // wrap around
309 captIdx = 0;
310 }
Eric Laurentda7581b2010-07-02 08:12:41 -0700311 int32_t smp = inBuffer->s16[2 * inIdx] + inBuffer->s16[2 * inIdx + 1];
Marco Nelissen64c3bde2010-10-27 09:06:01 -0700312 smp = smp >> shift;
Eric Laurentda7581b2010-07-02 08:12:41 -0700313 buf[captIdx] = ((uint8_t)smp)^0x80;
314 }
Marco Nelissenf06c2ed2012-06-06 09:52:31 -0700315
316 // XXX the following two should really be atomic, though it probably doesn't
317 // matter much for visualization purposes
Eric Laurentda7581b2010-07-02 08:12:41 -0700318 pContext->mCaptureIdx = captIdx;
Marco Nelissenf06c2ed2012-06-06 09:52:31 -0700319 // update last buffer update time stamp
320 if (clock_gettime(CLOCK_MONOTONIC, &pContext->mBufferUpdateTime) < 0) {
321 pContext->mBufferUpdateTime.tv_sec = 0;
Eric Laurentda7581b2010-07-02 08:12:41 -0700322 }
323
324 if (inBuffer->raw != outBuffer->raw) {
325 if (pContext->mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
326 for (size_t i = 0; i < outBuffer->frameCount*2; i++) {
327 outBuffer->s16[i] = clamp16(outBuffer->s16[i] + inBuffer->s16[i]);
328 }
329 } else {
330 memcpy(outBuffer->raw, inBuffer->raw, outBuffer->frameCount * 2 * sizeof(int16_t));
331 }
332 }
Eric Laurentf997cab2010-07-19 06:24:46 -0700333 if (pContext->mState != VISUALIZER_STATE_ACTIVE) {
334 return -ENODATA;
335 }
Eric Laurentda7581b2010-07-02 08:12:41 -0700336 return 0;
337} // end Visualizer_process
338
Eric Laurente1315cf2011-05-17 19:16:02 -0700339int Visualizer_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
Eric Laurent25f43952010-07-28 05:40:18 -0700340 void *pCmdData, uint32_t *replySize, void *pReplyData) {
Eric Laurentda7581b2010-07-02 08:12:41 -0700341
Eric Laurente1315cf2011-05-17 19:16:02 -0700342 VisualizerContext * pContext = (VisualizerContext *)self;
Eric Laurentda7581b2010-07-02 08:12:41 -0700343 int retsize;
344
345 if (pContext == NULL || pContext->mState == VISUALIZER_STATE_UNINITIALIZED) {
346 return -EINVAL;
347 }
348
Steve Block3856b092011-10-20 11:56:00 +0100349// ALOGV("Visualizer_command command %d cmdSize %d",cmdCode, cmdSize);
Eric Laurentda7581b2010-07-02 08:12:41 -0700350
351 switch (cmdCode) {
352 case EFFECT_CMD_INIT:
353 if (pReplyData == NULL || *replySize != sizeof(int)) {
354 return -EINVAL;
355 }
356 *(int *) pReplyData = Visualizer_init(pContext);
357 break;
Eric Laurent3d5188b2011-12-16 15:30:36 -0800358 case EFFECT_CMD_SET_CONFIG:
Eric Laurentda7581b2010-07-02 08:12:41 -0700359 if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
360 || pReplyData == NULL || *replySize != sizeof(int)) {
361 return -EINVAL;
362 }
Eric Laurent3d5188b2011-12-16 15:30:36 -0800363 *(int *) pReplyData = Visualizer_setConfig(pContext,
Eric Laurentda7581b2010-07-02 08:12:41 -0700364 (effect_config_t *) pCmdData);
365 break;
Eric Laurent3d5188b2011-12-16 15:30:36 -0800366 case EFFECT_CMD_GET_CONFIG:
367 if (pReplyData == NULL ||
368 *replySize != sizeof(effect_config_t)) {
369 return -EINVAL;
370 }
371 Visualizer_getConfig(pContext, (effect_config_t *)pReplyData);
372 break;
Eric Laurentda7581b2010-07-02 08:12:41 -0700373 case EFFECT_CMD_RESET:
374 Visualizer_reset(pContext);
375 break;
376 case EFFECT_CMD_ENABLE:
377 if (pReplyData == NULL || *replySize != sizeof(int)) {
378 return -EINVAL;
379 }
380 if (pContext->mState != VISUALIZER_STATE_INITIALIZED) {
381 return -ENOSYS;
382 }
383 pContext->mState = VISUALIZER_STATE_ACTIVE;
Steve Block3856b092011-10-20 11:56:00 +0100384 ALOGV("EFFECT_CMD_ENABLE() OK");
Eric Laurentda7581b2010-07-02 08:12:41 -0700385 *(int *)pReplyData = 0;
386 break;
387 case EFFECT_CMD_DISABLE:
388 if (pReplyData == NULL || *replySize != sizeof(int)) {
389 return -EINVAL;
390 }
391 if (pContext->mState != VISUALIZER_STATE_ACTIVE) {
392 return -ENOSYS;
393 }
394 pContext->mState = VISUALIZER_STATE_INITIALIZED;
Steve Block3856b092011-10-20 11:56:00 +0100395 ALOGV("EFFECT_CMD_DISABLE() OK");
Eric Laurentda7581b2010-07-02 08:12:41 -0700396 *(int *)pReplyData = 0;
397 break;
398 case EFFECT_CMD_GET_PARAM: {
399 if (pCmdData == NULL ||
400 cmdSize != (int)(sizeof(effect_param_t) + sizeof(uint32_t)) ||
401 pReplyData == NULL ||
402 *replySize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint32_t))) {
403 return -EINVAL;
404 }
405 memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + sizeof(uint32_t));
406 effect_param_t *p = (effect_param_t *)pReplyData;
407 p->status = 0;
408 *replySize = sizeof(effect_param_t) + sizeof(uint32_t);
Jean-Michel Trivi3476de62012-04-15 17:15:07 -0700409 if (p->psize != sizeof(uint32_t)) {
Eric Laurentda7581b2010-07-02 08:12:41 -0700410 p->status = -EINVAL;
411 break;
412 }
Jean-Michel Trivi3476de62012-04-15 17:15:07 -0700413 switch (*(uint32_t *)p->data) {
414 case VISUALIZER_PARAM_CAPTURE_SIZE:
415 ALOGV("get mCaptureSize = %d", pContext->mCaptureSize);
416 *((uint32_t *)p->data + 1) = pContext->mCaptureSize;
417 p->vsize = sizeof(uint32_t);
418 *replySize += sizeof(uint32_t);
419 break;
420 case VISUALIZER_PARAM_SCALING_MODE:
421 ALOGV("get mScalingMode = %d", pContext->mScalingMode);
422 *((uint32_t *)p->data + 1) = pContext->mScalingMode;
423 p->vsize = sizeof(uint32_t);
424 *replySize += sizeof(uint32_t);
425 break;
426 default:
427 p->status = -EINVAL;
428 }
Eric Laurentda7581b2010-07-02 08:12:41 -0700429 } break;
430 case EFFECT_CMD_SET_PARAM: {
431 if (pCmdData == NULL ||
432 cmdSize != (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint32_t)) ||
433 pReplyData == NULL || *replySize != sizeof(int32_t)) {
434 return -EINVAL;
435 }
436 *(int32_t *)pReplyData = 0;
437 effect_param_t *p = (effect_param_t *)pCmdData;
Jean-Michel Trivi3476de62012-04-15 17:15:07 -0700438 if (p->psize != sizeof(uint32_t) || p->vsize != sizeof(uint32_t)) {
Eric Laurentda7581b2010-07-02 08:12:41 -0700439 *(int32_t *)pReplyData = -EINVAL;
Jean-Michel Trivi3476de62012-04-15 17:15:07 -0700440 break;
Eric Laurentda7581b2010-07-02 08:12:41 -0700441 }
Jean-Michel Trivi3476de62012-04-15 17:15:07 -0700442 switch (*(uint32_t *)p->data) {
443 case VISUALIZER_PARAM_CAPTURE_SIZE:
444 pContext->mCaptureSize = *((uint32_t *)p->data + 1);
445 ALOGV("set mCaptureSize = %d", pContext->mCaptureSize);
446 break;
447 case VISUALIZER_PARAM_SCALING_MODE:
448 pContext->mScalingMode = *((uint32_t *)p->data + 1);
449 ALOGV("set mScalingMode = %d", pContext->mScalingMode);
450 break;
Marco Nelissenf06c2ed2012-06-06 09:52:31 -0700451 case VISUALIZER_PARAM_LATENCY:
452 pContext->mLatency = *((uint32_t *)p->data + 1);
453 ALOGV("set mLatency = %d", pContext->mLatency);
454 break;
Jean-Michel Trivi3476de62012-04-15 17:15:07 -0700455 default:
456 *(int32_t *)pReplyData = -EINVAL;
457 }
Eric Laurentda7581b2010-07-02 08:12:41 -0700458 } break;
459 case EFFECT_CMD_SET_DEVICE:
460 case EFFECT_CMD_SET_VOLUME:
461 case EFFECT_CMD_SET_AUDIO_MODE:
462 break;
463
464
Eric Laurent6d8b6942011-06-24 07:01:31 -0700465 case VISUALIZER_CMD_CAPTURE:
Eric Laurent0e75f0f2010-09-21 14:52:01 -0700466 if (pReplyData == NULL || *replySize != pContext->mCaptureSize) {
Steve Block3856b092011-10-20 11:56:00 +0100467 ALOGV("VISUALIZER_CMD_CAPTURE() error *replySize %d pContext->mCaptureSize %d",
Eric Laurentda7581b2010-07-02 08:12:41 -0700468 *replySize, pContext->mCaptureSize);
469 return -EINVAL;
470 }
471 if (pContext->mState == VISUALIZER_STATE_ACTIVE) {
Marco Nelissenf06c2ed2012-06-06 09:52:31 -0700472 int32_t latencyMs = pContext->mLatency;
473 uint32_t deltaMs = 0;
474 if (pContext->mBufferUpdateTime.tv_sec != 0) {
Eric Laurent183dc772012-03-23 15:35:48 -0700475 struct timespec ts;
476 if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
477 time_t secs = ts.tv_sec - pContext->mBufferUpdateTime.tv_sec;
478 long nsec = ts.tv_nsec - pContext->mBufferUpdateTime.tv_nsec;
479 if (nsec < 0) {
480 --secs;
481 nsec += 1000000000;
482 }
Marco Nelissenf06c2ed2012-06-06 09:52:31 -0700483 deltaMs = secs * 1000 + nsec / 1000000;
484 latencyMs -= deltaMs;
485 if (latencyMs < 0) {
486 latencyMs = 0;
Eric Laurent3df40a02011-11-10 10:02:18 -0800487 }
488 }
Eric Laurent3df40a02011-11-10 10:02:18 -0800489 }
Marco Nelissenf06c2ed2012-06-06 09:52:31 -0700490 uint32_t deltaSmpl = pContext->mConfig.inputCfg.samplingRate * latencyMs / 1000;
491
492 int32_t capturePoint = pContext->mCaptureIdx - pContext->mCaptureSize - deltaSmpl;
493 int32_t captureSize = pContext->mCaptureSize;
494 if (capturePoint < 0) {
495 int32_t size = -capturePoint;
496 if (size > captureSize) {
497 size = captureSize;
498 }
499 memcpy(pReplyData,
500 pContext->mCaptureBuf + CAPTURE_BUF_SIZE + capturePoint,
501 size);
502 pReplyData += size;
503 captureSize -= size;
504 capturePoint = 0;
505 }
506 memcpy(pReplyData,
507 pContext->mCaptureBuf + capturePoint,
508 captureSize);
509
510
511 // if audio framework has stopped playing audio although the effect is still
512 // active we must clear the capture buffer to return silence
513 if ((pContext->mLastCaptureIdx == pContext->mCaptureIdx) &&
514 (pContext->mBufferUpdateTime.tv_sec != 0)) {
515 if (deltaMs > MAX_STALL_TIME_MS) {
516 ALOGV("capture going to idle");
517 pContext->mBufferUpdateTime.tv_sec = 0;
518 memset(pReplyData, 0x80, pContext->mCaptureSize);
519 }
520 }
521 pContext->mLastCaptureIdx = pContext->mCaptureIdx;
Eric Laurentda7581b2010-07-02 08:12:41 -0700522 } else {
523 memset(pReplyData, 0x80, pContext->mCaptureSize);
524 }
Eric Laurent3df40a02011-11-10 10:02:18 -0800525
Eric Laurentda7581b2010-07-02 08:12:41 -0700526 break;
527
528 default:
Steve Block5ff1dd52012-01-05 23:22:43 +0000529 ALOGW("Visualizer_command invalid command %d",cmdCode);
Eric Laurentda7581b2010-07-02 08:12:41 -0700530 return -EINVAL;
531 }
532
533 return 0;
534}
535
Eric Laurente1315cf2011-05-17 19:16:02 -0700536/* Effect Control Interface Implementation: get_descriptor */
537int Visualizer_getDescriptor(effect_handle_t self,
538 effect_descriptor_t *pDescriptor)
539{
540 VisualizerContext * pContext = (VisualizerContext *) self;
541
542 if (pContext == NULL || pDescriptor == NULL) {
Steve Block3856b092011-10-20 11:56:00 +0100543 ALOGV("Visualizer_getDescriptor() invalid param");
Eric Laurente1315cf2011-05-17 19:16:02 -0700544 return -EINVAL;
545 }
546
Glenn Kastena189a682012-02-20 12:16:30 -0800547 *pDescriptor = gVisualizerDescriptor;
Eric Laurente1315cf2011-05-17 19:16:02 -0700548
549 return 0;
550} /* end Visualizer_getDescriptor */
551
552// effect_handle_t interface implementation for visualizer effect
Eric Laurentda7581b2010-07-02 08:12:41 -0700553const struct effect_interface_s gVisualizerInterface = {
554 Visualizer_process,
Eric Laurente1315cf2011-05-17 19:16:02 -0700555 Visualizer_command,
Eric Laurentba7b8f82011-06-17 18:54:16 -0700556 Visualizer_getDescriptor,
557 NULL,
Eric Laurentda7581b2010-07-02 08:12:41 -0700558};
559
Eric Laurentda7581b2010-07-02 08:12:41 -0700560
Eric Laurente1315cf2011-05-17 19:16:02 -0700561audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
562 tag : AUDIO_EFFECT_LIBRARY_TAG,
563 version : EFFECT_LIBRARY_API_VERSION,
564 name : "Visualizer Library",
565 implementor : "The Android Open Source Project",
Eric Laurente1315cf2011-05-17 19:16:02 -0700566 create_effect : VisualizerLib_Create,
567 release_effect : VisualizerLib_Release,
568 get_descriptor : VisualizerLib_GetDescriptor,
569};
570
571}; // extern "C"