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