blob: c957dba97adbe918bc98220a23173d7ccbf6aa9a [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>
24#include <media/EffectVisualizerApi.h>
25
26namespace android {
27
28// effect_interface_t interface implementation for visualizer effect
29extern "C" const struct effect_interface_s gVisualizerInterface;
30
31// Google Visualizer UUID: d069d9e0-8329-11df-9168-0002a5d5c51b
32const effect_descriptor_t gVisualizerDescriptor = {
33 {0xe46b26a0, 0xdddd, 0x11db, 0x8afd, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // type
34 {0xd069d9e0, 0x8329, 0x11df, 0x9168, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // uuid
35 EFFECT_API_VERSION,
36 (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST),
37 0, // TODO
38 1,
39 "Visualizer",
40 "Google Inc.",
41};
42
43enum visualizer_state_e {
44 VISUALIZER_STATE_UNINITIALIZED,
45 VISUALIZER_STATE_INITIALIZED,
46 VISUALIZER_STATE_ACTIVE,
47};
48
49struct VisualizerContext {
50 const struct effect_interface_s *mItfe;
51 effect_config_t mConfig;
52 uint32_t mState;
53 uint32_t mCaptureIdx;
54 uint32_t mCaptureSize;
55 uint32_t mCurrentBuf;
56 uint8_t mCaptureBuf[2][VISUALIZER_CAPTURE_SIZE_MAX];
57};
58
59
60//
61//--- Local functions
62//
63
64void Visualizer_reset(VisualizerContext *pContext)
65{
66 pContext->mCaptureIdx = 0;
67 pContext->mCurrentBuf = 0;
Eric Laurent0fa449c2010-09-24 11:52:04 -070068 memset(pContext->mCaptureBuf[0], 0x80, VISUALIZER_CAPTURE_SIZE_MAX);
69 memset(pContext->mCaptureBuf[1], 0x80, VISUALIZER_CAPTURE_SIZE_MAX);
Eric Laurentda7581b2010-07-02 08:12:41 -070070}
71
72//----------------------------------------------------------------------------
73// Visualizer_configure()
74//----------------------------------------------------------------------------
75// Purpose: Set input and output audio configuration.
76//
77// Inputs:
78// pContext: effect engine context
79// pConfig: pointer to effect_config_t structure holding input and output
80// configuration parameters
81//
82// Outputs:
83//
84//----------------------------------------------------------------------------
85
86int Visualizer_configure(VisualizerContext *pContext, effect_config_t *pConfig)
87{
88 LOGV("Visualizer_configure start");
89
90 if (pConfig->inputCfg.samplingRate != pConfig->outputCfg.samplingRate) return -EINVAL;
91 if (pConfig->inputCfg.channels != pConfig->outputCfg.channels) return -EINVAL;
92 if (pConfig->inputCfg.format != pConfig->outputCfg.format) return -EINVAL;
93 if (pConfig->inputCfg.channels != CHANNEL_STEREO) return -EINVAL;
94 if (pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_WRITE &&
95 pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_ACCUMULATE) return -EINVAL;
96 if (pConfig->inputCfg.format != SAMPLE_FORMAT_PCM_S15) return -EINVAL;
97
98 memcpy(&pContext->mConfig, pConfig, sizeof(effect_config_t));
99
100 Visualizer_reset(pContext);
101
102 return 0;
103}
104
105
106//----------------------------------------------------------------------------
107// Visualizer_init()
108//----------------------------------------------------------------------------
109// Purpose: Initialize engine with default configuration.
110//
111// Inputs:
112// pContext: effect engine context
113//
114// Outputs:
115//
116//----------------------------------------------------------------------------
117
118int Visualizer_init(VisualizerContext *pContext)
119{
120 pContext->mConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
121 pContext->mConfig.inputCfg.channels = CHANNEL_STEREO;
122 pContext->mConfig.inputCfg.format = SAMPLE_FORMAT_PCM_S15;
123 pContext->mConfig.inputCfg.samplingRate = 44100;
124 pContext->mConfig.inputCfg.bufferProvider.getBuffer = NULL;
125 pContext->mConfig.inputCfg.bufferProvider.releaseBuffer = NULL;
126 pContext->mConfig.inputCfg.bufferProvider.cookie = NULL;
127 pContext->mConfig.inputCfg.mask = EFFECT_CONFIG_ALL;
128 pContext->mConfig.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE;
129 pContext->mConfig.outputCfg.channels = CHANNEL_STEREO;
130 pContext->mConfig.outputCfg.format = SAMPLE_FORMAT_PCM_S15;
131 pContext->mConfig.outputCfg.samplingRate = 44100;
132 pContext->mConfig.outputCfg.bufferProvider.getBuffer = NULL;
133 pContext->mConfig.outputCfg.bufferProvider.releaseBuffer = NULL;
134 pContext->mConfig.outputCfg.bufferProvider.cookie = NULL;
135 pContext->mConfig.outputCfg.mask = EFFECT_CONFIG_ALL;
136
137 pContext->mCaptureSize = VISUALIZER_CAPTURE_SIZE_MAX;
138
139 Visualizer_configure(pContext, &pContext->mConfig);
140
141 return 0;
142}
143
144//
145//--- Effect Library Interface Implementation
146//
147
148extern "C" int EffectQueryNumberEffects(uint32_t *pNumEffects) {
149 *pNumEffects = 1;
150 return 0;
151}
152
153extern "C" int EffectQueryEffect(uint32_t index, effect_descriptor_t *pDescriptor) {
154 if (pDescriptor == NULL) {
155 return -EINVAL;
156 }
157 if (index > 0) {
158 return -EINVAL;
159 }
160 memcpy(pDescriptor, &gVisualizerDescriptor, sizeof(effect_descriptor_t));
161 return 0;
162}
163
164extern "C" int EffectCreate(effect_uuid_t *uuid,
165 int32_t sessionId,
166 int32_t ioId,
167 effect_interface_t *pInterface) {
168 int ret;
169 int i;
170
171 if (pInterface == NULL || uuid == NULL) {
172 return -EINVAL;
173 }
174
175 if (memcmp(uuid, &gVisualizerDescriptor.uuid, sizeof(effect_uuid_t)) != 0) {
176 return -EINVAL;
177 }
178
179 VisualizerContext *pContext = new VisualizerContext;
180
181 pContext->mItfe = &gVisualizerInterface;
182 pContext->mState = VISUALIZER_STATE_UNINITIALIZED;
183
184 ret = Visualizer_init(pContext);
185 if (ret < 0) {
186 LOGW("EffectCreate() init failed");
187 delete pContext;
188 return ret;
189 }
190
191 *pInterface = (effect_interface_t)pContext;
192
193 pContext->mState = VISUALIZER_STATE_INITIALIZED;
194
195 LOGV("EffectCreate %p", pContext);
196
197 return 0;
198
199}
200
201extern "C" int EffectRelease(effect_interface_t interface) {
202 VisualizerContext * pContext = (VisualizerContext *)interface;
203
204 LOGV("EffectRelease %p", interface);
205 if (pContext == NULL) {
206 return -EINVAL;
207 }
208 pContext->mState = VISUALIZER_STATE_UNINITIALIZED;
209 delete pContext;
210
211 return 0;
212}
213
214//
215//--- Effect Control Interface Implementation
216//
217
218static inline int16_t clamp16(int32_t sample)
219{
220 if ((sample>>15) ^ (sample>>31))
221 sample = 0x7FFF ^ (sample>>31);
222 return sample;
223}
224
225extern "C" int Visualizer_process(
226 effect_interface_t self,audio_buffer_t *inBuffer, audio_buffer_t *outBuffer)
227{
228 android::VisualizerContext * pContext = (android::VisualizerContext *)self;
229
230 if (pContext == NULL) {
231 return -EINVAL;
232 }
Eric Laurentda7581b2010-07-02 08:12:41 -0700233
234 if (inBuffer == NULL || inBuffer->raw == NULL ||
235 outBuffer == NULL || outBuffer->raw == NULL ||
236 inBuffer->frameCount != outBuffer->frameCount ||
237 inBuffer->frameCount == 0) {
238 return -EINVAL;
239 }
240
241 // all code below assumes stereo 16 bit PCM output and input
Eric Laurent0e75f0f2010-09-21 14:52:01 -0700242
243 // derive capture scaling factor from peak value in current buffer
244 // this gives more interesting captures for display.
245 int32_t shift = 32;
Marco Nelissen64c3bde2010-10-27 09:06:01 -0700246 int len = inBuffer->frameCount * 2;
247 for (size_t i = 0; i < len; i++) {
Eric Laurent0e75f0f2010-09-21 14:52:01 -0700248 int32_t smp = inBuffer->s16[i];
Marco Nelissen64c3bde2010-10-27 09:06:01 -0700249 if (smp < 0) smp = -smp - 1; // take care to keep the max negative in range
Eric Laurent0e75f0f2010-09-21 14:52:01 -0700250 int32_t clz = __builtin_clz(smp);
251 if (shift > clz) shift = clz;
252 }
Marco Nelissen64c3bde2010-10-27 09:06:01 -0700253 // A maximum amplitude signal will have 17 leading zeros, which we want to
254 // translate to a shift of 8 (for converting 16 bit to 8 bit)
255 shift = 25 - shift;
256 // Never scale by less than 8 to avoid returning unaltered PCM signal.
257 if (shift < 3) {
258 shift = 3;
Eric Laurent0e75f0f2010-09-21 14:52:01 -0700259 }
Marco Nelissen64c3bde2010-10-27 09:06:01 -0700260 // add one to combine the division by 2 needed after summing left and right channels below
261 shift++;
Eric Laurent0e75f0f2010-09-21 14:52:01 -0700262
Eric Laurentda7581b2010-07-02 08:12:41 -0700263 uint32_t captIdx;
264 uint32_t inIdx;
265 uint8_t *buf = pContext->mCaptureBuf[pContext->mCurrentBuf];
266 for (inIdx = 0, captIdx = pContext->mCaptureIdx;
267 inIdx < inBuffer->frameCount && captIdx < pContext->mCaptureSize;
268 inIdx++, captIdx++) {
269 int32_t smp = inBuffer->s16[2 * inIdx] + inBuffer->s16[2 * inIdx + 1];
Marco Nelissen64c3bde2010-10-27 09:06:01 -0700270 smp = smp >> shift;
Eric Laurentda7581b2010-07-02 08:12:41 -0700271 buf[captIdx] = ((uint8_t)smp)^0x80;
272 }
273 pContext->mCaptureIdx = captIdx;
274
275 // go to next buffer when buffer full
276 if (pContext->mCaptureIdx == pContext->mCaptureSize) {
277 pContext->mCurrentBuf ^= 1;
278 pContext->mCaptureIdx = 0;
279 }
280
281 if (inBuffer->raw != outBuffer->raw) {
282 if (pContext->mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
283 for (size_t i = 0; i < outBuffer->frameCount*2; i++) {
284 outBuffer->s16[i] = clamp16(outBuffer->s16[i] + inBuffer->s16[i]);
285 }
286 } else {
287 memcpy(outBuffer->raw, inBuffer->raw, outBuffer->frameCount * 2 * sizeof(int16_t));
288 }
289 }
Eric Laurentf997cab2010-07-19 06:24:46 -0700290 if (pContext->mState != VISUALIZER_STATE_ACTIVE) {
291 return -ENODATA;
292 }
Eric Laurentda7581b2010-07-02 08:12:41 -0700293 return 0;
294} // end Visualizer_process
295
Eric Laurent25f43952010-07-28 05:40:18 -0700296extern "C" int Visualizer_command(effect_interface_t self, uint32_t cmdCode, uint32_t cmdSize,
297 void *pCmdData, uint32_t *replySize, void *pReplyData) {
Eric Laurentda7581b2010-07-02 08:12:41 -0700298
299 android::VisualizerContext * pContext = (android::VisualizerContext *)self;
300 int retsize;
301
302 if (pContext == NULL || pContext->mState == VISUALIZER_STATE_UNINITIALIZED) {
303 return -EINVAL;
304 }
305
306// LOGV("Visualizer_command command %d cmdSize %d",cmdCode, cmdSize);
307
308 switch (cmdCode) {
309 case EFFECT_CMD_INIT:
310 if (pReplyData == NULL || *replySize != sizeof(int)) {
311 return -EINVAL;
312 }
313 *(int *) pReplyData = Visualizer_init(pContext);
314 break;
315 case EFFECT_CMD_CONFIGURE:
316 if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
317 || pReplyData == NULL || *replySize != sizeof(int)) {
318 return -EINVAL;
319 }
320 *(int *) pReplyData = Visualizer_configure(pContext,
321 (effect_config_t *) pCmdData);
322 break;
323 case EFFECT_CMD_RESET:
324 Visualizer_reset(pContext);
325 break;
326 case EFFECT_CMD_ENABLE:
327 if (pReplyData == NULL || *replySize != sizeof(int)) {
328 return -EINVAL;
329 }
330 if (pContext->mState != VISUALIZER_STATE_INITIALIZED) {
331 return -ENOSYS;
332 }
333 pContext->mState = VISUALIZER_STATE_ACTIVE;
334 LOGV("EFFECT_CMD_ENABLE() OK");
335 *(int *)pReplyData = 0;
336 break;
337 case EFFECT_CMD_DISABLE:
338 if (pReplyData == NULL || *replySize != sizeof(int)) {
339 return -EINVAL;
340 }
341 if (pContext->mState != VISUALIZER_STATE_ACTIVE) {
342 return -ENOSYS;
343 }
344 pContext->mState = VISUALIZER_STATE_INITIALIZED;
345 LOGV("EFFECT_CMD_DISABLE() OK");
346 *(int *)pReplyData = 0;
347 break;
348 case EFFECT_CMD_GET_PARAM: {
349 if (pCmdData == NULL ||
350 cmdSize != (int)(sizeof(effect_param_t) + sizeof(uint32_t)) ||
351 pReplyData == NULL ||
352 *replySize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint32_t))) {
353 return -EINVAL;
354 }
355 memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + sizeof(uint32_t));
356 effect_param_t *p = (effect_param_t *)pReplyData;
357 p->status = 0;
358 *replySize = sizeof(effect_param_t) + sizeof(uint32_t);
359 if (p->psize != sizeof(uint32_t) ||
360 *(uint32_t *)p->data != VISU_PARAM_CAPTURE_SIZE) {
361 p->status = -EINVAL;
362 break;
363 }
364 LOGV("get mCaptureSize = %d", pContext->mCaptureSize);
365 *((uint32_t *)p->data + 1) = pContext->mCaptureSize;
366 p->vsize = sizeof(uint32_t);
367 *replySize += sizeof(uint32_t);
368 } break;
369 case EFFECT_CMD_SET_PARAM: {
370 if (pCmdData == NULL ||
371 cmdSize != (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint32_t)) ||
372 pReplyData == NULL || *replySize != sizeof(int32_t)) {
373 return -EINVAL;
374 }
375 *(int32_t *)pReplyData = 0;
376 effect_param_t *p = (effect_param_t *)pCmdData;
377 if (p->psize != sizeof(uint32_t) ||
378 p->vsize != sizeof(uint32_t) ||
379 *(uint32_t *)p->data != VISU_PARAM_CAPTURE_SIZE) {
380 *(int32_t *)pReplyData = -EINVAL;
381 break;;
382 }
383 pContext->mCaptureSize = *((uint32_t *)p->data + 1);
384 LOGV("set mCaptureSize = %d", pContext->mCaptureSize);
385 } break;
386 case EFFECT_CMD_SET_DEVICE:
387 case EFFECT_CMD_SET_VOLUME:
388 case EFFECT_CMD_SET_AUDIO_MODE:
389 break;
390
391
392 case VISU_CMD_CAPTURE:
Eric Laurent0e75f0f2010-09-21 14:52:01 -0700393 if (pReplyData == NULL || *replySize != pContext->mCaptureSize) {
Eric Laurentda7581b2010-07-02 08:12:41 -0700394 LOGV("VISU_CMD_CAPTURE() error *replySize %d pContext->mCaptureSize %d",
395 *replySize, pContext->mCaptureSize);
396 return -EINVAL;
397 }
398 if (pContext->mState == VISUALIZER_STATE_ACTIVE) {
399 memcpy(pReplyData,
400 pContext->mCaptureBuf[pContext->mCurrentBuf ^ 1],
401 pContext->mCaptureSize);
402 } else {
403 memset(pReplyData, 0x80, pContext->mCaptureSize);
404 }
405 break;
406
407 default:
408 LOGW("Visualizer_command invalid command %d",cmdCode);
409 return -EINVAL;
410 }
411
412 return 0;
413}
414
415// effect_interface_t interface implementation for visualizer effect
416const struct effect_interface_s gVisualizerInterface = {
417 Visualizer_process,
418 Visualizer_command
419};
420
421} // namespace
422