xref: /aosp_15_r20/frameworks/base/media/jni/audioeffect/Visualizer.cpp (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
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