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