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 "EffectVisualizer" 18 //#define LOG_NDEBUG 0 19 20 #include <assert.h> 21 #include <inttypes.h> 22 #include <math.h> 23 #include <stdlib.h> 24 #include <string.h> 25 #include <time.h> 26 27 #include <new> 28 29 #include <log/log.h> 30 31 #include <audio_effects/effect_visualizer.h> 32 33 extern "C" { 34 35 // effect_handle_t interface implementation for visualizer effect 36 extern const struct effect_interface_s gVisualizerInterface; 37 38 // Google Visualizer UUID: d069d9e0-8329-11df-9168-0002a5d5c51b 39 const effect_descriptor_t gVisualizerDescriptor = { 40 {0xe46b26a0, 0xdddd, 0x11db, 0x8afd, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // type 41 {0xd069d9e0, 0x8329, 0x11df, 0x9168, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // uuid 42 EFFECT_CONTROL_API_VERSION, 43 (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST), 44 0, // TODO 45 1, 46 "Visualizer", 47 "The Android Open Source Project", 48 }; 49 50 enum visualizer_state_e { 51 VISUALIZER_STATE_UNINITIALIZED, 52 VISUALIZER_STATE_INITIALIZED, 53 VISUALIZER_STATE_ACTIVE, 54 }; 55 56 // maximum time since last capture buffer update before resetting capture buffer. This means 57 // that the framework has stopped playing audio and we must start returning silence 58 #define MAX_STALL_TIME_MS 1000 59 60 #define CAPTURE_BUF_SIZE 65536 // "64k should be enough for everyone" 61 62 #define DISCARD_MEASUREMENTS_TIME_MS 2000 // discard measurements older than this number of ms 63 64 #define MAX_LATENCY_MS 3000 // 3 seconds of latency for audio pipeline 65 66 // maximum number of buffers for which we keep track of the measurements 67 #define MEASUREMENT_WINDOW_MAX_SIZE_IN_BUFFERS 25 // note: buffer index is stored in uint8_t 68 69 70 struct BufferStats { 71 bool mIsValid; 72 uint16_t mPeakU16; // the positive peak of the absolute value of the samples in a buffer 73 float mRmsSquared; // the average square of the samples in a buffer 74 }; 75 76 struct VisualizerContext { 77 const struct effect_interface_s *mItfe; 78 effect_config_t mConfig; 79 uint32_t mCaptureIdx; 80 uint32_t mCaptureSize; 81 uint32_t mScalingMode; 82 uint8_t mState; 83 uint32_t mLastCaptureIdx; 84 uint32_t mLatency; 85 struct timespec mBufferUpdateTime; 86 uint8_t mCaptureBuf[CAPTURE_BUF_SIZE]; 87 // for measurements 88 uint8_t mChannelCount; // to avoid recomputing it every time a buffer is processed 89 uint32_t mMeasurementMode; 90 uint8_t mMeasurementWindowSizeInBuffers; 91 uint8_t mMeasurementBufferIdx; 92 BufferStats mPastMeasurements[MEASUREMENT_WINDOW_MAX_SIZE_IN_BUFFERS]; 93 }; 94 95 // 96 //--- Local functions 97 // 98 uint32_t Visualizer_getDeltaTimeMsFromUpdatedTime(VisualizerContext* pContext) { 99 uint32_t deltaMs = 0; 100 if (pContext->mBufferUpdateTime.tv_sec != 0) { 101 struct timespec ts; 102 if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) { 103 time_t secs = ts.tv_sec - pContext->mBufferUpdateTime.tv_sec; 104 long nsec = ts.tv_nsec - pContext->mBufferUpdateTime.tv_nsec; 105 if (nsec < 0) { 106 --secs; 107 nsec += 1000000000; 108 } 109 deltaMs = secs * 1000 + nsec / 1000000; 110 } 111 } 112 return deltaMs; 113 } 114 115 116 void Visualizer_reset(VisualizerContext *pContext) 117 { 118 pContext->mCaptureIdx = 0; 119 pContext->mLastCaptureIdx = 0; 120 pContext->mBufferUpdateTime.tv_sec = 0; 121 pContext->mLatency = 0; 122 memset(pContext->mCaptureBuf, 0x80, CAPTURE_BUF_SIZE); 123 } 124 125 //---------------------------------------------------------------------------- 126 // Visualizer_setConfig() 127 //---------------------------------------------------------------------------- 128 // Purpose: Set input and output audio configuration. 129 // 130 // Inputs: 131 // pContext: effect engine context 132 // pConfig: pointer to effect_config_t structure holding input and output 133 // configuration parameters 134 // 135 // Outputs: 136 // 137 //---------------------------------------------------------------------------- 138 139 int Visualizer_setConfig(VisualizerContext *pContext, effect_config_t *pConfig) 140 { 141 ALOGV("Visualizer_setConfig start"); 142 143 if (pConfig->inputCfg.samplingRate != pConfig->outputCfg.samplingRate) return -EINVAL; 144 if (pConfig->inputCfg.channels != pConfig->outputCfg.channels) return -EINVAL; 145 if (pConfig->inputCfg.format != pConfig->outputCfg.format) return -EINVAL; 146 if (pConfig->inputCfg.channels != AUDIO_CHANNEL_OUT_STEREO) return -EINVAL; 147 if (pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_WRITE && 148 pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_ACCUMULATE) return -EINVAL; 149 if (pConfig->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) return -EINVAL; 150 151 pContext->mConfig = *pConfig; 152 153 Visualizer_reset(pContext); 154 155 return 0; 156 } 157 158 159 //---------------------------------------------------------------------------- 160 // Visualizer_getConfig() 161 //---------------------------------------------------------------------------- 162 // Purpose: Get input and output audio configuration. 163 // 164 // Inputs: 165 // pContext: effect engine context 166 // pConfig: pointer to effect_config_t structure holding input and output 167 // configuration parameters 168 // 169 // Outputs: 170 // 171 //---------------------------------------------------------------------------- 172 173 void Visualizer_getConfig(VisualizerContext *pContext, effect_config_t *pConfig) 174 { 175 *pConfig = pContext->mConfig; 176 } 177 178 179 //---------------------------------------------------------------------------- 180 // Visualizer_init() 181 //---------------------------------------------------------------------------- 182 // Purpose: Initialize engine with default configuration. 183 // 184 // Inputs: 185 // pContext: effect engine context 186 // 187 // Outputs: 188 // 189 //---------------------------------------------------------------------------- 190 191 int Visualizer_init(VisualizerContext *pContext) 192 { 193 pContext->mConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ; 194 pContext->mConfig.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO; 195 pContext->mConfig.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT; 196 pContext->mConfig.inputCfg.samplingRate = 44100; 197 pContext->mConfig.inputCfg.bufferProvider.getBuffer = NULL; 198 pContext->mConfig.inputCfg.bufferProvider.releaseBuffer = NULL; 199 pContext->mConfig.inputCfg.bufferProvider.cookie = NULL; 200 pContext->mConfig.inputCfg.mask = EFFECT_CONFIG_ALL; 201 pContext->mConfig.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE; 202 pContext->mConfig.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO; 203 pContext->mConfig.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT; 204 pContext->mConfig.outputCfg.samplingRate = 44100; 205 pContext->mConfig.outputCfg.bufferProvider.getBuffer = NULL; 206 pContext->mConfig.outputCfg.bufferProvider.releaseBuffer = NULL; 207 pContext->mConfig.outputCfg.bufferProvider.cookie = NULL; 208 pContext->mConfig.outputCfg.mask = EFFECT_CONFIG_ALL; 209 210 // visualization initialization 211 pContext->mCaptureSize = VISUALIZER_CAPTURE_SIZE_MAX; 212 pContext->mScalingMode = VISUALIZER_SCALING_MODE_NORMALIZED; 213 214 // measurement initialization 215 pContext->mChannelCount = 216 audio_channel_count_from_out_mask(pContext->mConfig.inputCfg.channels); 217 pContext->mMeasurementMode = MEASUREMENT_MODE_NONE; 218 pContext->mMeasurementWindowSizeInBuffers = MEASUREMENT_WINDOW_MAX_SIZE_IN_BUFFERS; 219 pContext->mMeasurementBufferIdx = 0; 220 for (uint32_t i=0 ; i<pContext->mMeasurementWindowSizeInBuffers ; i++) { 221 pContext->mPastMeasurements[i].mIsValid = false; 222 pContext->mPastMeasurements[i].mPeakU16 = 0; 223 pContext->mPastMeasurements[i].mRmsSquared = 0; 224 } 225 226 Visualizer_setConfig(pContext, &pContext->mConfig); 227 228 return 0; 229 } 230 231 // 232 //--- Effect Library Interface Implementation 233 // 234 235 int VisualizerLib_Create(const effect_uuid_t *uuid, 236 int32_t /*sessionId*/, 237 int32_t /*ioId*/, 238 effect_handle_t *pHandle) { 239 int ret; 240 241 if (pHandle == NULL || uuid == NULL) { 242 return -EINVAL; 243 } 244 245 if (memcmp(uuid, &gVisualizerDescriptor.uuid, sizeof(effect_uuid_t)) != 0) { 246 return -EINVAL; 247 } 248 249 VisualizerContext *pContext = new VisualizerContext; 250 251 pContext->mItfe = &gVisualizerInterface; 252 pContext->mState = VISUALIZER_STATE_UNINITIALIZED; 253 254 ret = Visualizer_init(pContext); 255 if (ret < 0) { 256 ALOGW("VisualizerLib_Create() init failed"); 257 delete pContext; 258 return ret; 259 } 260 261 *pHandle = (effect_handle_t)pContext; 262 263 pContext->mState = VISUALIZER_STATE_INITIALIZED; 264 265 ALOGV("VisualizerLib_Create %p", pContext); 266 267 return 0; 268 269 } 270 271 int VisualizerLib_Release(effect_handle_t handle) { 272 VisualizerContext * pContext = (VisualizerContext *)handle; 273 274 ALOGV("VisualizerLib_Release %p", handle); 275 if (pContext == NULL) { 276 return -EINVAL; 277 } 278 pContext->mState = VISUALIZER_STATE_UNINITIALIZED; 279 delete pContext; 280 281 return 0; 282 } 283 284 int VisualizerLib_GetDescriptor(const effect_uuid_t *uuid, 285 effect_descriptor_t *pDescriptor) { 286 287 if (pDescriptor == NULL || uuid == NULL){ 288 ALOGV("VisualizerLib_GetDescriptor() called with NULL pointer"); 289 return -EINVAL; 290 } 291 292 if (memcmp(uuid, &gVisualizerDescriptor.uuid, sizeof(effect_uuid_t)) == 0) { 293 *pDescriptor = gVisualizerDescriptor; 294 return 0; 295 } 296 297 return -EINVAL; 298 } /* end VisualizerLib_GetDescriptor */ 299 300 // 301 //--- Effect Control Interface Implementation 302 // 303 304 static inline int16_t clamp16(int32_t sample) 305 { 306 if ((sample>>15) ^ (sample>>31)) 307 sample = 0x7FFF ^ (sample>>31); 308 return sample; 309 } 310 311 int Visualizer_process( 312 effect_handle_t self,audio_buffer_t *inBuffer, audio_buffer_t *outBuffer) 313 { 314 VisualizerContext * pContext = (VisualizerContext *)self; 315 316 if (pContext == NULL) { 317 return -EINVAL; 318 } 319 320 if (inBuffer == NULL || inBuffer->raw == NULL || 321 outBuffer == NULL || outBuffer->raw == NULL || 322 inBuffer->frameCount != outBuffer->frameCount || 323 inBuffer->frameCount == 0) { 324 return -EINVAL; 325 } 326 327 // perform measurements if needed 328 if (pContext->mMeasurementMode & MEASUREMENT_MODE_PEAK_RMS) { 329 // find the peak and RMS squared for the new buffer 330 uint32_t inIdx; 331 int16_t maxSample = 0; 332 float rmsSqAcc = 0; 333 for (inIdx = 0 ; inIdx < inBuffer->frameCount * pContext->mChannelCount ; inIdx++) { 334 if (inBuffer->s16[inIdx] > maxSample) { 335 maxSample = inBuffer->s16[inIdx]; 336 } else if (-inBuffer->s16[inIdx] > maxSample) { 337 maxSample = -inBuffer->s16[inIdx]; 338 } 339 rmsSqAcc += (inBuffer->s16[inIdx] * inBuffer->s16[inIdx]); 340 } 341 // store the measurement 342 pContext->mPastMeasurements[pContext->mMeasurementBufferIdx].mPeakU16 = (uint16_t)maxSample; 343 pContext->mPastMeasurements[pContext->mMeasurementBufferIdx].mRmsSquared = 344 rmsSqAcc / (inBuffer->frameCount * pContext->mChannelCount); 345 pContext->mPastMeasurements[pContext->mMeasurementBufferIdx].mIsValid = true; 346 if (++pContext->mMeasurementBufferIdx >= pContext->mMeasurementWindowSizeInBuffers) { 347 pContext->mMeasurementBufferIdx = 0; 348 } 349 } 350 351 // all code below assumes stereo 16 bit PCM output and input 352 int32_t shift; 353 354 if (pContext->mScalingMode == VISUALIZER_SCALING_MODE_NORMALIZED) { 355 // derive capture scaling factor from peak value in current buffer 356 // this gives more interesting captures for display. 357 shift = 32; 358 int len = inBuffer->frameCount * 2; 359 for (int i = 0; i < len; i++) { 360 int32_t smp = inBuffer->s16[i]; 361 if (smp < 0) smp = -smp - 1; // take care to keep the max negative in range 362 int32_t clz = __builtin_clz(smp); 363 if (shift > clz) shift = clz; 364 } 365 // A maximum amplitude signal will have 17 leading zeros, which we want to 366 // translate to a shift of 8 (for converting 16 bit to 8 bit) 367 shift = 25 - shift; 368 // Never scale by less than 8 to avoid returning unaltered PCM signal. 369 if (shift < 3) { 370 shift = 3; 371 } 372 // add one to combine the division by 2 needed after summing left and right channels below 373 shift++; 374 } else { 375 assert(pContext->mScalingMode == VISUALIZER_SCALING_MODE_AS_PLAYED); 376 shift = 9; 377 } 378 379 uint32_t captIdx; 380 uint32_t inIdx; 381 uint8_t *buf = pContext->mCaptureBuf; 382 for (inIdx = 0, captIdx = pContext->mCaptureIdx; 383 inIdx < inBuffer->frameCount; 384 inIdx++, captIdx++) { 385 if (captIdx >= CAPTURE_BUF_SIZE) { 386 // wrap around 387 captIdx = 0; 388 } 389 int32_t smp = inBuffer->s16[2 * inIdx] + inBuffer->s16[2 * inIdx + 1]; 390 smp = smp >> shift; 391 buf[captIdx] = ((uint8_t)smp)^0x80; 392 } 393 394 // XXX the following two should really be atomic, though it probably doesn't 395 // matter much for visualization purposes 396 pContext->mCaptureIdx = captIdx; 397 // update last buffer update time stamp 398 if (clock_gettime(CLOCK_MONOTONIC, &pContext->mBufferUpdateTime) < 0) { 399 pContext->mBufferUpdateTime.tv_sec = 0; 400 } 401 402 if (inBuffer->raw != outBuffer->raw) { 403 if (pContext->mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) { 404 for (size_t i = 0; i < outBuffer->frameCount*2; i++) { 405 outBuffer->s16[i] = clamp16(outBuffer->s16[i] + inBuffer->s16[i]); 406 } 407 } else { 408 memcpy(outBuffer->raw, inBuffer->raw, outBuffer->frameCount * 2 * sizeof(int16_t)); 409 } 410 } 411 if (pContext->mState != VISUALIZER_STATE_ACTIVE) { 412 return -ENODATA; 413 } 414 return 0; 415 } // end Visualizer_process 416 417 int Visualizer_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize, 418 void *pCmdData, uint32_t *replySize, void *pReplyData) { 419 420 VisualizerContext * pContext = (VisualizerContext *)self; 421 422 if (pContext == NULL || pContext->mState == VISUALIZER_STATE_UNINITIALIZED) { 423 return -EINVAL; 424 } 425 426 // ALOGV("Visualizer_command command %" PRIu32 " cmdSize %" PRIu32, cmdCode, cmdSize); 427 428 switch (cmdCode) { 429 case EFFECT_CMD_INIT: 430 if (pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)) { 431 return -EINVAL; 432 } 433 *(int *) pReplyData = Visualizer_init(pContext); 434 break; 435 case EFFECT_CMD_SET_CONFIG: 436 if (pCmdData == NULL || cmdSize != sizeof(effect_config_t) 437 || pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)) { 438 return -EINVAL; 439 } 440 *(int *) pReplyData = Visualizer_setConfig(pContext, 441 (effect_config_t *) pCmdData); 442 break; 443 case EFFECT_CMD_GET_CONFIG: 444 if (pReplyData == NULL || replySize == NULL || 445 *replySize != sizeof(effect_config_t)) { 446 return -EINVAL; 447 } 448 Visualizer_getConfig(pContext, (effect_config_t *)pReplyData); 449 break; 450 case EFFECT_CMD_RESET: 451 Visualizer_reset(pContext); 452 break; 453 case EFFECT_CMD_ENABLE: 454 if (pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)) { 455 return -EINVAL; 456 } 457 if (pContext->mState != VISUALIZER_STATE_INITIALIZED) { 458 return -ENOSYS; 459 } 460 pContext->mState = VISUALIZER_STATE_ACTIVE; 461 ALOGV("EFFECT_CMD_ENABLE() OK"); 462 *(int *)pReplyData = 0; 463 break; 464 case EFFECT_CMD_DISABLE: 465 if (pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)) { 466 return -EINVAL; 467 } 468 if (pContext->mState != VISUALIZER_STATE_ACTIVE) { 469 return -ENOSYS; 470 } 471 pContext->mState = VISUALIZER_STATE_INITIALIZED; 472 ALOGV("EFFECT_CMD_DISABLE() OK"); 473 *(int *)pReplyData = 0; 474 break; 475 case EFFECT_CMD_GET_PARAM: { 476 if (pCmdData == NULL || 477 cmdSize != (int)(sizeof(effect_param_t) + sizeof(uint32_t)) || 478 pReplyData == NULL || replySize == NULL || 479 *replySize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint32_t))) { 480 return -EINVAL; 481 } 482 memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + sizeof(uint32_t)); 483 effect_param_t *p = (effect_param_t *)pReplyData; 484 p->status = 0; 485 *replySize = sizeof(effect_param_t) + sizeof(uint32_t); 486 if (p->psize != sizeof(uint32_t)) { 487 p->status = -EINVAL; 488 break; 489 } 490 switch (*(uint32_t *)p->data) { 491 case VISUALIZER_PARAM_CAPTURE_SIZE: 492 ALOGV("get mCaptureSize = %" PRIu32, pContext->mCaptureSize); 493 *((uint32_t *)p->data + 1) = pContext->mCaptureSize; 494 p->vsize = sizeof(uint32_t); 495 *replySize += sizeof(uint32_t); 496 break; 497 case VISUALIZER_PARAM_SCALING_MODE: 498 ALOGV("get mScalingMode = %" PRIu32, pContext->mScalingMode); 499 *((uint32_t *)p->data + 1) = pContext->mScalingMode; 500 p->vsize = sizeof(uint32_t); 501 *replySize += sizeof(uint32_t); 502 break; 503 case VISUALIZER_PARAM_MEASUREMENT_MODE: 504 ALOGV("get mMeasurementMode = %" PRIu32, pContext->mMeasurementMode); 505 *((uint32_t *)p->data + 1) = pContext->mMeasurementMode; 506 p->vsize = sizeof(uint32_t); 507 *replySize += sizeof(uint32_t); 508 break; 509 default: 510 p->status = -EINVAL; 511 } 512 } break; 513 case EFFECT_CMD_SET_PARAM: { 514 if (pCmdData == NULL || 515 cmdSize != (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint32_t)) || 516 pReplyData == NULL || replySize == NULL || *replySize != sizeof(int32_t)) { 517 return -EINVAL; 518 } 519 *(int32_t *)pReplyData = 0; 520 effect_param_t *p = (effect_param_t *)pCmdData; 521 if (p->psize != sizeof(uint32_t) || p->vsize != sizeof(uint32_t)) { 522 *(int32_t *)pReplyData = -EINVAL; 523 break; 524 } 525 switch (*(uint32_t *)p->data) { 526 case VISUALIZER_PARAM_CAPTURE_SIZE: { 527 const uint32_t captureSize = *((uint32_t *)p->data + 1); 528 if (captureSize > VISUALIZER_CAPTURE_SIZE_MAX) { 529 android_errorWriteLog(0x534e4554, "31781965"); 530 *(int32_t *)pReplyData = -EINVAL; 531 ALOGW("set mCaptureSize = %u > %u", captureSize, VISUALIZER_CAPTURE_SIZE_MAX); 532 } else { 533 pContext->mCaptureSize = captureSize; 534 ALOGV("set mCaptureSize = %u", captureSize); 535 } 536 } break; 537 case VISUALIZER_PARAM_SCALING_MODE: 538 pContext->mScalingMode = *((uint32_t *)p->data + 1); 539 ALOGV("set mScalingMode = %" PRIu32, pContext->mScalingMode); 540 break; 541 case VISUALIZER_PARAM_LATENCY: { 542 uint32_t latency = *((uint32_t *)p->data + 1); 543 if (latency > MAX_LATENCY_MS) { 544 latency = MAX_LATENCY_MS; // clamp latency b/31781965 545 } 546 pContext->mLatency = latency; 547 ALOGV("set mLatency = %u", latency); 548 } break; 549 case VISUALIZER_PARAM_MEASUREMENT_MODE: 550 pContext->mMeasurementMode = *((uint32_t *)p->data + 1); 551 ALOGV("set mMeasurementMode = %" PRIu32, pContext->mMeasurementMode); 552 break; 553 default: 554 *(int32_t *)pReplyData = -EINVAL; 555 } 556 } break; 557 case EFFECT_CMD_SET_DEVICE: 558 case EFFECT_CMD_SET_VOLUME: 559 case EFFECT_CMD_SET_AUDIO_MODE: 560 break; 561 562 563 case VISUALIZER_CMD_CAPTURE: { 564 uint32_t captureSize = pContext->mCaptureSize; 565 if (pReplyData == NULL || replySize == NULL || *replySize != captureSize) { 566 ALOGV("VISUALIZER_CMD_CAPTURE() error *replySize %" PRIu32 " captureSize %" PRIu32, 567 *replySize, captureSize); 568 return -EINVAL; 569 } 570 if (pContext->mState == VISUALIZER_STATE_ACTIVE) { 571 const uint32_t deltaMs = Visualizer_getDeltaTimeMsFromUpdatedTime(pContext); 572 573 // if audio framework has stopped playing audio although the effect is still 574 // active we must clear the capture buffer to return silence 575 if ((pContext->mLastCaptureIdx == pContext->mCaptureIdx) && 576 (pContext->mBufferUpdateTime.tv_sec != 0) && 577 (deltaMs > MAX_STALL_TIME_MS)) { 578 ALOGV("capture going to idle"); 579 pContext->mBufferUpdateTime.tv_sec = 0; 580 memset(pReplyData, 0x80, captureSize); 581 } else { 582 int32_t latencyMs = pContext->mLatency; 583 latencyMs -= deltaMs; 584 if (latencyMs < 0) { 585 latencyMs = 0; 586 } 587 uint32_t deltaSmpl = captureSize 588 + pContext->mConfig.inputCfg.samplingRate * latencyMs / 1000; 589 590 // large sample rate, latency, or capture size, could cause overflow. 591 // do not offset more than the size of buffer. 592 if (deltaSmpl > CAPTURE_BUF_SIZE) { 593 android_errorWriteLog(0x534e4554, "31781965"); 594 deltaSmpl = CAPTURE_BUF_SIZE; 595 } 596 597 int32_t capturePoint; 598 //capturePoint = (int32_t)pContext->mCaptureIdx - deltaSmpl; 599 __builtin_sub_overflow((int32_t)pContext->mCaptureIdx, deltaSmpl, &capturePoint); 600 // a negative capturePoint means we wrap the buffer. 601 if (capturePoint < 0) { 602 uint32_t size = -capturePoint; 603 if (size > captureSize) { 604 size = captureSize; 605 } 606 memcpy(pReplyData, 607 pContext->mCaptureBuf + CAPTURE_BUF_SIZE + capturePoint, 608 size); 609 pReplyData = (char *)pReplyData + size; 610 captureSize -= size; 611 capturePoint = 0; 612 } 613 memcpy(pReplyData, 614 pContext->mCaptureBuf + capturePoint, 615 captureSize); 616 } 617 618 pContext->mLastCaptureIdx = pContext->mCaptureIdx; 619 } else { 620 memset(pReplyData, 0x80, captureSize); 621 } 622 623 } break; 624 625 case VISUALIZER_CMD_MEASURE: { 626 if (pReplyData == NULL || replySize == NULL || 627 *replySize < (sizeof(int32_t) * MEASUREMENT_COUNT)) { 628 if (replySize == NULL) { 629 ALOGV("VISUALIZER_CMD_MEASURE() error replySize NULL"); 630 } else { 631 ALOGV("VISUALIZER_CMD_MEASURE() error *replySize %" PRIu32 632 " < (sizeof(int32_t) * MEASUREMENT_COUNT) %" PRIu32, 633 *replySize, 634 uint32_t(sizeof(int32_t)) * MEASUREMENT_COUNT); 635 } 636 android_errorWriteLog(0x534e4554, "30229821"); 637 return -EINVAL; 638 } 639 uint16_t peakU16 = 0; 640 float sumRmsSquared = 0.0f; 641 uint8_t nbValidMeasurements = 0; 642 // reset measurements if last measurement was too long ago (which implies stored 643 // measurements aren't relevant anymore and shouldn't bias the new one) 644 const int32_t delayMs = Visualizer_getDeltaTimeMsFromUpdatedTime(pContext); 645 if (delayMs > DISCARD_MEASUREMENTS_TIME_MS) { 646 ALOGV("Discarding measurements, last measurement is %" PRId32 "ms old", delayMs); 647 for (uint32_t i=0 ; i<pContext->mMeasurementWindowSizeInBuffers ; i++) { 648 pContext->mPastMeasurements[i].mIsValid = false; 649 pContext->mPastMeasurements[i].mPeakU16 = 0; 650 pContext->mPastMeasurements[i].mRmsSquared = 0; 651 } 652 pContext->mMeasurementBufferIdx = 0; 653 } else { 654 // only use actual measurements, otherwise the first RMS measure happening before 655 // MEASUREMENT_WINDOW_MAX_SIZE_IN_BUFFERS have been played will always be artificially 656 // low 657 for (uint32_t i=0 ; i < pContext->mMeasurementWindowSizeInBuffers ; i++) { 658 if (pContext->mPastMeasurements[i].mIsValid) { 659 if (pContext->mPastMeasurements[i].mPeakU16 > peakU16) { 660 peakU16 = pContext->mPastMeasurements[i].mPeakU16; 661 } 662 sumRmsSquared += pContext->mPastMeasurements[i].mRmsSquared; 663 nbValidMeasurements++; 664 } 665 } 666 } 667 float rms = nbValidMeasurements == 0 ? 0.0f : sqrtf(sumRmsSquared / nbValidMeasurements); 668 int32_t* pIntReplyData = (int32_t*)pReplyData; 669 // convert from I16 sample values to mB and write results 670 if (rms < 0.000016f) { 671 pIntReplyData[MEASUREMENT_IDX_RMS] = -9600; //-96dB 672 } else { 673 pIntReplyData[MEASUREMENT_IDX_RMS] = (int32_t) (2000 * log10(rms / 32767.0f)); 674 } 675 if (peakU16 == 0) { 676 pIntReplyData[MEASUREMENT_IDX_PEAK] = -9600; //-96dB 677 } else { 678 pIntReplyData[MEASUREMENT_IDX_PEAK] = (int32_t) (2000 * log10(peakU16 / 32767.0f)); 679 } 680 ALOGV("VISUALIZER_CMD_MEASURE peak=%" PRIu16 " (%" PRId32 "mB), rms=%.1f (%" PRId32 "mB)", 681 peakU16, pIntReplyData[MEASUREMENT_IDX_PEAK], 682 rms, pIntReplyData[MEASUREMENT_IDX_RMS]); 683 } 684 break; 685 686 default: 687 ALOGW("Visualizer_command invalid command %" PRIu32, cmdCode); 688 return -EINVAL; 689 } 690 691 return 0; 692 } 693 694 /* Effect Control Interface Implementation: get_descriptor */ 695 int Visualizer_getDescriptor(effect_handle_t self, 696 effect_descriptor_t *pDescriptor) 697 { 698 VisualizerContext * pContext = (VisualizerContext *) self; 699 700 if (pContext == NULL || pDescriptor == NULL) { 701 ALOGV("Visualizer_getDescriptor() invalid param"); 702 return -EINVAL; 703 } 704 705 *pDescriptor = gVisualizerDescriptor; 706 707 return 0; 708 } /* end Visualizer_getDescriptor */ 709 710 // effect_handle_t interface implementation for visualizer effect 711 const struct effect_interface_s gVisualizerInterface = { 712 Visualizer_process, 713 Visualizer_command, 714 Visualizer_getDescriptor, 715 NULL, 716 }; 717 718 // This is the only symbol that needs to be exported 719 __attribute__ ((visibility ("default"))) 720 audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = { 721 .tag = AUDIO_EFFECT_LIBRARY_TAG, 722 .version = EFFECT_LIBRARY_API_VERSION, 723 .name = "Visualizer Library", 724 .implementor = "The Android Open Source Project", 725 .create_effect = VisualizerLib_Create, 726 .release_effect = VisualizerLib_Release, 727 .get_descriptor = VisualizerLib_GetDescriptor, 728 }; 729 730 }; // extern "C" 731