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