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