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