1/* 2** 3** Copyright 2010, The Android Open Source Project 4** 5** Licensed under the Apache License, Version 2.0 (the "License"); 6** you may not use this file except in compliance with the License. 7** You may obtain a copy of the License at 8** 9** http://www.apache.org/licenses/LICENSE-2.0 10** 11** Unless required by applicable law or agreed to in writing, software 12** distributed under the License is distributed on an "AS IS" BASIS, 13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14** See the License for the specific language governing permissions and 15** limitations under the License. 16*/ 17 18 19//#define LOG_NDEBUG 0 20#define LOG_TAG "Visualizer" 21#include <utils/Log.h> 22 23#include <stdint.h> 24#include <sys/types.h> 25#include <limits.h> 26 27#include <cutils/bitops.h> 28 29#include <media/Visualizer.h> 30#include <audio_utils/fixedfft.h> 31#include <utils/Thread.h> 32 33namespace android { 34 35// --------------------------------------------------------------------------- 36 37Visualizer::Visualizer (const String16& opPackageName, 38 int32_t priority, 39 effect_callback_t cbf, 40 void* user, 41 audio_session_t sessionId) 42 : AudioEffect(SL_IID_VISUALIZATION, opPackageName, NULL, priority, cbf, user, sessionId), 43 mCaptureRate(CAPTURE_RATE_DEF), 44 mCaptureSize(CAPTURE_SIZE_DEF), 45 mSampleRate(44100000), 46 mScalingMode(VISUALIZER_SCALING_MODE_NORMALIZED), 47 mMeasurementMode(MEASUREMENT_MODE_NONE), 48 mCaptureCallBack(NULL), 49 mCaptureCbkUser(NULL) 50{ 51 initCaptureSize(); 52} 53 54Visualizer::~Visualizer() 55{ 56 ALOGV("Visualizer::~Visualizer()"); 57 setEnabled(false); 58 setCaptureCallBack(NULL, NULL, 0, 0); 59} 60 61status_t Visualizer::setEnabled(bool enabled) 62{ 63 Mutex::Autolock _l(mCaptureLock); 64 65 sp<CaptureThread> t = mCaptureThread; 66 if (t != 0) { 67 if (enabled) { 68 if (t->exitPending()) { 69 if (t->requestExitAndWait() == WOULD_BLOCK) { 70 ALOGE("Visualizer::enable() called from thread"); 71 return INVALID_OPERATION; 72 } 73 } 74 } 75 t->mLock.lock(); 76 } 77 78 status_t status = AudioEffect::setEnabled(enabled); 79 80 if (t != 0) { 81 if (enabled && status == NO_ERROR) { 82 t->run("Visualizer"); 83 } else { 84 t->requestExit(); 85 } 86 } 87 88 if (t != 0) { 89 t->mLock.unlock(); 90 } 91 92 return status; 93} 94 95status_t Visualizer::setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t flags, 96 uint32_t rate) 97{ 98 if (rate > CAPTURE_RATE_MAX) { 99 return BAD_VALUE; 100 } 101 Mutex::Autolock _l(mCaptureLock); 102 103 if (mEnabled) { 104 return INVALID_OPERATION; 105 } 106 107 if (mCaptureThread != 0) { 108 mCaptureLock.unlock(); 109 mCaptureThread->requestExitAndWait(); 110 mCaptureLock.lock(); 111 } 112 113 mCaptureThread.clear(); 114 mCaptureCallBack = cbk; 115 mCaptureCbkUser = user; 116 mCaptureFlags = flags; 117 mCaptureRate = rate; 118 119 if (cbk != NULL) { 120 mCaptureThread = new CaptureThread(*this, rate, ((flags & CAPTURE_CALL_JAVA) != 0)); 121 } 122 ALOGV("setCaptureCallBack() rate: %d thread %p flags 0x%08x", 123 rate, mCaptureThread.get(), mCaptureFlags); 124 return NO_ERROR; 125} 126 127status_t Visualizer::setCaptureSize(uint32_t size) 128{ 129 if (size > VISUALIZER_CAPTURE_SIZE_MAX || 130 size < VISUALIZER_CAPTURE_SIZE_MIN || 131 popcount(size) != 1) { 132 return BAD_VALUE; 133 } 134 135 Mutex::Autolock _l(mCaptureLock); 136 if (mEnabled) { 137 return INVALID_OPERATION; 138 } 139 140 uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2]; 141 effect_param_t *p = (effect_param_t *)buf32; 142 143 p->psize = sizeof(uint32_t); 144 p->vsize = sizeof(uint32_t); 145 *(int32_t *)p->data = VISUALIZER_PARAM_CAPTURE_SIZE; 146 *((int32_t *)p->data + 1)= size; 147 status_t status = setParameter(p); 148 149 ALOGV("setCaptureSize size %d status %d p->status %d", size, status, p->status); 150 151 if (status == NO_ERROR) { 152 status = p->status; 153 if (status == NO_ERROR) { 154 mCaptureSize = size; 155 } 156 } 157 158 return status; 159} 160 161status_t Visualizer::setScalingMode(uint32_t mode) { 162 if ((mode != VISUALIZER_SCALING_MODE_NORMALIZED) 163 && (mode != VISUALIZER_SCALING_MODE_AS_PLAYED)) { 164 return BAD_VALUE; 165 } 166 167 Mutex::Autolock _l(mCaptureLock); 168 169 uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2]; 170 effect_param_t *p = (effect_param_t *)buf32; 171 172 p->psize = sizeof(uint32_t); 173 p->vsize = sizeof(uint32_t); 174 *(int32_t *)p->data = VISUALIZER_PARAM_SCALING_MODE; 175 *((int32_t *)p->data + 1)= mode; 176 status_t status = setParameter(p); 177 178 ALOGV("setScalingMode mode %d status %d p->status %d", mode, status, p->status); 179 180 if (status == NO_ERROR) { 181 status = p->status; 182 if (status == NO_ERROR) { 183 mScalingMode = mode; 184 } 185 } 186 187 return status; 188} 189 190status_t Visualizer::setMeasurementMode(uint32_t mode) { 191 if ((mode != MEASUREMENT_MODE_NONE) 192 //Note: needs to be handled as a mask when more measurement modes are added 193 && ((mode & MEASUREMENT_MODE_PEAK_RMS) != mode)) { 194 return BAD_VALUE; 195 } 196 197 Mutex::Autolock _l(mCaptureLock); 198 199 uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2]; 200 effect_param_t *p = (effect_param_t *)buf32; 201 202 p->psize = sizeof(uint32_t); 203 p->vsize = sizeof(uint32_t); 204 *(int32_t *)p->data = VISUALIZER_PARAM_MEASUREMENT_MODE; 205 *((int32_t *)p->data + 1)= mode; 206 status_t status = setParameter(p); 207 208 ALOGV("setMeasurementMode mode %d status %d p->status %d", mode, status, p->status); 209 210 if (status == NO_ERROR) { 211 status = p->status; 212 if (status == NO_ERROR) { 213 mMeasurementMode = mode; 214 } 215 } 216 return status; 217} 218 219status_t Visualizer::getIntMeasurements(uint32_t type, uint32_t number, int32_t *measurements) { 220 if (mMeasurementMode == MEASUREMENT_MODE_NONE) { 221 ALOGE("Cannot retrieve int measurements, no measurement mode set"); 222 return INVALID_OPERATION; 223 } 224 if (!(mMeasurementMode & type)) { 225 // measurement type has not been set on this Visualizer 226 ALOGE("Cannot retrieve int measurements, requested measurement mode 0x%x not set(0x%x)", 227 type, mMeasurementMode); 228 return INVALID_OPERATION; 229 } 230 // only peak+RMS measurement supported 231 if ((type != MEASUREMENT_MODE_PEAK_RMS) 232 // for peak+RMS measurement, the results are 2 int32_t values 233 || (number != 2)) { 234 ALOGE("Cannot retrieve int measurements, MEASUREMENT_MODE_PEAK_RMS returns 2 ints, not %d", 235 number); 236 return BAD_VALUE; 237 } 238 239 status_t status = NO_ERROR; 240 if (mEnabled) { 241 uint32_t replySize = number * sizeof(int32_t); 242 status = command(VISUALIZER_CMD_MEASURE, 243 sizeof(uint32_t) /*cmdSize*/, 244 &type /*cmdData*/, 245 &replySize, measurements); 246 ALOGV("getMeasurements() command returned %d", status); 247 if ((status == NO_ERROR) && (replySize == 0)) { 248 status = NOT_ENOUGH_DATA; 249 } 250 } else { 251 ALOGV("getMeasurements() disabled"); 252 return INVALID_OPERATION; 253 } 254 return status; 255} 256 257status_t Visualizer::getWaveForm(uint8_t *waveform) 258{ 259 if (waveform == NULL) { 260 return BAD_VALUE; 261 } 262 if (mCaptureSize == 0) { 263 return NO_INIT; 264 } 265 266 status_t status = NO_ERROR; 267 if (mEnabled) { 268 uint32_t replySize = mCaptureSize; 269 status = command(VISUALIZER_CMD_CAPTURE, 0, NULL, &replySize, waveform); 270 ALOGV("getWaveForm() command returned %d", status); 271 if ((status == NO_ERROR) && (replySize == 0)) { 272 status = NOT_ENOUGH_DATA; 273 } 274 } else { 275 ALOGV("getWaveForm() disabled"); 276 memset(waveform, 0x80, mCaptureSize); 277 } 278 return status; 279} 280 281status_t Visualizer::getFft(uint8_t *fft) 282{ 283 if (fft == NULL) { 284 return BAD_VALUE; 285 } 286 if (mCaptureSize == 0) { 287 return NO_INIT; 288 } 289 290 status_t status = NO_ERROR; 291 if (mEnabled) { 292 uint8_t buf[mCaptureSize]; 293 status = getWaveForm(buf); 294 if (status == NO_ERROR) { 295 status = doFft(fft, buf); 296 } 297 } else { 298 memset(fft, 0, mCaptureSize); 299 } 300 return status; 301} 302 303status_t Visualizer::doFft(uint8_t *fft, uint8_t *waveform) 304{ 305 int32_t workspace[mCaptureSize >> 1]; 306 int32_t nonzero = 0; 307 308 for (uint32_t i = 0; i < mCaptureSize; i += 2) { 309 workspace[i >> 1] = 310 ((waveform[i] ^ 0x80) << 24) | ((waveform[i + 1] ^ 0x80) << 8); 311 nonzero |= workspace[i >> 1]; 312 } 313 314 if (nonzero) { 315 fixed_fft_real(mCaptureSize >> 1, workspace); 316 } 317 318 for (uint32_t i = 0; i < mCaptureSize; i += 2) { 319 short tmp = workspace[i >> 1] >> 21; 320 while (tmp > 127 || tmp < -128) tmp >>= 1; 321 fft[i] = tmp; 322 tmp = workspace[i >> 1]; 323 tmp >>= 5; 324 while (tmp > 127 || tmp < -128) tmp >>= 1; 325 fft[i + 1] = tmp; 326 } 327 328 return NO_ERROR; 329} 330 331void Visualizer::periodicCapture() 332{ 333 Mutex::Autolock _l(mCaptureLock); 334 ALOGV("periodicCapture() %p mCaptureCallBack %p mCaptureFlags 0x%08x", 335 this, mCaptureCallBack, mCaptureFlags); 336 if (mCaptureCallBack != NULL && 337 (mCaptureFlags & (CAPTURE_WAVEFORM|CAPTURE_FFT)) && 338 mCaptureSize != 0) { 339 uint8_t waveform[mCaptureSize]; 340 status_t status = getWaveForm(waveform); 341 if (status != NO_ERROR) { 342 return; 343 } 344 uint8_t fft[mCaptureSize]; 345 if (mCaptureFlags & CAPTURE_FFT) { 346 status = doFft(fft, waveform); 347 } 348 if (status != NO_ERROR) { 349 return; 350 } 351 uint8_t *wavePtr = NULL; 352 uint8_t *fftPtr = NULL; 353 uint32_t waveSize = 0; 354 uint32_t fftSize = 0; 355 if (mCaptureFlags & CAPTURE_WAVEFORM) { 356 wavePtr = waveform; 357 waveSize = mCaptureSize; 358 } 359 if (mCaptureFlags & CAPTURE_FFT) { 360 fftPtr = fft; 361 fftSize = mCaptureSize; 362 } 363 mCaptureCallBack(mCaptureCbkUser, waveSize, wavePtr, fftSize, fftPtr, mSampleRate); 364 } 365} 366 367uint32_t Visualizer::initCaptureSize() 368{ 369 uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2]; 370 effect_param_t *p = (effect_param_t *)buf32; 371 372 p->psize = sizeof(uint32_t); 373 p->vsize = sizeof(uint32_t); 374 *(int32_t *)p->data = VISUALIZER_PARAM_CAPTURE_SIZE; 375 status_t status = getParameter(p); 376 377 if (status == NO_ERROR) { 378 status = p->status; 379 } 380 381 uint32_t size = 0; 382 if (status == NO_ERROR) { 383 size = *((int32_t *)p->data + 1); 384 } 385 mCaptureSize = size; 386 387 ALOGV("initCaptureSize size %d status %d", mCaptureSize, status); 388 389 return size; 390} 391 392void Visualizer::controlStatusChanged(bool controlGranted) { 393 if (controlGranted) { 394 // this Visualizer instance regained control of the effect, reset the scaling mode 395 // and capture size as has been cached through it. 396 ALOGV("controlStatusChanged(true) causes effect parameter reset:"); 397 ALOGV(" scaling mode reset to %d", mScalingMode); 398 setScalingMode(mScalingMode); 399 ALOGV(" capture size reset to %d", mCaptureSize); 400 setCaptureSize(mCaptureSize); 401 } 402 AudioEffect::controlStatusChanged(controlGranted); 403} 404 405//------------------------------------------------------------------------- 406 407Visualizer::CaptureThread::CaptureThread(Visualizer& receiver, uint32_t captureRate, 408 bool bCanCallJava) 409 : Thread(bCanCallJava), mReceiver(receiver) 410{ 411 mSleepTimeUs = 1000000000 / captureRate; 412 ALOGV("CaptureThread cstor %p captureRate %d mSleepTimeUs %d", this, captureRate, mSleepTimeUs); 413} 414 415bool Visualizer::CaptureThread::threadLoop() 416{ 417 ALOGV("CaptureThread %p enter", this); 418 while (!exitPending()) 419 { 420 usleep(mSleepTimeUs); 421 mReceiver.periodicCapture(); 422 } 423 ALOGV("CaptureThread %p exiting", this); 424 return false; 425} 426 427} // namespace android 428