blob: 8ab57c932345972274d963d98d22fa7b87007272 [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>
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;
68 memset(pContext->mCaptureBuf[0], 0, VISUALIZER_CAPTURE_SIZE_MAX);
69 memset(pContext->mCaptureBuf[1], 0, VISUALIZER_CAPTURE_SIZE_MAX);
70}
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 Laurentdf9b81c2010-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
242 uint32_t captIdx;
243 uint32_t inIdx;
244 uint8_t *buf = pContext->mCaptureBuf[pContext->mCurrentBuf];
245 for (inIdx = 0, captIdx = pContext->mCaptureIdx;
246 inIdx < inBuffer->frameCount && captIdx < pContext->mCaptureSize;
247 inIdx++, captIdx++) {
248 int32_t smp = inBuffer->s16[2 * inIdx] + inBuffer->s16[2 * inIdx + 1];
249 smp = (smp + (1 << 8)) >> 9;
250 buf[captIdx] = ((uint8_t)smp)^0x80;
251 }
252 pContext->mCaptureIdx = captIdx;
253
254 // go to next buffer when buffer full
255 if (pContext->mCaptureIdx == pContext->mCaptureSize) {
256 pContext->mCurrentBuf ^= 1;
257 pContext->mCaptureIdx = 0;
258 }
259
260 if (inBuffer->raw != outBuffer->raw) {
261 if (pContext->mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
262 for (size_t i = 0; i < outBuffer->frameCount*2; i++) {
263 outBuffer->s16[i] = clamp16(outBuffer->s16[i] + inBuffer->s16[i]);
264 }
265 } else {
266 memcpy(outBuffer->raw, inBuffer->raw, outBuffer->frameCount * 2 * sizeof(int16_t));
267 }
268 }
Eric Laurent0d7e0482010-07-19 06:24:46 -0700269 if (pContext->mState != VISUALIZER_STATE_ACTIVE) {
270 return -ENODATA;
271 }
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700272 return 0;
273} // end Visualizer_process
274
Eric Laurenta4c72ac2010-07-28 05:40:18 -0700275extern "C" int Visualizer_command(effect_interface_t self, uint32_t cmdCode, uint32_t cmdSize,
276 void *pCmdData, uint32_t *replySize, void *pReplyData) {
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700277
278 android::VisualizerContext * pContext = (android::VisualizerContext *)self;
279 int retsize;
280
281 if (pContext == NULL || pContext->mState == VISUALIZER_STATE_UNINITIALIZED) {
282 return -EINVAL;
283 }
284
285// LOGV("Visualizer_command command %d cmdSize %d",cmdCode, cmdSize);
286
287 switch (cmdCode) {
288 case EFFECT_CMD_INIT:
289 if (pReplyData == NULL || *replySize != sizeof(int)) {
290 return -EINVAL;
291 }
292 *(int *) pReplyData = Visualizer_init(pContext);
293 break;
294 case EFFECT_CMD_CONFIGURE:
295 if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
296 || pReplyData == NULL || *replySize != sizeof(int)) {
297 return -EINVAL;
298 }
299 *(int *) pReplyData = Visualizer_configure(pContext,
300 (effect_config_t *) pCmdData);
301 break;
302 case EFFECT_CMD_RESET:
303 Visualizer_reset(pContext);
304 break;
305 case EFFECT_CMD_ENABLE:
306 if (pReplyData == NULL || *replySize != sizeof(int)) {
307 return -EINVAL;
308 }
309 if (pContext->mState != VISUALIZER_STATE_INITIALIZED) {
310 return -ENOSYS;
311 }
312 pContext->mState = VISUALIZER_STATE_ACTIVE;
313 LOGV("EFFECT_CMD_ENABLE() OK");
314 *(int *)pReplyData = 0;
315 break;
316 case EFFECT_CMD_DISABLE:
317 if (pReplyData == NULL || *replySize != sizeof(int)) {
318 return -EINVAL;
319 }
320 if (pContext->mState != VISUALIZER_STATE_ACTIVE) {
321 return -ENOSYS;
322 }
323 pContext->mState = VISUALIZER_STATE_INITIALIZED;
324 LOGV("EFFECT_CMD_DISABLE() OK");
325 *(int *)pReplyData = 0;
326 break;
327 case EFFECT_CMD_GET_PARAM: {
328 if (pCmdData == NULL ||
329 cmdSize != (int)(sizeof(effect_param_t) + sizeof(uint32_t)) ||
330 pReplyData == NULL ||
331 *replySize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint32_t))) {
332 return -EINVAL;
333 }
334 memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + sizeof(uint32_t));
335 effect_param_t *p = (effect_param_t *)pReplyData;
336 p->status = 0;
337 *replySize = sizeof(effect_param_t) + sizeof(uint32_t);
338 if (p->psize != sizeof(uint32_t) ||
339 *(uint32_t *)p->data != VISU_PARAM_CAPTURE_SIZE) {
340 p->status = -EINVAL;
341 break;
342 }
343 LOGV("get mCaptureSize = %d", pContext->mCaptureSize);
344 *((uint32_t *)p->data + 1) = pContext->mCaptureSize;
345 p->vsize = sizeof(uint32_t);
346 *replySize += sizeof(uint32_t);
347 } break;
348 case EFFECT_CMD_SET_PARAM: {
349 if (pCmdData == NULL ||
350 cmdSize != (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint32_t)) ||
351 pReplyData == NULL || *replySize != sizeof(int32_t)) {
352 return -EINVAL;
353 }
354 *(int32_t *)pReplyData = 0;
355 effect_param_t *p = (effect_param_t *)pCmdData;
356 if (p->psize != sizeof(uint32_t) ||
357 p->vsize != sizeof(uint32_t) ||
358 *(uint32_t *)p->data != VISU_PARAM_CAPTURE_SIZE) {
359 *(int32_t *)pReplyData = -EINVAL;
360 break;;
361 }
362 pContext->mCaptureSize = *((uint32_t *)p->data + 1);
363 LOGV("set mCaptureSize = %d", pContext->mCaptureSize);
364 } break;
365 case EFFECT_CMD_SET_DEVICE:
366 case EFFECT_CMD_SET_VOLUME:
367 case EFFECT_CMD_SET_AUDIO_MODE:
368 break;
369
370
371 case VISU_CMD_CAPTURE:
372 if (pReplyData == NULL || *replySize != (int)pContext->mCaptureSize) {
373 LOGV("VISU_CMD_CAPTURE() error *replySize %d pContext->mCaptureSize %d",
374 *replySize, pContext->mCaptureSize);
375 return -EINVAL;
376 }
377 if (pContext->mState == VISUALIZER_STATE_ACTIVE) {
378 memcpy(pReplyData,
379 pContext->mCaptureBuf[pContext->mCurrentBuf ^ 1],
380 pContext->mCaptureSize);
381 } else {
382 memset(pReplyData, 0x80, pContext->mCaptureSize);
383 }
384 break;
385
386 default:
387 LOGW("Visualizer_command invalid command %d",cmdCode);
388 return -EINVAL;
389 }
390
391 return 0;
392}
393
394// effect_interface_t interface implementation for visualizer effect
395const struct effect_interface_s gVisualizerInterface = {
396 Visualizer_process,
397 Visualizer_command
398};
399
400} // namespace
401