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