• 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 <media/Visualizer.h>
28 
29 extern void fixed_fft_real(int n, int32_t *v);
30 
31 namespace android {
32 
33 // ---------------------------------------------------------------------------
34 
Visualizer(int32_t priority,effect_callback_t cbf,void * user,int sessionId)35 Visualizer::Visualizer (int32_t priority,
36          effect_callback_t cbf,
37          void* user,
38          int sessionId)
39     :   AudioEffect(SL_IID_VISUALIZATION, NULL, priority, cbf, user, sessionId),
40         mCaptureRate(CAPTURE_RATE_DEF),
41         mCaptureSize(CAPTURE_SIZE_DEF),
42         mSampleRate(44100000),
43         mCaptureCallBack(NULL),
44         mCaptureCbkUser(NULL)
45 {
46     initCaptureSize();
47 }
48 
~Visualizer()49 Visualizer::~Visualizer()
50 {
51 }
52 
setEnabled(bool enabled)53 status_t Visualizer::setEnabled(bool enabled)
54 {
55     Mutex::Autolock _l(mLock);
56 
57     sp<CaptureThread> t = mCaptureThread;
58     if (t != 0) {
59         if (enabled) {
60             if (t->exitPending()) {
61                 if (t->requestExitAndWait() == WOULD_BLOCK) {
62                     LOGE("Visualizer::enable() called from thread");
63                     return INVALID_OPERATION;
64                 }
65             }
66         }
67         t->mLock.lock();
68      }
69 
70     status_t status = AudioEffect::setEnabled(enabled);
71 
72     if (status == NO_ERROR) {
73         if (t != 0) {
74             if (enabled) {
75                 t->run("AudioTrackThread");
76             } else {
77                 t->requestExit();
78             }
79         }
80     }
81 
82     if (t != 0) {
83         t->mLock.unlock();
84     }
85 
86     return status;
87 }
88 
setCaptureCallBack(capture_cbk_t cbk,void * user,uint32_t flags,uint32_t rate)89 status_t Visualizer::setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t flags, uint32_t rate)
90 {
91     if (rate > CAPTURE_RATE_MAX) {
92         return BAD_VALUE;
93     }
94     Mutex::Autolock _l(mLock);
95 
96     if (mEnabled) {
97         return INVALID_OPERATION;
98     }
99 
100     sp<CaptureThread> t = mCaptureThread;
101     if (t != 0) {
102         t->mLock.lock();
103     }
104     mCaptureThread.clear();
105     mCaptureCallBack = cbk;
106     mCaptureCbkUser = user;
107     mCaptureFlags = flags;
108     mCaptureRate = rate;
109 
110     if (t != 0) {
111         t->mLock.unlock();
112     }
113 
114     if (cbk != NULL) {
115         mCaptureThread = new CaptureThread(*this, rate, ((flags & CAPTURE_CALL_JAVA) != 0));
116         if (mCaptureThread == 0) {
117             LOGE("Could not create callback thread");
118             return NO_INIT;
119         }
120     }
121     LOGV("setCaptureCallBack() rate: %d thread %p flags 0x%08x",
122             rate, mCaptureThread.get(), mCaptureFlags);
123     return NO_ERROR;
124 }
125 
setCaptureSize(uint32_t size)126 status_t Visualizer::setCaptureSize(uint32_t size)
127 {
128     if (size > VISUALIZER_CAPTURE_SIZE_MAX ||
129         size < VISUALIZER_CAPTURE_SIZE_MIN ||
130         AudioSystem::popCount(size) != 1) {
131         return BAD_VALUE;
132     }
133 
134     Mutex::Autolock _l(mLock);
135     if (mEnabled) {
136         return INVALID_OPERATION;
137     }
138 
139     uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
140     effect_param_t *p = (effect_param_t *)buf32;
141 
142     p->psize = sizeof(uint32_t);
143     p->vsize = sizeof(uint32_t);
144     *(int32_t *)p->data = VISU_PARAM_CAPTURE_SIZE;
145     *((int32_t *)p->data + 1)= size;
146     status_t status = setParameter(p);
147 
148     LOGV("setCaptureSize size %d  status %d p->status %d", size, status, p->status);
149 
150     if (status == NO_ERROR) {
151         status = p->status;
152     }
153     if (status == NO_ERROR) {
154         mCaptureSize = size;
155     }
156 
157     return status;
158 }
159 
getWaveForm(uint8_t * waveform)160 status_t Visualizer::getWaveForm(uint8_t *waveform)
161 {
162     if (waveform == NULL) {
163         return BAD_VALUE;
164     }
165     if (mCaptureSize == 0) {
166         return NO_INIT;
167     }
168 
169     status_t status = NO_ERROR;
170     if (mEnabled) {
171         uint32_t replySize = mCaptureSize;
172         status = command(VISU_CMD_CAPTURE, 0, NULL, &replySize, waveform);
173         LOGV("getWaveForm() command returned %d", status);
174         if (replySize == 0) {
175             status = NOT_ENOUGH_DATA;
176         }
177     } else {
178         LOGV("getWaveForm() disabled");
179         memset(waveform, 0x80, mCaptureSize);
180     }
181     return status;
182 }
183 
getFft(uint8_t * fft)184 status_t Visualizer::getFft(uint8_t *fft)
185 {
186     if (fft == NULL) {
187         return BAD_VALUE;
188     }
189     if (mCaptureSize == 0) {
190         return NO_INIT;
191     }
192 
193     status_t status = NO_ERROR;
194     if (mEnabled) {
195         uint8_t buf[mCaptureSize];
196         status = getWaveForm(buf);
197         if (status == NO_ERROR) {
198             status = doFft(fft, buf);
199         }
200     } else {
201         memset(fft, 0, mCaptureSize);
202     }
203     return status;
204 }
205 
doFft(uint8_t * fft,uint8_t * waveform)206 status_t Visualizer::doFft(uint8_t *fft, uint8_t *waveform)
207 {
208     int32_t workspace[mCaptureSize >> 1];
209     int32_t nonzero = 0;
210 
211     for (uint32_t i = 0; i < mCaptureSize; i += 2) {
212         workspace[i >> 1] =
213                 ((waveform[i] ^ 0x80) << 24) | ((waveform[i + 1] ^ 0x80) << 8);
214         nonzero |= workspace[i >> 1];
215     }
216 
217     if (nonzero) {
218         fixed_fft_real(mCaptureSize >> 1, workspace);
219     }
220 
221     for (uint32_t i = 0; i < mCaptureSize; i += 2) {
222         short tmp = workspace[i >> 1] >> 21;
223         while (tmp > 127 || tmp < -128) tmp >>= 1;
224         fft[i] = tmp;
225         tmp = workspace[i >> 1];
226         tmp >>= 5;
227         while (tmp > 127 || tmp < -128) tmp >>= 1;
228         fft[i + 1] = tmp;
229     }
230 
231     return NO_ERROR;
232 }
233 
periodicCapture()234 void Visualizer::periodicCapture()
235 {
236     Mutex::Autolock _l(mLock);
237     LOGV("periodicCapture() %p mCaptureCallBack %p mCaptureFlags 0x%08x",
238             this, mCaptureCallBack, mCaptureFlags);
239     if (mCaptureCallBack != NULL &&
240         (mCaptureFlags & (CAPTURE_WAVEFORM|CAPTURE_FFT)) &&
241         mCaptureSize != 0) {
242         uint8_t waveform[mCaptureSize];
243         status_t status = getWaveForm(waveform);
244         if (status != NO_ERROR) {
245             return;
246         }
247         uint8_t fft[mCaptureSize];
248         if (mCaptureFlags & CAPTURE_FFT) {
249             status = doFft(fft, waveform);
250         }
251         if (status != NO_ERROR) {
252             return;
253         }
254         uint8_t *wavePtr = NULL;
255         uint8_t *fftPtr = NULL;
256         uint32_t waveSize = 0;
257         uint32_t fftSize = 0;
258         if (mCaptureFlags & CAPTURE_WAVEFORM) {
259             wavePtr = waveform;
260             waveSize = mCaptureSize;
261         }
262         if (mCaptureFlags & CAPTURE_FFT) {
263             fftPtr = fft;
264             fftSize = mCaptureSize;
265         }
266         mCaptureCallBack(mCaptureCbkUser, waveSize, wavePtr, fftSize, fftPtr, mSampleRate);
267     }
268 }
269 
initCaptureSize()270 uint32_t Visualizer::initCaptureSize()
271 {
272     uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
273     effect_param_t *p = (effect_param_t *)buf32;
274 
275     p->psize = sizeof(uint32_t);
276     p->vsize = sizeof(uint32_t);
277     *(int32_t *)p->data = VISU_PARAM_CAPTURE_SIZE;
278     status_t status = getParameter(p);
279 
280     if (status == NO_ERROR) {
281         status = p->status;
282     }
283 
284     uint32_t size = 0;
285     if (status == NO_ERROR) {
286         size = *((int32_t *)p->data + 1);
287     }
288     mCaptureSize = size;
289 
290     LOGV("initCaptureSize size %d status %d", mCaptureSize, status);
291 
292     return size;
293 }
294 
295 //-------------------------------------------------------------------------
296 
CaptureThread(Visualizer & receiver,uint32_t captureRate,bool bCanCallJava)297 Visualizer::CaptureThread::CaptureThread(Visualizer& receiver, uint32_t captureRate, bool bCanCallJava)
298     : Thread(bCanCallJava), mReceiver(receiver)
299 {
300     mSleepTimeUs = 1000000000 / captureRate;
301     LOGV("CaptureThread cstor %p captureRate %d mSleepTimeUs %d", this, captureRate, mSleepTimeUs);
302 }
303 
threadLoop()304 bool Visualizer::CaptureThread::threadLoop()
305 {
306     LOGV("CaptureThread %p enter", this);
307     while (!exitPending())
308     {
309         usleep(mSleepTimeUs);
310         mReceiver.periodicCapture();
311     }
312     LOGV("CaptureThread %p exiting", this);
313     return false;
314 }
315 
readyToRun()316 status_t Visualizer::CaptureThread::readyToRun()
317 {
318     return NO_ERROR;
319 }
320 
onFirstRef()321 void Visualizer::CaptureThread::onFirstRef()
322 {
323 }
324 
325 }; // namespace android
326 
327