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