blob: 66758d24ba3b48c3c6346926386fef6cbd60a687 [file] [log] [blame]
Eric Laurentda7581b2010-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
Dima Zavinfce7a472011-04-19 22:30:36 -070027#include <cutils/bitops.h>
28
Eric Laurentda7581b2010-07-02 08:12:41 -070029#include <media/Visualizer.h>
30
Chia-chi Yehdbd2b7e2010-08-19 15:34:10 +080031extern void fixed_fft_real(int n, int32_t *v);
Eric Laurentda7581b2010-07-02 08:12:41 -070032
33namespace android {
34
35// ---------------------------------------------------------------------------
36
37Visualizer::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 mCaptureCallBack(NULL),
46 mCaptureCbkUser(NULL)
47{
48 initCaptureSize();
Eric Laurentda7581b2010-07-02 08:12:41 -070049}
50
51Visualizer::~Visualizer()
52{
Eric Laurentda7581b2010-07-02 08:12:41 -070053}
54
55status_t Visualizer::setEnabled(bool enabled)
56{
57 Mutex::Autolock _l(mLock);
58
59 sp<CaptureThread> t = mCaptureThread;
60 if (t != 0) {
61 if (enabled) {
62 if (t->exitPending()) {
63 if (t->requestExitAndWait() == WOULD_BLOCK) {
Steve Block29357bc2012-01-06 19:20:56 +000064 ALOGE("Visualizer::enable() called from thread");
Eric Laurentda7581b2010-07-02 08:12:41 -070065 return INVALID_OPERATION;
66 }
67 }
68 }
69 t->mLock.lock();
70 }
71
72 status_t status = AudioEffect::setEnabled(enabled);
73
74 if (status == NO_ERROR) {
75 if (t != 0) {
76 if (enabled) {
77 t->run("AudioTrackThread");
78 } else {
79 t->requestExit();
80 }
81 }
82 }
83
84 if (t != 0) {
85 t->mLock.unlock();
86 }
87
88 return status;
89}
90
91status_t Visualizer::setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t flags, uint32_t rate)
92{
93 if (rate > CAPTURE_RATE_MAX) {
94 return BAD_VALUE;
95 }
96 Mutex::Autolock _l(mLock);
97
98 if (mEnabled) {
99 return INVALID_OPERATION;
100 }
101
102 sp<CaptureThread> t = mCaptureThread;
103 if (t != 0) {
104 t->mLock.lock();
105 }
106 mCaptureThread.clear();
107 mCaptureCallBack = cbk;
108 mCaptureCbkUser = user;
109 mCaptureFlags = flags;
110 mCaptureRate = rate;
111
112 if (t != 0) {
113 t->mLock.unlock();
114 }
115
116 if (cbk != NULL) {
117 mCaptureThread = new CaptureThread(*this, rate, ((flags & CAPTURE_CALL_JAVA) != 0));
Eric Laurentda7581b2010-07-02 08:12:41 -0700118 }
Steve Block3856b092011-10-20 11:56:00 +0100119 ALOGV("setCaptureCallBack() rate: %d thread %p flags 0x%08x",
Eric Laurentda7581b2010-07-02 08:12:41 -0700120 rate, mCaptureThread.get(), mCaptureFlags);
121 return NO_ERROR;
122}
123
124status_t Visualizer::setCaptureSize(uint32_t size)
125{
126 if (size > VISUALIZER_CAPTURE_SIZE_MAX ||
127 size < VISUALIZER_CAPTURE_SIZE_MIN ||
Dima Zavinfce7a472011-04-19 22:30:36 -0700128 popcount(size) != 1) {
Eric Laurentda7581b2010-07-02 08:12:41 -0700129 return BAD_VALUE;
130 }
131
132 Mutex::Autolock _l(mLock);
133 if (mEnabled) {
134 return INVALID_OPERATION;
135 }
136
137 uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
138 effect_param_t *p = (effect_param_t *)buf32;
139
140 p->psize = sizeof(uint32_t);
141 p->vsize = sizeof(uint32_t);
Eric Laurent6d8b6942011-06-24 07:01:31 -0700142 *(int32_t *)p->data = VISUALIZER_PARAM_CAPTURE_SIZE;
Eric Laurentda7581b2010-07-02 08:12:41 -0700143 *((int32_t *)p->data + 1)= size;
144 status_t status = setParameter(p);
145
Steve Block3856b092011-10-20 11:56:00 +0100146 ALOGV("setCaptureSize size %d status %d p->status %d", size, status, p->status);
Eric Laurentda7581b2010-07-02 08:12:41 -0700147
148 if (status == NO_ERROR) {
149 status = p->status;
150 }
151 if (status == NO_ERROR) {
152 mCaptureSize = size;
Eric Laurentda7581b2010-07-02 08:12:41 -0700153 }
154
155 return status;
156}
157
158status_t Visualizer::getWaveForm(uint8_t *waveform)
159{
160 if (waveform == NULL) {
161 return BAD_VALUE;
162 }
163 if (mCaptureSize == 0) {
164 return NO_INIT;
165 }
166
167 status_t status = NO_ERROR;
168 if (mEnabled) {
Eric Laurent25f43952010-07-28 05:40:18 -0700169 uint32_t replySize = mCaptureSize;
Eric Laurent6d8b6942011-06-24 07:01:31 -0700170 status = command(VISUALIZER_CMD_CAPTURE, 0, NULL, &replySize, waveform);
Steve Block3856b092011-10-20 11:56:00 +0100171 ALOGV("getWaveForm() command returned %d", status);
Eric Laurentda7581b2010-07-02 08:12:41 -0700172 if (replySize == 0) {
173 status = NOT_ENOUGH_DATA;
174 }
175 } else {
Steve Block3856b092011-10-20 11:56:00 +0100176 ALOGV("getWaveForm() disabled");
Eric Laurentda7581b2010-07-02 08:12:41 -0700177 memset(waveform, 0x80, mCaptureSize);
178 }
179 return status;
180}
181
182status_t Visualizer::getFft(uint8_t *fft)
183{
184 if (fft == NULL) {
185 return BAD_VALUE;
186 }
187 if (mCaptureSize == 0) {
188 return NO_INIT;
189 }
190
191 status_t status = NO_ERROR;
192 if (mEnabled) {
193 uint8_t buf[mCaptureSize];
Eric Laurent0fa449c2010-09-24 11:52:04 -0700194 status = getWaveForm(buf);
Eric Laurentda7581b2010-07-02 08:12:41 -0700195 if (status == NO_ERROR) {
196 status = doFft(fft, buf);
197 }
198 } else {
199 memset(fft, 0, mCaptureSize);
200 }
201 return status;
202}
203
204status_t Visualizer::doFft(uint8_t *fft, uint8_t *waveform)
205{
Chia-chi Yehdbd2b7e2010-08-19 15:34:10 +0800206 int32_t workspace[mCaptureSize >> 1];
207 int32_t nonzero = 0;
208
209 for (uint32_t i = 0; i < mCaptureSize; i += 2) {
Chia-chi Yeh6b6a7362010-11-01 10:56:45 +0800210 workspace[i >> 1] =
211 ((waveform[i] ^ 0x80) << 24) | ((waveform[i + 1] ^ 0x80) << 8);
Chia-chi Yehdbd2b7e2010-08-19 15:34:10 +0800212 nonzero |= workspace[i >> 1];
Eric Laurentda7581b2010-07-02 08:12:41 -0700213 }
214
Chia-chi Yehdbd2b7e2010-08-19 15:34:10 +0800215 if (nonzero) {
216 fixed_fft_real(mCaptureSize >> 1, workspace);
Eric Laurentda7581b2010-07-02 08:12:41 -0700217 }
Chia-chi Yehdbd2b7e2010-08-19 15:34:10 +0800218
219 for (uint32_t i = 0; i < mCaptureSize; i += 2) {
Marco Nelissen209821c2011-01-18 16:44:28 -0800220 short tmp = workspace[i >> 1] >> 21;
221 while (tmp > 127 || tmp < -128) tmp >>= 1;
222 fft[i] = tmp;
223 tmp = workspace[i >> 1];
224 tmp >>= 5;
225 while (tmp > 127 || tmp < -128) tmp >>= 1;
226 fft[i + 1] = tmp;
Eric Laurentda7581b2010-07-02 08:12:41 -0700227 }
Chia-chi Yehdbd2b7e2010-08-19 15:34:10 +0800228
Eric Laurentda7581b2010-07-02 08:12:41 -0700229 return NO_ERROR;
230}
231
232void Visualizer::periodicCapture()
233{
234 Mutex::Autolock _l(mLock);
Steve Block3856b092011-10-20 11:56:00 +0100235 ALOGV("periodicCapture() %p mCaptureCallBack %p mCaptureFlags 0x%08x",
Eric Laurentda7581b2010-07-02 08:12:41 -0700236 this, mCaptureCallBack, mCaptureFlags);
237 if (mCaptureCallBack != NULL &&
238 (mCaptureFlags & (CAPTURE_WAVEFORM|CAPTURE_FFT)) &&
239 mCaptureSize != 0) {
240 uint8_t waveform[mCaptureSize];
241 status_t status = getWaveForm(waveform);
242 if (status != NO_ERROR) {
243 return;
244 }
245 uint8_t fft[mCaptureSize];
246 if (mCaptureFlags & CAPTURE_FFT) {
247 status = doFft(fft, waveform);
248 }
249 if (status != NO_ERROR) {
250 return;
251 }
252 uint8_t *wavePtr = NULL;
253 uint8_t *fftPtr = NULL;
254 uint32_t waveSize = 0;
255 uint32_t fftSize = 0;
256 if (mCaptureFlags & CAPTURE_WAVEFORM) {
257 wavePtr = waveform;
258 waveSize = mCaptureSize;
259 }
260 if (mCaptureFlags & CAPTURE_FFT) {
261 fftPtr = fft;
262 fftSize = mCaptureSize;
263 }
264 mCaptureCallBack(mCaptureCbkUser, waveSize, wavePtr, fftSize, fftPtr, mSampleRate);
265 }
266}
267
268uint32_t Visualizer::initCaptureSize()
269{
270 uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
271 effect_param_t *p = (effect_param_t *)buf32;
272
273 p->psize = sizeof(uint32_t);
274 p->vsize = sizeof(uint32_t);
Eric Laurent6d8b6942011-06-24 07:01:31 -0700275 *(int32_t *)p->data = VISUALIZER_PARAM_CAPTURE_SIZE;
Eric Laurentda7581b2010-07-02 08:12:41 -0700276 status_t status = getParameter(p);
277
278 if (status == NO_ERROR) {
279 status = p->status;
280 }
281
282 uint32_t size = 0;
283 if (status == NO_ERROR) {
284 size = *((int32_t *)p->data + 1);
285 }
286 mCaptureSize = size;
287
Steve Block3856b092011-10-20 11:56:00 +0100288 ALOGV("initCaptureSize size %d status %d", mCaptureSize, status);
Eric Laurentda7581b2010-07-02 08:12:41 -0700289
290 return size;
291}
292
293//-------------------------------------------------------------------------
294
295Visualizer::CaptureThread::CaptureThread(Visualizer& receiver, uint32_t captureRate, bool bCanCallJava)
296 : Thread(bCanCallJava), mReceiver(receiver)
297{
298 mSleepTimeUs = 1000000000 / captureRate;
Steve Block3856b092011-10-20 11:56:00 +0100299 ALOGV("CaptureThread cstor %p captureRate %d mSleepTimeUs %d", this, captureRate, mSleepTimeUs);
Eric Laurentda7581b2010-07-02 08:12:41 -0700300}
301
302bool Visualizer::CaptureThread::threadLoop()
303{
Steve Block3856b092011-10-20 11:56:00 +0100304 ALOGV("CaptureThread %p enter", this);
Eric Laurentda7581b2010-07-02 08:12:41 -0700305 while (!exitPending())
306 {
307 usleep(mSleepTimeUs);
308 mReceiver.periodicCapture();
309 }
Steve Block3856b092011-10-20 11:56:00 +0100310 ALOGV("CaptureThread %p exiting", this);
Eric Laurentda7581b2010-07-02 08:12:41 -0700311 return false;
312}
313
314status_t Visualizer::CaptureThread::readyToRun()
315{
316 return NO_ERROR;
317}
318
319void Visualizer::CaptureThread::onFirstRef()
320{
321}
322
323}; // namespace android
324