blob: 43571cfbbf6d72ba2b77a868cd47d20d8df35252 [file] [log] [blame]
Eric Laurentdf9b81c2010-07-02 08:12:41 -07001/*
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
Chia-chi Yeh58d3bd02010-08-19 15:34:10 +080029extern void fixed_fft_real(int n, int32_t *v);
Eric Laurentdf9b81c2010-07-02 08:12:41 -070030
31namespace android {
32
33// ---------------------------------------------------------------------------
34
35Visualizer::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();
Eric Laurentdf9b81c2010-07-02 08:12:41 -070047}
48
49Visualizer::~Visualizer()
50{
Eric Laurentdf9b81c2010-07-02 08:12:41 -070051}
52
53status_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
89status_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
126status_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;
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700155 }
156
157 return status;
158}
159
160status_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) {
Eric Laurenta4c72ac2010-07-28 05:40:18 -0700171 uint32_t replySize = mCaptureSize;
Eric Laurent4d3fb502010-09-24 11:52:04 -0700172 status = command(VISU_CMD_CAPTURE, 0, NULL, &replySize, waveform);
173 LOGV("getWaveForm() command returned %d", status);
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700174 if (replySize == 0) {
175 status = NOT_ENOUGH_DATA;
176 }
177 } else {
Eric Laurent4d3fb502010-09-24 11:52:04 -0700178 LOGV("getWaveForm() disabled");
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700179 memset(waveform, 0x80, mCaptureSize);
180 }
181 return status;
182}
183
184status_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];
Eric Laurent4d3fb502010-09-24 11:52:04 -0700196 status = getWaveForm(buf);
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700197 if (status == NO_ERROR) {
198 status = doFft(fft, buf);
199 }
200 } else {
201 memset(fft, 0, mCaptureSize);
202 }
203 return status;
204}
205
206status_t Visualizer::doFft(uint8_t *fft, uint8_t *waveform)
207{
Chia-chi Yeh58d3bd02010-08-19 15:34:10 +0800208 int32_t workspace[mCaptureSize >> 1];
209 int32_t nonzero = 0;
210
211 for (uint32_t i = 0; i < mCaptureSize; i += 2) {
Chia-chi Yeh67f41772010-11-01 10:56:45 +0800212 workspace[i >> 1] =
213 ((waveform[i] ^ 0x80) << 24) | ((waveform[i + 1] ^ 0x80) << 8);
Chia-chi Yeh58d3bd02010-08-19 15:34:10 +0800214 nonzero |= workspace[i >> 1];
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700215 }
216
Chia-chi Yeh58d3bd02010-08-19 15:34:10 +0800217 if (nonzero) {
218 fixed_fft_real(mCaptureSize >> 1, workspace);
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700219 }
Chia-chi Yeh58d3bd02010-08-19 15:34:10 +0800220
221 for (uint32_t i = 0; i < mCaptureSize; i += 2) {
Marco Nelissendbc0fe92011-01-18 16:44:28 -0800222 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;
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700229 }
Chia-chi Yeh58d3bd02010-08-19 15:34:10 +0800230
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700231 return NO_ERROR;
232}
233
234void 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
270uint32_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
297Visualizer::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
304bool 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
316status_t Visualizer::CaptureThread::readyToRun()
317{
318 return NO_ERROR;
319}
320
321void Visualizer::CaptureThread::onFirstRef()
322{
323}
324
325}; // namespace android
326