Visualizer.cpp revision 209821c7b7ead3ac58743d0a6d21dd05a2e77708
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 29extern void fixed_fft_real(int n, int32_t *v); 30 31namespace android { 32 33// --------------------------------------------------------------------------- 34 35Visualizer::Visualizer (int32_t priority, 36 effect_callback_t cbf, 37 void* user, 38 int sessionId) 39 : AudioEffect(SL_IID_VISUALIZATION, NULL, priority, cbf, user, sessionId), 40 mCaptureRate(CAPTURE_RATE_DEF), 41 mCaptureSize(CAPTURE_SIZE_DEF), 42 mSampleRate(44100000), 43 mCaptureCallBack(NULL), 44 mCaptureCbkUser(NULL) 45{ 46 initCaptureSize(); 47} 48 49Visualizer::~Visualizer() 50{ 51} 52 53status_t Visualizer::setEnabled(bool enabled) 54{ 55 Mutex::Autolock _l(mLock); 56 57 sp<CaptureThread> t = mCaptureThread; 58 if (t != 0) { 59 if (enabled) { 60 if (t->exitPending()) { 61 if (t->requestExitAndWait() == WOULD_BLOCK) { 62 LOGE("Visualizer::enable() called from thread"); 63 return INVALID_OPERATION; 64 } 65 } 66 } 67 t->mLock.lock(); 68 } 69 70 status_t status = AudioEffect::setEnabled(enabled); 71 72 if (status == NO_ERROR) { 73 if (t != 0) { 74 if (enabled) { 75 t->run("AudioTrackThread"); 76 } else { 77 t->requestExit(); 78 } 79 } 80 } 81 82 if (t != 0) { 83 t->mLock.unlock(); 84 } 85 86 return status; 87} 88 89status_t Visualizer::setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t flags, uint32_t rate) 90{ 91 if (rate > CAPTURE_RATE_MAX) { 92 return BAD_VALUE; 93 } 94 Mutex::Autolock _l(mLock); 95 96 if (mEnabled) { 97 return INVALID_OPERATION; 98 } 99 100 sp<CaptureThread> t = mCaptureThread; 101 if (t != 0) { 102 t->mLock.lock(); 103 } 104 mCaptureThread.clear(); 105 mCaptureCallBack = cbk; 106 mCaptureCbkUser = user; 107 mCaptureFlags = flags; 108 mCaptureRate = rate; 109 110 if (t != 0) { 111 t->mLock.unlock(); 112 } 113 114 if (cbk != NULL) { 115 mCaptureThread = new CaptureThread(*this, rate, ((flags & CAPTURE_CALL_JAVA) != 0)); 116 if (mCaptureThread == 0) { 117 LOGE("Could not create callback thread"); 118 return NO_INIT; 119 } 120 } 121 LOGV("setCaptureCallBack() rate: %d thread %p flags 0x%08x", 122 rate, mCaptureThread.get(), mCaptureFlags); 123 return NO_ERROR; 124} 125 126status_t Visualizer::setCaptureSize(uint32_t size) 127{ 128 if (size > VISUALIZER_CAPTURE_SIZE_MAX || 129 size < VISUALIZER_CAPTURE_SIZE_MIN || 130 AudioSystem::popCount(size) != 1) { 131 return BAD_VALUE; 132 } 133 134 Mutex::Autolock _l(mLock); 135 if (mEnabled) { 136 return INVALID_OPERATION; 137 } 138 139 uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2]; 140 effect_param_t *p = (effect_param_t *)buf32; 141 142 p->psize = sizeof(uint32_t); 143 p->vsize = sizeof(uint32_t); 144 *(int32_t *)p->data = VISU_PARAM_CAPTURE_SIZE; 145 *((int32_t *)p->data + 1)= size; 146 status_t status = setParameter(p); 147 148 LOGV("setCaptureSize size %d status %d p->status %d", size, status, p->status); 149 150 if (status == NO_ERROR) { 151 status = p->status; 152 } 153 if (status == NO_ERROR) { 154 mCaptureSize = size; 155 } 156 157 return status; 158} 159 160status_t Visualizer::getWaveForm(uint8_t *waveform) 161{ 162 if (waveform == NULL) { 163 return BAD_VALUE; 164 } 165 if (mCaptureSize == 0) { 166 return NO_INIT; 167 } 168 169 status_t status = NO_ERROR; 170 if (mEnabled) { 171 uint32_t replySize = mCaptureSize; 172 status = command(VISU_CMD_CAPTURE, 0, NULL, &replySize, waveform); 173 LOGV("getWaveForm() command returned %d", status); 174 if (replySize == 0) { 175 status = NOT_ENOUGH_DATA; 176 } 177 } else { 178 LOGV("getWaveForm() disabled"); 179 memset(waveform, 0x80, mCaptureSize); 180 } 181 return status; 182} 183 184status_t Visualizer::getFft(uint8_t *fft) 185{ 186 if (fft == NULL) { 187 return BAD_VALUE; 188 } 189 if (mCaptureSize == 0) { 190 return NO_INIT; 191 } 192 193 status_t status = NO_ERROR; 194 if (mEnabled) { 195 uint8_t buf[mCaptureSize]; 196 status = getWaveForm(buf); 197 if (status == NO_ERROR) { 198 status = doFft(fft, buf); 199 } 200 } else { 201 memset(fft, 0, mCaptureSize); 202 } 203 return status; 204} 205 206status_t Visualizer::doFft(uint8_t *fft, uint8_t *waveform) 207{ 208 int32_t workspace[mCaptureSize >> 1]; 209 int32_t nonzero = 0; 210 211 for (uint32_t i = 0; i < mCaptureSize; i += 2) { 212 workspace[i >> 1] = 213 ((waveform[i] ^ 0x80) << 24) | ((waveform[i + 1] ^ 0x80) << 8); 214 nonzero |= workspace[i >> 1]; 215 } 216 217 if (nonzero) { 218 fixed_fft_real(mCaptureSize >> 1, workspace); 219 } 220 221 for (uint32_t i = 0; i < mCaptureSize; i += 2) { 222 short tmp = workspace[i >> 1] >> 21; 223 while (tmp > 127 || tmp < -128) tmp >>= 1; 224 fft[i] = tmp; 225 tmp = workspace[i >> 1]; 226 tmp >>= 5; 227 while (tmp > 127 || tmp < -128) tmp >>= 1; 228 fft[i + 1] = tmp; 229 } 230 231 return NO_ERROR; 232} 233 234void Visualizer::periodicCapture() 235{ 236 Mutex::Autolock _l(mLock); 237 LOGV("periodicCapture() %p mCaptureCallBack %p mCaptureFlags 0x%08x", 238 this, mCaptureCallBack, mCaptureFlags); 239 if (mCaptureCallBack != NULL && 240 (mCaptureFlags & (CAPTURE_WAVEFORM|CAPTURE_FFT)) && 241 mCaptureSize != 0) { 242 uint8_t waveform[mCaptureSize]; 243 status_t status = getWaveForm(waveform); 244 if (status != NO_ERROR) { 245 return; 246 } 247 uint8_t fft[mCaptureSize]; 248 if (mCaptureFlags & CAPTURE_FFT) { 249 status = doFft(fft, waveform); 250 } 251 if (status != NO_ERROR) { 252 return; 253 } 254 uint8_t *wavePtr = NULL; 255 uint8_t *fftPtr = NULL; 256 uint32_t waveSize = 0; 257 uint32_t fftSize = 0; 258 if (mCaptureFlags & CAPTURE_WAVEFORM) { 259 wavePtr = waveform; 260 waveSize = mCaptureSize; 261 } 262 if (mCaptureFlags & CAPTURE_FFT) { 263 fftPtr = fft; 264 fftSize = mCaptureSize; 265 } 266 mCaptureCallBack(mCaptureCbkUser, waveSize, wavePtr, fftSize, fftPtr, mSampleRate); 267 } 268} 269 270uint32_t Visualizer::initCaptureSize() 271{ 272 uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2]; 273 effect_param_t *p = (effect_param_t *)buf32; 274 275 p->psize = sizeof(uint32_t); 276 p->vsize = sizeof(uint32_t); 277 *(int32_t *)p->data = VISU_PARAM_CAPTURE_SIZE; 278 status_t status = getParameter(p); 279 280 if (status == NO_ERROR) { 281 status = p->status; 282 } 283 284 uint32_t size = 0; 285 if (status == NO_ERROR) { 286 size = *((int32_t *)p->data + 1); 287 } 288 mCaptureSize = size; 289 290 LOGV("initCaptureSize size %d status %d", mCaptureSize, status); 291 292 return size; 293} 294 295//------------------------------------------------------------------------- 296 297Visualizer::CaptureThread::CaptureThread(Visualizer& receiver, uint32_t captureRate, bool bCanCallJava) 298 : Thread(bCanCallJava), mReceiver(receiver) 299{ 300 mSleepTimeUs = 1000000000 / captureRate; 301 LOGV("CaptureThread cstor %p captureRate %d mSleepTimeUs %d", this, captureRate, mSleepTimeUs); 302} 303 304bool Visualizer::CaptureThread::threadLoop() 305{ 306 LOGV("CaptureThread %p enter", this); 307 while (!exitPending()) 308 { 309 usleep(mSleepTimeUs); 310 mReceiver.periodicCapture(); 311 } 312 LOGV("CaptureThread %p exiting", this); 313 return false; 314} 315 316status_t Visualizer::CaptureThread::readyToRun() 317{ 318 return NO_ERROR; 319} 320 321void Visualizer::CaptureThread::onFirstRef() 322{ 323} 324 325}; // namespace android 326 327