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