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