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 33 namespace android { 34 35 // --------------------------------------------------------------------------- 36 37 Visualizer::Visualizer (int32_t priority, 38 effect_callback_t cbf, 39 void* user, 40 int sessionId) 41 : AudioEffect(SL_IID_VISUALIZATION, NULL, priority, cbf, user, sessionId), 42 mCaptureRate(CAPTURE_RATE_DEF), 43 mCaptureSize(CAPTURE_SIZE_DEF), 44 mSampleRate(44100000), 45 mScalingMode(VISUALIZER_SCALING_MODE_NORMALIZED), 46 mMeasurementMode(MEASUREMENT_MODE_NONE), 47 mCaptureCallBack(NULL), 48 mCaptureCbkUser(NULL) 49 { 50 initCaptureSize(); 51 } 52 53 Visualizer::~Visualizer() 54 { 55 } 56 57 status_t Visualizer::setEnabled(bool enabled) 58 { 59 Mutex::Autolock _l(mCaptureLock); 60 61 sp<CaptureThread> t = mCaptureThread; 62 if (t != 0) { 63 if (enabled) { 64 if (t->exitPending()) { 65 if (t->requestExitAndWait() == WOULD_BLOCK) { 66 ALOGE("Visualizer::enable() called from thread"); 67 return INVALID_OPERATION; 68 } 69 } 70 } 71 t->mLock.lock(); 72 } 73 74 status_t status = AudioEffect::setEnabled(enabled); 75 76 if (status == NO_ERROR) { 77 if (t != 0) { 78 if (enabled) { 79 t->run("Visualizer"); 80 } else { 81 t->requestExit(); 82 } 83 } 84 } 85 86 if (t != 0) { 87 t->mLock.unlock(); 88 } 89 90 return status; 91 } 92 93 status_t Visualizer::setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t flags, 94 uint32_t rate) 95 { 96 if (rate > CAPTURE_RATE_MAX) { 97 return BAD_VALUE; 98 } 99 Mutex::Autolock _l(mCaptureLock); 100 101 if (mEnabled) { 102 return INVALID_OPERATION; 103 } 104 105 sp<CaptureThread> t = mCaptureThread; 106 if (t != 0) { 107 t->mLock.lock(); 108 } 109 mCaptureThread.clear(); 110 mCaptureCallBack = cbk; 111 mCaptureCbkUser = user; 112 mCaptureFlags = flags; 113 mCaptureRate = rate; 114 115 if (t != 0) { 116 t->mLock.unlock(); 117 } 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 127 status_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 161 status_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 190 status_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 219 status_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 257 status_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 281 status_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 303 status_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 331 void 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 367 uint32_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 392 void 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 407 Visualizer::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 415 bool 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