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