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