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