blob: f4165ffede883b68d10871c9901003dbb2175e2e [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2**
3** Copyright 2008, 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//#define LOG_NDEBUG 0
19#define LOG_TAG "AudioRecord"
20
21#include <stdint.h>
22#include <sys/types.h>
23
24#include <sched.h>
25#include <sys/resource.h>
26
27#include <private/media/AudioTrackShared.h>
28
29#include <media/AudioSystem.h>
30#include <media/AudioRecord.h>
Eric Laurenta553c252009-07-17 12:17:14 -070031#include <media/mediarecorder.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032
Mathias Agopian07952722009-05-19 19:08:10 -070033#include <binder/IServiceManager.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034#include <utils/Log.h>
Mathias Agopian07952722009-05-19 19:08:10 -070035#include <binder/MemoryDealer.h>
36#include <binder/Parcel.h>
37#include <binder/IPCThreadState.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038#include <utils/Timers.h>
39#include <cutils/atomic.h>
40
41#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
42#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
43
44namespace android {
45
46// ---------------------------------------------------------------------------
47
48AudioRecord::AudioRecord()
Eric Laurent49f02be2009-11-19 09:00:56 -080049 : mStatus(NO_INIT)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050{
51}
52
53AudioRecord::AudioRecord(
Eric Laurent4bc035a2009-05-22 09:18:15 -070054 int inputSource,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055 uint32_t sampleRate,
56 int format,
Eric Laurenta553c252009-07-17 12:17:14 -070057 uint32_t channels,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058 int frameCount,
59 uint32_t flags,
60 callback_t cbf,
61 void* user,
62 int notificationFrames)
Eric Laurent49f02be2009-11-19 09:00:56 -080063 : mStatus(NO_INIT)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064{
Eric Laurenta553c252009-07-17 12:17:14 -070065 mStatus = set(inputSource, sampleRate, format, channels,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080066 frameCount, flags, cbf, user, notificationFrames);
67}
68
69AudioRecord::~AudioRecord()
70{
71 if (mStatus == NO_ERROR) {
72 // Make sure that callback function exits in the case where
73 // it is looping on buffer empty condition in obtainBuffer().
74 // Otherwise the callback thread will never exit.
75 stop();
76 if (mClientRecordThread != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080077 mClientRecordThread->requestExitAndWait();
78 mClientRecordThread.clear();
79 }
80 mAudioRecord.clear();
81 IPCThreadState::self()->flushCommands();
82 }
83}
84
85status_t AudioRecord::set(
Eric Laurent4bc035a2009-05-22 09:18:15 -070086 int inputSource,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087 uint32_t sampleRate,
88 int format,
Eric Laurenta553c252009-07-17 12:17:14 -070089 uint32_t channels,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090 int frameCount,
91 uint32_t flags,
92 callback_t cbf,
93 void* user,
94 int notificationFrames,
95 bool threadCanCallJava)
96{
97
Eric Laurenta553c252009-07-17 12:17:14 -070098 LOGV("set(): sampleRate %d, channels %d, frameCount %d",sampleRate, channels, frameCount);
Eric Laurentef028272009-04-21 07:56:33 -070099 if (mAudioRecord != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100 return INVALID_OPERATION;
101 }
102
Eric Laurenta553c252009-07-17 12:17:14 -0700103 if (inputSource == AUDIO_SOURCE_DEFAULT) {
104 inputSource = AUDIO_SOURCE_MIC;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800105 }
106
107 if (sampleRate == 0) {
108 sampleRate = DEFAULT_SAMPLE_RATE;
109 }
110 // these below should probably come from the audioFlinger too...
111 if (format == 0) {
112 format = AudioSystem::PCM_16_BIT;
113 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800114 // validate parameters
Eric Laurenta553c252009-07-17 12:17:14 -0700115 if (!AudioSystem::isValidFormat(format)) {
116 LOGE("Invalid format");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800117 return BAD_VALUE;
118 }
Eric Laurenta553c252009-07-17 12:17:14 -0700119
120 if (!AudioSystem::isInputChannel(channels)) {
121 return BAD_VALUE;
122 }
123 int channelCount = AudioSystem::popCount(channels);
124
Eric Laurent49f02be2009-11-19 09:00:56 -0800125 audio_io_handle_t input = AudioSystem::getInput(inputSource,
Eric Laurenta553c252009-07-17 12:17:14 -0700126 sampleRate, format, channels, (AudioSystem::audio_in_acoustics)flags);
Eric Laurent49f02be2009-11-19 09:00:56 -0800127 if (input == 0) {
Eric Laurent9cc489a22009-12-05 05:20:01 -0800128 LOGE("Could not get audio input for record source %d", inputSource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800129 return BAD_VALUE;
130 }
131
132 // validate framecount
133 size_t inputBuffSizeInBytes = -1;
134 if (AudioSystem::getInputBufferSize(sampleRate, format, channelCount, &inputBuffSizeInBytes)
135 != NO_ERROR) {
136 LOGE("AudioSystem could not query the input buffer size.");
Eric Laurenta553c252009-07-17 12:17:14 -0700137 return NO_INIT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800138 }
Eric Laurenta553c252009-07-17 12:17:14 -0700139
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140 if (inputBuffSizeInBytes == 0) {
141 LOGE("Recording parameters are not supported: sampleRate %d, channelCount %d, format %d",
142 sampleRate, channelCount, format);
143 return BAD_VALUE;
144 }
Eric Laurenta553c252009-07-17 12:17:14 -0700145
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800146 int frameSizeInBytes = channelCount * (format == AudioSystem::PCM_16_BIT ? 2 : 1);
Eric Laurenta553c252009-07-17 12:17:14 -0700147 if (AudioSystem::isLinearPCM(format)) {
148 frameSizeInBytes = channelCount * (format == AudioSystem::PCM_16_BIT ? sizeof(int16_t) : sizeof(int8_t));
149 } else {
150 frameSizeInBytes = sizeof(int8_t);
151 }
152
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800153
154 // We use 2* size of input buffer for ping pong use of record buffer.
155 int minFrameCount = 2 * inputBuffSizeInBytes / frameSizeInBytes;
156 LOGV("AudioRecord::set() minFrameCount = %d", minFrameCount);
157
158 if (frameCount == 0) {
159 frameCount = minFrameCount;
160 } else if (frameCount < minFrameCount) {
161 return BAD_VALUE;
162 }
163
164 if (notificationFrames == 0) {
165 notificationFrames = frameCount/2;
166 }
167
Eric Laurentbda74692009-11-04 08:27:26 -0800168 // create the IAudioRecord
169 status_t status = openRecord(sampleRate, format, channelCount,
Eric Laurent49f02be2009-11-19 09:00:56 -0800170 frameCount, flags, input);
Eric Laurentbda74692009-11-04 08:27:26 -0800171
172 if (status != NO_ERROR) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800173 return status;
174 }
Eric Laurentbda74692009-11-04 08:27:26 -0800175
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800176 if (cbf != 0) {
177 mClientRecordThread = new ClientRecordThread(*this, threadCanCallJava);
178 if (mClientRecordThread == 0) {
179 return NO_INIT;
180 }
181 }
182
183 mStatus = NO_ERROR;
184
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800185 mFormat = format;
186 // Update buffer size in case it has been limited by AudioFlinger during track creation
187 mFrameCount = mCblk->frameCount;
Eric Laurenta553c252009-07-17 12:17:14 -0700188 mChannelCount = (uint8_t)channelCount;
Eric Laurent49f02be2009-11-19 09:00:56 -0800189 mChannels = channels;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800190 mActive = 0;
191 mCbf = cbf;
192 mNotificationFrames = notificationFrames;
193 mRemainingFrames = notificationFrames;
194 mUserData = user;
195 // TODO: add audio hardware input latency here
Eric Laurent88e209d2009-07-07 07:10:45 -0700196 mLatency = (1000*mFrameCount) / sampleRate;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800197 mMarkerPosition = 0;
Jean-Michel Trivi78c13142009-03-24 19:48:58 -0700198 mMarkerReached = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800199 mNewPosition = 0;
200 mUpdatePeriod = 0;
Eric Laurent4bc035a2009-05-22 09:18:15 -0700201 mInputSource = (uint8_t)inputSource;
Eric Laurentbda74692009-11-04 08:27:26 -0800202 mFlags = flags;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800203
204 return NO_ERROR;
205}
206
207status_t AudioRecord::initCheck() const
208{
209 return mStatus;
210}
211
212// -------------------------------------------------------------------------
213
214uint32_t AudioRecord::latency() const
215{
216 return mLatency;
217}
218
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800219int AudioRecord::format() const
220{
221 return mFormat;
222}
223
224int AudioRecord::channelCount() const
225{
226 return mChannelCount;
227}
228
229uint32_t AudioRecord::frameCount() const
230{
231 return mFrameCount;
232}
233
234int AudioRecord::frameSize() const
235{
Eric Laurenta553c252009-07-17 12:17:14 -0700236 if (AudioSystem::isLinearPCM(mFormat)) {
237 return channelCount()*((format() == AudioSystem::PCM_8_BIT) ? sizeof(uint8_t) : sizeof(int16_t));
238 } else {
239 return sizeof(uint8_t);
240 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800241}
242
Eric Laurent4bc035a2009-05-22 09:18:15 -0700243int AudioRecord::inputSource() const
244{
245 return (int)mInputSource;
246}
247
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800248// -------------------------------------------------------------------------
249
250status_t AudioRecord::start()
251{
252 status_t ret = NO_ERROR;
253 sp<ClientRecordThread> t = mClientRecordThread;
254
255 LOGV("start");
256
257 if (t != 0) {
258 if (t->exitPending()) {
259 if (t->requestExitAndWait() == WOULD_BLOCK) {
260 LOGE("AudioRecord::start called from thread");
261 return WOULD_BLOCK;
262 }
263 }
264 t->mLock.lock();
265 }
266
267 if (android_atomic_or(1, &mActive) == 0) {
Eric Laurent49f02be2009-11-19 09:00:56 -0800268 ret = mAudioRecord->start();
269 if (ret == DEAD_OBJECT) {
270 LOGV("start() dead IAudioRecord: creating a new one");
271 ret = openRecord(mCblk->sampleRate, mFormat, mChannelCount,
272 mFrameCount, mFlags, getInput());
Eric Laurentbda74692009-11-04 08:27:26 -0800273 if (ret == NO_ERROR) {
Eric Laurent49f02be2009-11-19 09:00:56 -0800274 ret = mAudioRecord->start();
Eric Laurentbda74692009-11-04 08:27:26 -0800275 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800276 }
Eric Laurent49f02be2009-11-19 09:00:56 -0800277 if (ret == NO_ERROR) {
278 mNewPosition = mCblk->user + mUpdatePeriod;
279 mCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
280 mCblk->waitTimeMs = 0;
281 if (t != 0) {
282 t->run("ClientRecordThread", THREAD_PRIORITY_AUDIO_CLIENT);
283 } else {
284 setpriority(PRIO_PROCESS, 0, THREAD_PRIORITY_AUDIO_CLIENT);
285 }
286 } else {
287 LOGV("start() failed");
288 android_atomic_and(~1, &mActive);
289 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800290 }
291
292 if (t != 0) {
293 t->mLock.unlock();
294 }
295
296 return ret;
297}
298
299status_t AudioRecord::stop()
300{
301 sp<ClientRecordThread> t = mClientRecordThread;
302
303 LOGV("stop");
304
305 if (t != 0) {
306 t->mLock.lock();
307 }
308
309 if (android_atomic_and(~1, &mActive) == 1) {
Eric Laurentef028272009-04-21 07:56:33 -0700310 mCblk->cv.signal();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800311 mAudioRecord->stop();
Jean-Michel Trivi78c13142009-03-24 19:48:58 -0700312 // the record head position will reset to 0, so if a marker is set, we need
313 // to activate it again
314 mMarkerReached = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800315 if (t != 0) {
316 t->requestExit();
317 } else {
318 setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL);
319 }
320 }
321
322 if (t != 0) {
323 t->mLock.unlock();
324 }
325
326 return NO_ERROR;
327}
328
329bool AudioRecord::stopped() const
330{
331 return !mActive;
332}
333
Eric Laurent88e209d2009-07-07 07:10:45 -0700334uint32_t AudioRecord::getSampleRate()
335{
336 return mCblk->sampleRate;
337}
338
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800339status_t AudioRecord::setMarkerPosition(uint32_t marker)
340{
341 if (mCbf == 0) return INVALID_OPERATION;
342
343 mMarkerPosition = marker;
Jean-Michel Trivi78c13142009-03-24 19:48:58 -0700344 mMarkerReached = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800345
346 return NO_ERROR;
347}
348
349status_t AudioRecord::getMarkerPosition(uint32_t *marker)
350{
351 if (marker == 0) return BAD_VALUE;
352
353 *marker = mMarkerPosition;
354
355 return NO_ERROR;
356}
357
358status_t AudioRecord::setPositionUpdatePeriod(uint32_t updatePeriod)
359{
360 if (mCbf == 0) return INVALID_OPERATION;
361
362 uint32_t curPosition;
363 getPosition(&curPosition);
364 mNewPosition = curPosition + updatePeriod;
365 mUpdatePeriod = updatePeriod;
366
367 return NO_ERROR;
368}
369
370status_t AudioRecord::getPositionUpdatePeriod(uint32_t *updatePeriod)
371{
372 if (updatePeriod == 0) return BAD_VALUE;
373
374 *updatePeriod = mUpdatePeriod;
375
376 return NO_ERROR;
377}
378
379status_t AudioRecord::getPosition(uint32_t *position)
380{
381 if (position == 0) return BAD_VALUE;
382
383 *position = mCblk->user;
384
385 return NO_ERROR;
386}
387
388
389// -------------------------------------------------------------------------
390
Eric Laurentbda74692009-11-04 08:27:26 -0800391status_t AudioRecord::openRecord(
392 uint32_t sampleRate,
393 int format,
394 int channelCount,
395 int frameCount,
Eric Laurent49f02be2009-11-19 09:00:56 -0800396 uint32_t flags,
397 audio_io_handle_t input)
Eric Laurentbda74692009-11-04 08:27:26 -0800398{
399 status_t status;
400 const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
401 if (audioFlinger == 0) {
402 return NO_INIT;
403 }
404
Eric Laurent49f02be2009-11-19 09:00:56 -0800405 sp<IAudioRecord> record = audioFlinger->openRecord(getpid(), input,
Eric Laurentbda74692009-11-04 08:27:26 -0800406 sampleRate, format,
407 channelCount,
408 frameCount,
409 ((uint16_t)flags) << 16,
410 &status);
411 if (record == 0) {
412 LOGE("AudioFlinger could not create record track, status: %d", status);
413 return status;
414 }
415 sp<IMemory> cblk = record->getCblk();
416 if (cblk == 0) {
417 LOGE("Could not get control block");
418 return NO_INIT;
419 }
420 mAudioRecord.clear();
421 mAudioRecord = record;
422 mCblkMemory.clear();
423 mCblkMemory = cblk;
424 mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer());
425 mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
426 mCblk->out = 0;
Eric Laurent49f02be2009-11-19 09:00:56 -0800427 mCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
428 mCblk->waitTimeMs = 0;
Eric Laurentbda74692009-11-04 08:27:26 -0800429 return NO_ERROR;
430}
431
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800432status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
433{
434 int active;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800435 status_t result;
436 audio_track_cblk_t* cblk = mCblk;
437 uint32_t framesReq = audioBuffer->frameCount;
Eric Laurentef028272009-04-21 07:56:33 -0700438 uint32_t waitTimeMs = (waitCount < 0) ? cblk->bufferTimeoutMs : WAIT_PERIOD_MS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800439
440 audioBuffer->frameCount = 0;
441 audioBuffer->size = 0;
442
443 uint32_t framesReady = cblk->framesReady();
444
445 if (framesReady == 0) {
Eric Laurentbda74692009-11-04 08:27:26 -0800446 cblk->lock.lock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800447 goto start_loop_here;
448 while (framesReady == 0) {
449 active = mActive;
Eric Laurentbda74692009-11-04 08:27:26 -0800450 if (UNLIKELY(!active)) {
451 cblk->lock.unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800452 return NO_MORE_BUFFERS;
Eric Laurentbda74692009-11-04 08:27:26 -0800453 }
454 if (UNLIKELY(!waitCount)) {
455 cblk->lock.unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800456 return WOULD_BLOCK;
Eric Laurentbda74692009-11-04 08:27:26 -0800457 }
Eric Laurentef028272009-04-21 07:56:33 -0700458 result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800459 if (__builtin_expect(result!=NO_ERROR, false)) {
Eric Laurentef028272009-04-21 07:56:33 -0700460 cblk->waitTimeMs += waitTimeMs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800461 if (cblk->waitTimeMs >= cblk->bufferTimeoutMs) {
462 LOGW( "obtainBuffer timed out (is the CPU pegged?) "
463 "user=%08x, server=%08x", cblk->user, cblk->server);
Eric Laurentbda74692009-11-04 08:27:26 -0800464 cblk->lock.unlock();
465 result = mAudioRecord->start();
466 if (result == DEAD_OBJECT) {
467 LOGW("obtainBuffer() dead IAudioRecord: creating a new one");
468 result = openRecord(cblk->sampleRate, mFormat, mChannelCount,
Eric Laurent49f02be2009-11-19 09:00:56 -0800469 mFrameCount, mFlags, getInput());
Eric Laurentbda74692009-11-04 08:27:26 -0800470 if (result == NO_ERROR) {
471 cblk = mCblk;
Eric Laurent49f02be2009-11-19 09:00:56 -0800472 mAudioRecord->start();
Eric Laurentbda74692009-11-04 08:27:26 -0800473 }
474 }
475 cblk->lock.lock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800476 cblk->waitTimeMs = 0;
477 }
478 if (--waitCount == 0) {
Eric Laurentbda74692009-11-04 08:27:26 -0800479 cblk->lock.unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800480 return TIMED_OUT;
481 }
482 }
483 // read the server count again
484 start_loop_here:
485 framesReady = cblk->framesReady();
486 }
Eric Laurentbda74692009-11-04 08:27:26 -0800487 cblk->lock.unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800488 }
489
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800490 cblk->waitTimeMs = 0;
Eric Laurenta553c252009-07-17 12:17:14 -0700491
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800492 if (framesReq > framesReady) {
493 framesReq = framesReady;
494 }
495
496 uint32_t u = cblk->user;
497 uint32_t bufferEnd = cblk->userBase + cblk->frameCount;
498
499 if (u + framesReq > bufferEnd) {
500 framesReq = bufferEnd - u;
501 }
502
503 audioBuffer->flags = 0;
504 audioBuffer->channelCount= mChannelCount;
505 audioBuffer->format = mFormat;
506 audioBuffer->frameCount = framesReq;
Eric Laurenta553c252009-07-17 12:17:14 -0700507 audioBuffer->size = framesReq*cblk->frameSize;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800508 audioBuffer->raw = (int8_t*)cblk->buffer(u);
509 active = mActive;
510 return active ? status_t(NO_ERROR) : status_t(STOPPED);
511}
512
513void AudioRecord::releaseBuffer(Buffer* audioBuffer)
514{
515 audio_track_cblk_t* cblk = mCblk;
516 cblk->stepUser(audioBuffer->frameCount);
517}
518
Eric Laurent49f02be2009-11-19 09:00:56 -0800519audio_io_handle_t AudioRecord::getInput()
520{
521 return AudioSystem::getInput(mInputSource,
522 mCblk->sampleRate,
523 mFormat, mChannels,
524 (AudioSystem::audio_in_acoustics)mFlags);
525}
526
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800527// -------------------------------------------------------------------------
528
529ssize_t AudioRecord::read(void* buffer, size_t userSize)
530{
531 ssize_t read = 0;
532 Buffer audioBuffer;
533 int8_t *dst = static_cast<int8_t*>(buffer);
534
535 if (ssize_t(userSize) < 0) {
536 // sanity-check. user is most-likely passing an error code.
537 LOGE("AudioRecord::read(buffer=%p, size=%u (%d)",
538 buffer, userSize, userSize);
539 return BAD_VALUE;
540 }
541
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800542
543 do {
544
Eric Laurenta553c252009-07-17 12:17:14 -0700545 audioBuffer.frameCount = userSize/frameSize();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800546
547 // Calling obtainBuffer() with a negative wait count causes
548 // an (almost) infinite wait time.
549 status_t err = obtainBuffer(&audioBuffer, -1);
550 if (err < 0) {
551 // out of buffers, return #bytes written
552 if (err == status_t(NO_MORE_BUFFERS))
553 break;
554 return ssize_t(err);
555 }
556
557 size_t bytesRead = audioBuffer.size;
558 memcpy(dst, audioBuffer.i8, bytesRead);
559
560 dst += bytesRead;
561 userSize -= bytesRead;
562 read += bytesRead;
563
564 releaseBuffer(&audioBuffer);
565 } while (userSize);
566
567 return read;
568}
569
570// -------------------------------------------------------------------------
571
572bool AudioRecord::processAudioBuffer(const sp<ClientRecordThread>& thread)
573{
574 Buffer audioBuffer;
575 uint32_t frames = mRemainingFrames;
576 size_t readSize;
577
578 // Manage marker callback
Jean-Michel Trivi78c13142009-03-24 19:48:58 -0700579 if (!mMarkerReached && (mMarkerPosition > 0)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800580 if (mCblk->user >= mMarkerPosition) {
581 mCbf(EVENT_MARKER, mUserData, (void *)&mMarkerPosition);
Jean-Michel Trivi78c13142009-03-24 19:48:58 -0700582 mMarkerReached = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800583 }
584 }
585
586 // Manage new position callback
587 if (mUpdatePeriod > 0) {
588 while (mCblk->user >= mNewPosition) {
589 mCbf(EVENT_NEW_POS, mUserData, (void *)&mNewPosition);
590 mNewPosition += mUpdatePeriod;
591 }
592 }
593
594 do {
595 audioBuffer.frameCount = frames;
Eric Laurenta553c252009-07-17 12:17:14 -0700596 // Calling obtainBuffer() with a wait count of 1
597 // limits wait time to WAIT_PERIOD_MS. This prevents from being
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800598 // stuck here not being able to handle timed events (position, markers).
599 status_t err = obtainBuffer(&audioBuffer, 1);
600 if (err < NO_ERROR) {
601 if (err != TIMED_OUT) {
Eric Laurentef028272009-04-21 07:56:33 -0700602 LOGE_IF(err != status_t(NO_MORE_BUFFERS), "Error obtaining an audio buffer, giving up.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800603 return false;
604 }
605 break;
606 }
607 if (err == status_t(STOPPED)) return false;
608
609 size_t reqSize = audioBuffer.size;
610 mCbf(EVENT_MORE_DATA, mUserData, &audioBuffer);
611 readSize = audioBuffer.size;
612
613 // Sanity check on returned size
Eric Laurent272beb62009-03-24 21:23:54 -0700614 if (ssize_t(readSize) <= 0) {
615 // The callback is done filling buffers
616 // Keep this thread going to handle timed events and
617 // still try to get more data in intervals of WAIT_PERIOD_MS
618 // but don't just loop and block the CPU, so wait
619 usleep(WAIT_PERIOD_MS*1000);
620 break;
621 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800622 if (readSize > reqSize) readSize = reqSize;
623
624 audioBuffer.size = readSize;
Eric Laurenta553c252009-07-17 12:17:14 -0700625 audioBuffer.frameCount = readSize/frameSize();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800626 frames -= audioBuffer.frameCount;
627
628 releaseBuffer(&audioBuffer);
629
630 } while (frames);
631
Eric Laurenta553c252009-07-17 12:17:14 -0700632
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800633 // Manage overrun callback
634 if (mActive && (mCblk->framesAvailable_l() == 0)) {
635 LOGV("Overrun user: %x, server: %x, flowControlFlag %d", mCblk->user, mCblk->server, mCblk->flowControlFlag);
636 if (mCblk->flowControlFlag == 0) {
637 mCbf(EVENT_OVERRUN, mUserData, 0);
638 mCblk->flowControlFlag = 1;
639 }
640 }
641
642 if (frames == 0) {
643 mRemainingFrames = mNotificationFrames;
644 } else {
645 mRemainingFrames = frames;
646 }
647 return true;
648}
649
650// =========================================================================
651
652AudioRecord::ClientRecordThread::ClientRecordThread(AudioRecord& receiver, bool bCanCallJava)
653 : Thread(bCanCallJava), mReceiver(receiver)
654{
655}
656
657bool AudioRecord::ClientRecordThread::threadLoop()
658{
659 return mReceiver.processAudioBuffer(this);
660}
661
662// -------------------------------------------------------------------------
663
664}; // namespace android
665