EffectVisualizer.cpp revision 25f4395b932fa9859a6e91ba77c5d20d009da64a
1/* 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 } 233 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 } 269 if (pContext->mState != VISUALIZER_STATE_ACTIVE) { 270 return -ENODATA; 271 } 272 return 0; 273} // end Visualizer_process 274 275extern "C" int Visualizer_command(effect_interface_t self, uint32_t cmdCode, uint32_t cmdSize, 276 void *pCmdData, uint32_t *replySize, void *pReplyData) { 277 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 402