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