blob: f91e3e4f1e042b0982ff728910f27262bd0c26fb [file] [log] [blame]
Eric Laurentda7581b2010-07-02 08:12:41 -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
Dima Zavinfce7a472011-04-19 22:30:36 -070027#include <cutils/bitops.h>
28
Eric Laurentda7581b2010-07-02 08:12:41 -070029#include <media/Visualizer.h>
Glenn Kasten3f6448e2012-01-16 13:11:50 -080030#include <audio_utils/fixedfft.h>
Glenn Kasten1ab85ec2013-05-31 09:18:43 -070031#include <utils/Thread.h>
Eric Laurentda7581b2010-07-02 08:12:41 -070032
33namespace android {
34
35// ---------------------------------------------------------------------------
36
37Visualizer::Visualizer (int32_t priority,
38 effect_callback_t cbf,
39 void* user,
40 int sessionId)
41 : AudioEffect(SL_IID_VISUALIZATION, NULL, priority, cbf, user, sessionId),
42 mCaptureRate(CAPTURE_RATE_DEF),
43 mCaptureSize(CAPTURE_SIZE_DEF),
44 mSampleRate(44100000),
Jean-Michel Trivi3476de62012-04-15 17:15:07 -070045 mScalingMode(VISUALIZER_SCALING_MODE_NORMALIZED),
Jean-Michel Trivi09647d22013-09-20 11:58:40 -070046 mMeasurementMode(MEASUREMENT_MODE_NONE),
Eric Laurentda7581b2010-07-02 08:12:41 -070047 mCaptureCallBack(NULL),
48 mCaptureCbkUser(NULL)
49{
50 initCaptureSize();
Eric Laurentda7581b2010-07-02 08:12:41 -070051}
52
53Visualizer::~Visualizer()
54{
Haynes Mathew George63f6ffb2014-09-25 10:33:12 -070055 ALOGV("Visualizer::~Visualizer()");
56 if (mCaptureThread != NULL) {
57 mCaptureThread->requestExitAndWait();
58 mCaptureThread.clear();
59 }
60 mCaptureCallBack = NULL;
61 mCaptureFlags = 0;
Eric Laurentda7581b2010-07-02 08:12:41 -070062}
63
64status_t Visualizer::setEnabled(bool enabled)
65{
Glenn Kastena9b21c52012-01-17 10:06:38 -080066 Mutex::Autolock _l(mCaptureLock);
Eric Laurentda7581b2010-07-02 08:12:41 -070067
68 sp<CaptureThread> t = mCaptureThread;
69 if (t != 0) {
70 if (enabled) {
71 if (t->exitPending()) {
72 if (t->requestExitAndWait() == WOULD_BLOCK) {
Steve Block29357bc2012-01-06 19:20:56 +000073 ALOGE("Visualizer::enable() called from thread");
Eric Laurentda7581b2010-07-02 08:12:41 -070074 return INVALID_OPERATION;
75 }
76 }
77 }
78 t->mLock.lock();
Glenn Kastene53b9ea2012-03-12 16:29:55 -070079 }
Eric Laurentda7581b2010-07-02 08:12:41 -070080
81 status_t status = AudioEffect::setEnabled(enabled);
82
83 if (status == NO_ERROR) {
84 if (t != 0) {
85 if (enabled) {
Glenn Kasten9096f342012-01-19 08:14:08 -080086 t->run("Visualizer");
Eric Laurentda7581b2010-07-02 08:12:41 -070087 } else {
88 t->requestExit();
89 }
90 }
91 }
92
93 if (t != 0) {
94 t->mLock.unlock();
95 }
96
97 return status;
98}
99
Glenn Kasten85ab62c2012-11-01 11:11:38 -0700100status_t Visualizer::setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t flags,
101 uint32_t rate)
Eric Laurentda7581b2010-07-02 08:12:41 -0700102{
103 if (rate > CAPTURE_RATE_MAX) {
104 return BAD_VALUE;
105 }
Glenn Kastena9b21c52012-01-17 10:06:38 -0800106 Mutex::Autolock _l(mCaptureLock);
Eric Laurentda7581b2010-07-02 08:12:41 -0700107
108 if (mEnabled) {
109 return INVALID_OPERATION;
110 }
111
Haynes Mathew George63f6ffb2014-09-25 10:33:12 -0700112 if (mCaptureThread != 0) {
113 mCaptureLock.unlock();
114 mCaptureThread->requestExitAndWait();
115 mCaptureLock.lock();
Eric Laurentda7581b2010-07-02 08:12:41 -0700116 }
Haynes Mathew George63f6ffb2014-09-25 10:33:12 -0700117
Eric Laurentda7581b2010-07-02 08:12:41 -0700118 mCaptureThread.clear();
119 mCaptureCallBack = cbk;
120 mCaptureCbkUser = user;
121 mCaptureFlags = flags;
122 mCaptureRate = rate;
123
Eric Laurentda7581b2010-07-02 08:12:41 -0700124 if (cbk != NULL) {
125 mCaptureThread = new CaptureThread(*this, rate, ((flags & CAPTURE_CALL_JAVA) != 0));
Eric Laurentda7581b2010-07-02 08:12:41 -0700126 }
Steve Block3856b092011-10-20 11:56:00 +0100127 ALOGV("setCaptureCallBack() rate: %d thread %p flags 0x%08x",
Eric Laurentda7581b2010-07-02 08:12:41 -0700128 rate, mCaptureThread.get(), mCaptureFlags);
129 return NO_ERROR;
130}
131
132status_t Visualizer::setCaptureSize(uint32_t size)
133{
134 if (size > VISUALIZER_CAPTURE_SIZE_MAX ||
135 size < VISUALIZER_CAPTURE_SIZE_MIN ||
Dima Zavinfce7a472011-04-19 22:30:36 -0700136 popcount(size) != 1) {
Eric Laurentda7581b2010-07-02 08:12:41 -0700137 return BAD_VALUE;
138 }
139
Glenn Kastena9b21c52012-01-17 10:06:38 -0800140 Mutex::Autolock _l(mCaptureLock);
Eric Laurentda7581b2010-07-02 08:12:41 -0700141 if (mEnabled) {
142 return INVALID_OPERATION;
143 }
144
145 uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
146 effect_param_t *p = (effect_param_t *)buf32;
147
148 p->psize = sizeof(uint32_t);
149 p->vsize = sizeof(uint32_t);
Eric Laurent6d8b6942011-06-24 07:01:31 -0700150 *(int32_t *)p->data = VISUALIZER_PARAM_CAPTURE_SIZE;
Eric Laurentda7581b2010-07-02 08:12:41 -0700151 *((int32_t *)p->data + 1)= size;
152 status_t status = setParameter(p);
153
Steve Block3856b092011-10-20 11:56:00 +0100154 ALOGV("setCaptureSize size %d status %d p->status %d", size, status, p->status);
Eric Laurentda7581b2010-07-02 08:12:41 -0700155
156 if (status == NO_ERROR) {
157 status = p->status;
Jean-Michel Trivi3476de62012-04-15 17:15:07 -0700158 if (status == NO_ERROR) {
159 mCaptureSize = size;
160 }
Eric Laurentda7581b2010-07-02 08:12:41 -0700161 }
Jean-Michel Trivi3476de62012-04-15 17:15:07 -0700162
163 return status;
164}
165
166status_t Visualizer::setScalingMode(uint32_t mode) {
167 if ((mode != VISUALIZER_SCALING_MODE_NORMALIZED)
168 && (mode != VISUALIZER_SCALING_MODE_AS_PLAYED)) {
169 return BAD_VALUE;
170 }
171
172 Mutex::Autolock _l(mCaptureLock);
173
174 uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
175 effect_param_t *p = (effect_param_t *)buf32;
176
177 p->psize = sizeof(uint32_t);
178 p->vsize = sizeof(uint32_t);
179 *(int32_t *)p->data = VISUALIZER_PARAM_SCALING_MODE;
180 *((int32_t *)p->data + 1)= mode;
181 status_t status = setParameter(p);
182
183 ALOGV("setScalingMode mode %d status %d p->status %d", mode, status, p->status);
184
Eric Laurentda7581b2010-07-02 08:12:41 -0700185 if (status == NO_ERROR) {
Jean-Michel Trivi3476de62012-04-15 17:15:07 -0700186 status = p->status;
187 if (status == NO_ERROR) {
188 mScalingMode = mode;
189 }
Eric Laurentda7581b2010-07-02 08:12:41 -0700190 }
191
192 return status;
193}
194
Jean-Michel Trivi09647d22013-09-20 11:58:40 -0700195status_t Visualizer::setMeasurementMode(uint32_t mode) {
196 if ((mode != MEASUREMENT_MODE_NONE)
197 //Note: needs to be handled as a mask when more measurement modes are added
198 && ((mode & MEASUREMENT_MODE_PEAK_RMS) != mode)) {
199 return BAD_VALUE;
200 }
201
202 Mutex::Autolock _l(mCaptureLock);
203
204 uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
205 effect_param_t *p = (effect_param_t *)buf32;
206
207 p->psize = sizeof(uint32_t);
208 p->vsize = sizeof(uint32_t);
209 *(int32_t *)p->data = VISUALIZER_PARAM_MEASUREMENT_MODE;
210 *((int32_t *)p->data + 1)= mode;
211 status_t status = setParameter(p);
212
213 ALOGV("setMeasurementMode mode %d status %d p->status %d", mode, status, p->status);
214
215 if (status == NO_ERROR) {
216 status = p->status;
217 if (status == NO_ERROR) {
218 mMeasurementMode = mode;
219 }
220 }
221 return status;
222}
223
224status_t Visualizer::getIntMeasurements(uint32_t type, uint32_t number, int32_t *measurements) {
225 if (mMeasurementMode == MEASUREMENT_MODE_NONE) {
226 ALOGE("Cannot retrieve int measurements, no measurement mode set");
227 return INVALID_OPERATION;
228 }
229 if (!(mMeasurementMode & type)) {
230 // measurement type has not been set on this Visualizer
231 ALOGE("Cannot retrieve int measurements, requested measurement mode 0x%x not set(0x%x)",
232 type, mMeasurementMode);
233 return INVALID_OPERATION;
234 }
235 // only peak+RMS measurement supported
236 if ((type != MEASUREMENT_MODE_PEAK_RMS)
237 // for peak+RMS measurement, the results are 2 int32_t values
238 || (number != 2)) {
239 ALOGE("Cannot retrieve int measurements, MEASUREMENT_MODE_PEAK_RMS returns 2 ints, not %d",
240 number);
241 return BAD_VALUE;
242 }
243
244 status_t status = NO_ERROR;
245 if (mEnabled) {
246 uint32_t replySize = number * sizeof(int32_t);
247 status = command(VISUALIZER_CMD_MEASURE,
248 sizeof(uint32_t) /*cmdSize*/,
249 &type /*cmdData*/,
250 &replySize, measurements);
251 ALOGV("getMeasurements() command returned %d", status);
252 if ((status == NO_ERROR) && (replySize == 0)) {
253 status = NOT_ENOUGH_DATA;
254 }
255 } else {
256 ALOGV("getMeasurements() disabled");
257 return INVALID_OPERATION;
258 }
259 return status;
260}
261
Eric Laurentda7581b2010-07-02 08:12:41 -0700262status_t Visualizer::getWaveForm(uint8_t *waveform)
263{
264 if (waveform == NULL) {
265 return BAD_VALUE;
266 }
267 if (mCaptureSize == 0) {
268 return NO_INIT;
269 }
270
271 status_t status = NO_ERROR;
272 if (mEnabled) {
Eric Laurent25f43952010-07-28 05:40:18 -0700273 uint32_t replySize = mCaptureSize;
Eric Laurent6d8b6942011-06-24 07:01:31 -0700274 status = command(VISUALIZER_CMD_CAPTURE, 0, NULL, &replySize, waveform);
Steve Block3856b092011-10-20 11:56:00 +0100275 ALOGV("getWaveForm() command returned %d", status);
John Grossmanaf7d8182012-01-11 12:23:42 -0800276 if ((status == NO_ERROR) && (replySize == 0)) {
Eric Laurentda7581b2010-07-02 08:12:41 -0700277 status = NOT_ENOUGH_DATA;
278 }
279 } else {
Steve Block3856b092011-10-20 11:56:00 +0100280 ALOGV("getWaveForm() disabled");
Eric Laurentda7581b2010-07-02 08:12:41 -0700281 memset(waveform, 0x80, mCaptureSize);
282 }
283 return status;
284}
285
286status_t Visualizer::getFft(uint8_t *fft)
287{
288 if (fft == NULL) {
289 return BAD_VALUE;
290 }
291 if (mCaptureSize == 0) {
292 return NO_INIT;
293 }
294
295 status_t status = NO_ERROR;
296 if (mEnabled) {
297 uint8_t buf[mCaptureSize];
Eric Laurent0fa449c2010-09-24 11:52:04 -0700298 status = getWaveForm(buf);
Eric Laurentda7581b2010-07-02 08:12:41 -0700299 if (status == NO_ERROR) {
300 status = doFft(fft, buf);
301 }
302 } else {
303 memset(fft, 0, mCaptureSize);
304 }
305 return status;
306}
307
308status_t Visualizer::doFft(uint8_t *fft, uint8_t *waveform)
309{
Chia-chi Yehdbd2b7e2010-08-19 15:34:10 +0800310 int32_t workspace[mCaptureSize >> 1];
311 int32_t nonzero = 0;
312
313 for (uint32_t i = 0; i < mCaptureSize; i += 2) {
Chia-chi Yeh6b6a7362010-11-01 10:56:45 +0800314 workspace[i >> 1] =
315 ((waveform[i] ^ 0x80) << 24) | ((waveform[i + 1] ^ 0x80) << 8);
Chia-chi Yehdbd2b7e2010-08-19 15:34:10 +0800316 nonzero |= workspace[i >> 1];
Eric Laurentda7581b2010-07-02 08:12:41 -0700317 }
318
Chia-chi Yehdbd2b7e2010-08-19 15:34:10 +0800319 if (nonzero) {
320 fixed_fft_real(mCaptureSize >> 1, workspace);
Eric Laurentda7581b2010-07-02 08:12:41 -0700321 }
Chia-chi Yehdbd2b7e2010-08-19 15:34:10 +0800322
323 for (uint32_t i = 0; i < mCaptureSize; i += 2) {
Marco Nelissen209821c2011-01-18 16:44:28 -0800324 short tmp = workspace[i >> 1] >> 21;
325 while (tmp > 127 || tmp < -128) tmp >>= 1;
326 fft[i] = tmp;
327 tmp = workspace[i >> 1];
328 tmp >>= 5;
329 while (tmp > 127 || tmp < -128) tmp >>= 1;
330 fft[i + 1] = tmp;
Eric Laurentda7581b2010-07-02 08:12:41 -0700331 }
Chia-chi Yehdbd2b7e2010-08-19 15:34:10 +0800332
Eric Laurentda7581b2010-07-02 08:12:41 -0700333 return NO_ERROR;
334}
335
336void Visualizer::periodicCapture()
337{
Glenn Kastena9b21c52012-01-17 10:06:38 -0800338 Mutex::Autolock _l(mCaptureLock);
Steve Block3856b092011-10-20 11:56:00 +0100339 ALOGV("periodicCapture() %p mCaptureCallBack %p mCaptureFlags 0x%08x",
Eric Laurentda7581b2010-07-02 08:12:41 -0700340 this, mCaptureCallBack, mCaptureFlags);
341 if (mCaptureCallBack != NULL &&
342 (mCaptureFlags & (CAPTURE_WAVEFORM|CAPTURE_FFT)) &&
343 mCaptureSize != 0) {
344 uint8_t waveform[mCaptureSize];
345 status_t status = getWaveForm(waveform);
346 if (status != NO_ERROR) {
347 return;
348 }
349 uint8_t fft[mCaptureSize];
350 if (mCaptureFlags & CAPTURE_FFT) {
351 status = doFft(fft, waveform);
352 }
353 if (status != NO_ERROR) {
354 return;
355 }
356 uint8_t *wavePtr = NULL;
357 uint8_t *fftPtr = NULL;
358 uint32_t waveSize = 0;
359 uint32_t fftSize = 0;
360 if (mCaptureFlags & CAPTURE_WAVEFORM) {
361 wavePtr = waveform;
362 waveSize = mCaptureSize;
363 }
364 if (mCaptureFlags & CAPTURE_FFT) {
365 fftPtr = fft;
366 fftSize = mCaptureSize;
367 }
368 mCaptureCallBack(mCaptureCbkUser, waveSize, wavePtr, fftSize, fftPtr, mSampleRate);
369 }
370}
371
372uint32_t Visualizer::initCaptureSize()
373{
374 uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
375 effect_param_t *p = (effect_param_t *)buf32;
376
377 p->psize = sizeof(uint32_t);
378 p->vsize = sizeof(uint32_t);
Eric Laurent6d8b6942011-06-24 07:01:31 -0700379 *(int32_t *)p->data = VISUALIZER_PARAM_CAPTURE_SIZE;
Eric Laurentda7581b2010-07-02 08:12:41 -0700380 status_t status = getParameter(p);
381
382 if (status == NO_ERROR) {
383 status = p->status;
384 }
385
386 uint32_t size = 0;
387 if (status == NO_ERROR) {
388 size = *((int32_t *)p->data + 1);
389 }
390 mCaptureSize = size;
391
Steve Block3856b092011-10-20 11:56:00 +0100392 ALOGV("initCaptureSize size %d status %d", mCaptureSize, status);
Eric Laurentda7581b2010-07-02 08:12:41 -0700393
394 return size;
395}
396
Jean-Michel Trivi3476de62012-04-15 17:15:07 -0700397void Visualizer::controlStatusChanged(bool controlGranted) {
398 if (controlGranted) {
399 // this Visualizer instance regained control of the effect, reset the scaling mode
400 // and capture size as has been cached through it.
401 ALOGV("controlStatusChanged(true) causes effect parameter reset:");
402 ALOGV(" scaling mode reset to %d", mScalingMode);
403 setScalingMode(mScalingMode);
404 ALOGV(" capture size reset to %d", mCaptureSize);
405 setCaptureSize(mCaptureSize);
406 }
407 AudioEffect::controlStatusChanged(controlGranted);
408}
409
Eric Laurentda7581b2010-07-02 08:12:41 -0700410//-------------------------------------------------------------------------
411
Glenn Kasten85ab62c2012-11-01 11:11:38 -0700412Visualizer::CaptureThread::CaptureThread(Visualizer& receiver, uint32_t captureRate,
413 bool bCanCallJava)
Eric Laurentda7581b2010-07-02 08:12:41 -0700414 : Thread(bCanCallJava), mReceiver(receiver)
415{
416 mSleepTimeUs = 1000000000 / captureRate;
Steve Block3856b092011-10-20 11:56:00 +0100417 ALOGV("CaptureThread cstor %p captureRate %d mSleepTimeUs %d", this, captureRate, mSleepTimeUs);
Eric Laurentda7581b2010-07-02 08:12:41 -0700418}
419
420bool Visualizer::CaptureThread::threadLoop()
421{
Steve Block3856b092011-10-20 11:56:00 +0100422 ALOGV("CaptureThread %p enter", this);
Eric Laurentda7581b2010-07-02 08:12:41 -0700423 while (!exitPending())
424 {
425 usleep(mSleepTimeUs);
426 mReceiver.periodicCapture();
427 }
Steve Block3856b092011-10-20 11:56:00 +0100428 ALOGV("CaptureThread %p exiting", this);
Eric Laurentda7581b2010-07-02 08:12:41 -0700429 return false;
430}
431
Eric Laurentda7581b2010-07-02 08:12:41 -0700432}; // namespace android