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