blob: 8438714dac28fc11091ba5736d9b69a67e39fb7e [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/Parcel.h>
36#include <binder/IPCThreadState.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037#include <utils/Timers.h>
Eric Laurentae29b762011-03-28 18:37:07 -070038#include <utils/Atomic.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039
Dima Zavin24fc2fb2011-04-19 22:30:36 -070040#include <hardware/audio.h>
41#include <cutils/bitops.h>
42
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
44#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
45
46namespace android {
Chia-chi Yeh97d61f72010-06-22 08:01:13 +080047// ---------------------------------------------------------------------------
48
49// static
50status_t AudioRecord::getMinFrameCount(
51 int* frameCount,
52 uint32_t sampleRate,
53 int format,
54 int channelCount)
55{
56 size_t size = 0;
57 if (AudioSystem::getInputBufferSize(sampleRate, format, channelCount, &size)
58 != NO_ERROR) {
59 LOGE("AudioSystem could not query the input buffer size.");
60 return NO_INIT;
61 }
62
63 if (size == 0) {
64 LOGE("Unsupported configuration: sampleRate %d, format %d, channelCount %d",
65 sampleRate, format, channelCount);
66 return BAD_VALUE;
67 }
68
69 // We double the size of input buffer for ping pong use of record buffer.
70 size <<= 1;
71
Dima Zavin24fc2fb2011-04-19 22:30:36 -070072 if (audio_is_linear_pcm(format)) {
73 size /= channelCount * (format == AUDIO_FORMAT_PCM_16_BIT ? 2 : 1);
Chia-chi Yeh97d61f72010-06-22 08:01:13 +080074 }
75
76 *frameCount = size;
77 return NO_ERROR;
78}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079
80// ---------------------------------------------------------------------------
81
82AudioRecord::AudioRecord()
Eric Laurent65b65452010-06-01 23:49:17 -070083 : mStatus(NO_INIT), mSessionId(0)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084{
85}
86
87AudioRecord::AudioRecord(
Eric Laurent4bc035a2009-05-22 09:18:15 -070088 int inputSource,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080089 uint32_t sampleRate,
90 int format,
Eric Laurenta553c252009-07-17 12:17:14 -070091 uint32_t channels,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092 int frameCount,
93 uint32_t flags,
94 callback_t cbf,
95 void* user,
Eric Laurent65b65452010-06-01 23:49:17 -070096 int notificationFrames,
97 int sessionId)
98 : mStatus(NO_INIT), mSessionId(0)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099{
Eric Laurenta553c252009-07-17 12:17:14 -0700100 mStatus = set(inputSource, sampleRate, format, channels,
Eric Laurent65b65452010-06-01 23:49:17 -0700101 frameCount, flags, cbf, user, notificationFrames, sessionId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102}
103
104AudioRecord::~AudioRecord()
105{
106 if (mStatus == NO_ERROR) {
107 // Make sure that callback function exits in the case where
108 // it is looping on buffer empty condition in obtainBuffer().
109 // Otherwise the callback thread will never exit.
110 stop();
111 if (mClientRecordThread != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800112 mClientRecordThread->requestExitAndWait();
113 mClientRecordThread.clear();
114 }
115 mAudioRecord.clear();
116 IPCThreadState::self()->flushCommands();
117 }
118}
119
120status_t AudioRecord::set(
Eric Laurent4bc035a2009-05-22 09:18:15 -0700121 int inputSource,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800122 uint32_t sampleRate,
123 int format,
Eric Laurenta553c252009-07-17 12:17:14 -0700124 uint32_t channels,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125 int frameCount,
126 uint32_t flags,
127 callback_t cbf,
128 void* user,
129 int notificationFrames,
Eric Laurent65b65452010-06-01 23:49:17 -0700130 bool threadCanCallJava,
131 int sessionId)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800132{
133
Eric Laurenta553c252009-07-17 12:17:14 -0700134 LOGV("set(): sampleRate %d, channels %d, frameCount %d",sampleRate, channels, frameCount);
Eric Laurent421ddc02011-03-07 14:52:59 -0800135
136 AutoMutex lock(mLock);
137
Eric Laurentef028272009-04-21 07:56:33 -0700138 if (mAudioRecord != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800139 return INVALID_OPERATION;
140 }
141
Eric Laurenta553c252009-07-17 12:17:14 -0700142 if (inputSource == AUDIO_SOURCE_DEFAULT) {
143 inputSource = AUDIO_SOURCE_MIC;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800144 }
145
146 if (sampleRate == 0) {
147 sampleRate = DEFAULT_SAMPLE_RATE;
148 }
149 // these below should probably come from the audioFlinger too...
150 if (format == 0) {
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700151 format = AUDIO_FORMAT_PCM_16_BIT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800153 // validate parameters
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700154 if (!audio_is_valid_format(format)) {
Eric Laurenta553c252009-07-17 12:17:14 -0700155 LOGE("Invalid format");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800156 return BAD_VALUE;
157 }
Eric Laurenta553c252009-07-17 12:17:14 -0700158
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700159 if (!audio_is_input_channel(channels)) {
Eric Laurenta553c252009-07-17 12:17:14 -0700160 return BAD_VALUE;
161 }
Eric Laurent65b65452010-06-01 23:49:17 -0700162
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700163 int channelCount = popcount(channels);
Eric Laurenta553c252009-07-17 12:17:14 -0700164
Eric Laurent49f02be2009-11-19 09:00:56 -0800165 audio_io_handle_t input = AudioSystem::getInput(inputSource,
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700166 sampleRate, format, channels, (audio_in_acoustics_t)flags);
Eric Laurent49f02be2009-11-19 09:00:56 -0800167 if (input == 0) {
Eric Laurent9cc489a2009-12-05 05:20:01 -0800168 LOGE("Could not get audio input for record source %d", inputSource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800169 return BAD_VALUE;
170 }
171
172 // validate framecount
Chia-chi Yeh97d61f72010-06-22 08:01:13 +0800173 int minFrameCount = 0;
174 status_t status = getMinFrameCount(&minFrameCount, sampleRate, format, channelCount);
175 if (status != NO_ERROR) {
176 return status;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800177 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800178 LOGV("AudioRecord::set() minFrameCount = %d", minFrameCount);
179
180 if (frameCount == 0) {
181 frameCount = minFrameCount;
182 } else if (frameCount < minFrameCount) {
183 return BAD_VALUE;
184 }
185
186 if (notificationFrames == 0) {
187 notificationFrames = frameCount/2;
188 }
189
Eric Laurent65b65452010-06-01 23:49:17 -0700190 mSessionId = sessionId;
191
Eric Laurentbda74692009-11-04 08:27:26 -0800192 // create the IAudioRecord
Eric Laurent421ddc02011-03-07 14:52:59 -0800193 status = openRecord_l(sampleRate, format, channelCount,
Chia-chi Yeh97d61f72010-06-22 08:01:13 +0800194 frameCount, flags, input);
Eric Laurentbda74692009-11-04 08:27:26 -0800195 if (status != NO_ERROR) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800196 return status;
197 }
Eric Laurentbda74692009-11-04 08:27:26 -0800198
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800199 if (cbf != 0) {
200 mClientRecordThread = new ClientRecordThread(*this, threadCanCallJava);
201 if (mClientRecordThread == 0) {
202 return NO_INIT;
203 }
204 }
205
206 mStatus = NO_ERROR;
207
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800208 mFormat = format;
209 // Update buffer size in case it has been limited by AudioFlinger during track creation
210 mFrameCount = mCblk->frameCount;
Eric Laurenta553c252009-07-17 12:17:14 -0700211 mChannelCount = (uint8_t)channelCount;
Eric Laurent49f02be2009-11-19 09:00:56 -0800212 mChannels = channels;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800213 mActive = 0;
214 mCbf = cbf;
215 mNotificationFrames = notificationFrames;
216 mRemainingFrames = notificationFrames;
217 mUserData = user;
218 // TODO: add audio hardware input latency here
Eric Laurent88e209d2009-07-07 07:10:45 -0700219 mLatency = (1000*mFrameCount) / sampleRate;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800220 mMarkerPosition = 0;
Jean-Michel Trivi78c13142009-03-24 19:48:58 -0700221 mMarkerReached = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800222 mNewPosition = 0;
223 mUpdatePeriod = 0;
Eric Laurent4bc035a2009-05-22 09:18:15 -0700224 mInputSource = (uint8_t)inputSource;
Eric Laurentbda74692009-11-04 08:27:26 -0800225 mFlags = flags;
Eric Laurent47d0a922010-02-26 02:47:27 -0800226 mInput = input;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800227
228 return NO_ERROR;
229}
230
231status_t AudioRecord::initCheck() const
232{
233 return mStatus;
234}
235
236// -------------------------------------------------------------------------
237
238uint32_t AudioRecord::latency() const
239{
240 return mLatency;
241}
242
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800243int AudioRecord::format() const
244{
245 return mFormat;
246}
247
248int AudioRecord::channelCount() const
249{
250 return mChannelCount;
251}
252
253uint32_t AudioRecord::frameCount() const
254{
255 return mFrameCount;
256}
257
258int AudioRecord::frameSize() const
259{
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700260 if (audio_is_linear_pcm(mFormat)) {
261 return channelCount()*((format() == AUDIO_FORMAT_PCM_8_BIT) ? sizeof(uint8_t) : sizeof(int16_t));
Eric Laurenta553c252009-07-17 12:17:14 -0700262 } else {
263 return sizeof(uint8_t);
264 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800265}
266
Eric Laurent4bc035a2009-05-22 09:18:15 -0700267int AudioRecord::inputSource() const
268{
269 return (int)mInputSource;
270}
271
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800272// -------------------------------------------------------------------------
273
274status_t AudioRecord::start()
275{
276 status_t ret = NO_ERROR;
277 sp<ClientRecordThread> t = mClientRecordThread;
278
279 LOGV("start");
280
281 if (t != 0) {
282 if (t->exitPending()) {
283 if (t->requestExitAndWait() == WOULD_BLOCK) {
284 LOGE("AudioRecord::start called from thread");
285 return WOULD_BLOCK;
286 }
287 }
288 t->mLock.lock();
289 }
290
Eric Laurentf3d6dd02010-11-18 08:40:16 -0800291 AutoMutex lock(mLock);
Eric Laurent421ddc02011-03-07 14:52:59 -0800292 // acquire a strong reference on the IAudioRecord and IMemory so that they cannot be destroyed
293 // while we are accessing the cblk
294 sp <IAudioRecord> audioRecord = mAudioRecord;
295 sp <IMemory> iMem = mCblkMemory;
296 audio_track_cblk_t* cblk = mCblk;
Eric Laurentf3d6dd02010-11-18 08:40:16 -0800297 if (mActive == 0) {
298 mActive = 1;
Eric Laurent421ddc02011-03-07 14:52:59 -0800299
300 cblk->lock.lock();
301 if (!(cblk->flags & CBLK_INVALID_MSK)) {
302 cblk->lock.unlock();
303 ret = mAudioRecord->start();
304 cblk->lock.lock();
305 if (ret == DEAD_OBJECT) {
Eric Laurentae29b762011-03-28 18:37:07 -0700306 android_atomic_or(CBLK_INVALID_ON, &cblk->flags);
Eric Laurentbda74692009-11-04 08:27:26 -0800307 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800308 }
Eric Laurent421ddc02011-03-07 14:52:59 -0800309 if (cblk->flags & CBLK_INVALID_MSK) {
310 ret = restoreRecord_l(cblk);
311 }
312 cblk->lock.unlock();
Eric Laurent49f02be2009-11-19 09:00:56 -0800313 if (ret == NO_ERROR) {
Eric Laurent421ddc02011-03-07 14:52:59 -0800314 mNewPosition = cblk->user + mUpdatePeriod;
315 cblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
316 cblk->waitTimeMs = 0;
Eric Laurent49f02be2009-11-19 09:00:56 -0800317 if (t != 0) {
318 t->run("ClientRecordThread", THREAD_PRIORITY_AUDIO_CLIENT);
319 } else {
320 setpriority(PRIO_PROCESS, 0, THREAD_PRIORITY_AUDIO_CLIENT);
321 }
322 } else {
Eric Laurentf3d6dd02010-11-18 08:40:16 -0800323 mActive = 0;
Eric Laurent49f02be2009-11-19 09:00:56 -0800324 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800325 }
326
327 if (t != 0) {
328 t->mLock.unlock();
329 }
330
331 return ret;
332}
333
334status_t AudioRecord::stop()
335{
336 sp<ClientRecordThread> t = mClientRecordThread;
337
338 LOGV("stop");
339
340 if (t != 0) {
341 t->mLock.lock();
Eric Laurentf3d6dd02010-11-18 08:40:16 -0800342 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800343
Eric Laurentf3d6dd02010-11-18 08:40:16 -0800344 AutoMutex lock(mLock);
345 if (mActive == 1) {
346 mActive = 0;
Eric Laurentef028272009-04-21 07:56:33 -0700347 mCblk->cv.signal();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800348 mAudioRecord->stop();
Jean-Michel Trivi78c13142009-03-24 19:48:58 -0700349 // the record head position will reset to 0, so if a marker is set, we need
350 // to activate it again
351 mMarkerReached = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800352 if (t != 0) {
353 t->requestExit();
354 } else {
355 setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL);
356 }
357 }
358
359 if (t != 0) {
360 t->mLock.unlock();
361 }
362
363 return NO_ERROR;
364}
365
366bool AudioRecord::stopped() const
367{
368 return !mActive;
369}
370
Eric Laurent88e209d2009-07-07 07:10:45 -0700371uint32_t AudioRecord::getSampleRate()
372{
Eric Laurent421ddc02011-03-07 14:52:59 -0800373 AutoMutex lock(mLock);
Eric Laurent88e209d2009-07-07 07:10:45 -0700374 return mCblk->sampleRate;
375}
376
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800377status_t AudioRecord::setMarkerPosition(uint32_t marker)
378{
379 if (mCbf == 0) return INVALID_OPERATION;
380
381 mMarkerPosition = marker;
Jean-Michel Trivi78c13142009-03-24 19:48:58 -0700382 mMarkerReached = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800383
384 return NO_ERROR;
385}
386
387status_t AudioRecord::getMarkerPosition(uint32_t *marker)
388{
389 if (marker == 0) return BAD_VALUE;
390
391 *marker = mMarkerPosition;
392
393 return NO_ERROR;
394}
395
396status_t AudioRecord::setPositionUpdatePeriod(uint32_t updatePeriod)
397{
398 if (mCbf == 0) return INVALID_OPERATION;
399
400 uint32_t curPosition;
401 getPosition(&curPosition);
402 mNewPosition = curPosition + updatePeriod;
403 mUpdatePeriod = updatePeriod;
404
405 return NO_ERROR;
406}
407
408status_t AudioRecord::getPositionUpdatePeriod(uint32_t *updatePeriod)
409{
410 if (updatePeriod == 0) return BAD_VALUE;
411
412 *updatePeriod = mUpdatePeriod;
413
414 return NO_ERROR;
415}
416
417status_t AudioRecord::getPosition(uint32_t *position)
418{
419 if (position == 0) return BAD_VALUE;
420
Eric Laurent421ddc02011-03-07 14:52:59 -0800421 AutoMutex lock(mLock);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800422 *position = mCblk->user;
423
424 return NO_ERROR;
425}
426
Eric Laurent47d0a922010-02-26 02:47:27 -0800427unsigned int AudioRecord::getInputFramesLost()
428{
429 if (mActive)
430 return AudioSystem::getInputFramesLost(mInput);
431 else
432 return 0;
433}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800434
435// -------------------------------------------------------------------------
436
Eric Laurent421ddc02011-03-07 14:52:59 -0800437// must be called with mLock held
438status_t AudioRecord::openRecord_l(
Eric Laurentbda74692009-11-04 08:27:26 -0800439 uint32_t sampleRate,
440 int format,
441 int channelCount,
442 int frameCount,
Eric Laurent49f02be2009-11-19 09:00:56 -0800443 uint32_t flags,
444 audio_io_handle_t input)
Eric Laurentbda74692009-11-04 08:27:26 -0800445{
446 status_t status;
447 const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
448 if (audioFlinger == 0) {
449 return NO_INIT;
450 }
451
Eric Laurent49f02be2009-11-19 09:00:56 -0800452 sp<IAudioRecord> record = audioFlinger->openRecord(getpid(), input,
Eric Laurentbda74692009-11-04 08:27:26 -0800453 sampleRate, format,
454 channelCount,
455 frameCount,
456 ((uint16_t)flags) << 16,
Eric Laurent65b65452010-06-01 23:49:17 -0700457 &mSessionId,
Eric Laurentbda74692009-11-04 08:27:26 -0800458 &status);
459 if (record == 0) {
460 LOGE("AudioFlinger could not create record track, status: %d", status);
461 return status;
462 }
463 sp<IMemory> cblk = record->getCblk();
464 if (cblk == 0) {
465 LOGE("Could not get control block");
466 return NO_INIT;
467 }
468 mAudioRecord.clear();
469 mAudioRecord = record;
470 mCblkMemory.clear();
471 mCblkMemory = cblk;
472 mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer());
473 mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
Eric Laurentae29b762011-03-28 18:37:07 -0700474 android_atomic_and(~CBLK_DIRECTION_MSK, &mCblk->flags);
Eric Laurent49f02be2009-11-19 09:00:56 -0800475 mCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
476 mCblk->waitTimeMs = 0;
Eric Laurentbda74692009-11-04 08:27:26 -0800477 return NO_ERROR;
478}
479
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800480status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
481{
Eric Laurent421ddc02011-03-07 14:52:59 -0800482 AutoMutex lock(mLock);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800483 int active;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800484 status_t result;
485 audio_track_cblk_t* cblk = mCblk;
486 uint32_t framesReq = audioBuffer->frameCount;
Eric Laurentef028272009-04-21 07:56:33 -0700487 uint32_t waitTimeMs = (waitCount < 0) ? cblk->bufferTimeoutMs : WAIT_PERIOD_MS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800488
489 audioBuffer->frameCount = 0;
490 audioBuffer->size = 0;
491
492 uint32_t framesReady = cblk->framesReady();
493
494 if (framesReady == 0) {
Eric Laurentbda74692009-11-04 08:27:26 -0800495 cblk->lock.lock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800496 goto start_loop_here;
497 while (framesReady == 0) {
498 active = mActive;
Eric Laurentbda74692009-11-04 08:27:26 -0800499 if (UNLIKELY(!active)) {
500 cblk->lock.unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800501 return NO_MORE_BUFFERS;
Eric Laurentbda74692009-11-04 08:27:26 -0800502 }
503 if (UNLIKELY(!waitCount)) {
504 cblk->lock.unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800505 return WOULD_BLOCK;
Eric Laurentbda74692009-11-04 08:27:26 -0800506 }
Eric Laurent421ddc02011-03-07 14:52:59 -0800507 if (!(cblk->flags & CBLK_INVALID_MSK)) {
508 mLock.unlock();
509 result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs));
510 cblk->lock.unlock();
511 mLock.lock();
512 if (mActive == 0) {
513 return status_t(STOPPED);
514 }
515 cblk->lock.lock();
516 }
517 if (cblk->flags & CBLK_INVALID_MSK) {
518 goto create_new_record;
519 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800520 if (__builtin_expect(result!=NO_ERROR, false)) {
Eric Laurentef028272009-04-21 07:56:33 -0700521 cblk->waitTimeMs += waitTimeMs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800522 if (cblk->waitTimeMs >= cblk->bufferTimeoutMs) {
523 LOGW( "obtainBuffer timed out (is the CPU pegged?) "
524 "user=%08x, server=%08x", cblk->user, cblk->server);
Eric Laurentbda74692009-11-04 08:27:26 -0800525 cblk->lock.unlock();
526 result = mAudioRecord->start();
Eric Laurentbda74692009-11-04 08:27:26 -0800527 cblk->lock.lock();
Eric Laurent421ddc02011-03-07 14:52:59 -0800528 if (result == DEAD_OBJECT) {
Eric Laurentae29b762011-03-28 18:37:07 -0700529 android_atomic_or(CBLK_INVALID_ON, &cblk->flags);
Eric Laurent421ddc02011-03-07 14:52:59 -0800530create_new_record:
531 result = AudioRecord::restoreRecord_l(cblk);
532 }
533 if (result != NO_ERROR) {
534 LOGW("obtainBuffer create Track error %d", result);
535 cblk->lock.unlock();
536 return result;
537 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800538 cblk->waitTimeMs = 0;
539 }
540 if (--waitCount == 0) {
Eric Laurentbda74692009-11-04 08:27:26 -0800541 cblk->lock.unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800542 return TIMED_OUT;
543 }
544 }
545 // read the server count again
546 start_loop_here:
547 framesReady = cblk->framesReady();
548 }
Eric Laurentbda74692009-11-04 08:27:26 -0800549 cblk->lock.unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800550 }
551
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800552 cblk->waitTimeMs = 0;
Eric Laurenta553c252009-07-17 12:17:14 -0700553
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800554 if (framesReq > framesReady) {
555 framesReq = framesReady;
556 }
557
558 uint32_t u = cblk->user;
559 uint32_t bufferEnd = cblk->userBase + cblk->frameCount;
560
561 if (u + framesReq > bufferEnd) {
562 framesReq = bufferEnd - u;
563 }
564
565 audioBuffer->flags = 0;
566 audioBuffer->channelCount= mChannelCount;
567 audioBuffer->format = mFormat;
568 audioBuffer->frameCount = framesReq;
Eric Laurenta553c252009-07-17 12:17:14 -0700569 audioBuffer->size = framesReq*cblk->frameSize;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800570 audioBuffer->raw = (int8_t*)cblk->buffer(u);
571 active = mActive;
572 return active ? status_t(NO_ERROR) : status_t(STOPPED);
573}
574
575void AudioRecord::releaseBuffer(Buffer* audioBuffer)
576{
Eric Laurent421ddc02011-03-07 14:52:59 -0800577 AutoMutex lock(mLock);
578 mCblk->stepUser(audioBuffer->frameCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800579}
580
Eric Laurent49f02be2009-11-19 09:00:56 -0800581audio_io_handle_t AudioRecord::getInput()
582{
Eric Laurent421ddc02011-03-07 14:52:59 -0800583 AutoMutex lock(mLock);
584 return getInput_l();
585}
586
587// must be called with mLock held
588audio_io_handle_t AudioRecord::getInput_l()
589{
Eric Laurent47d0a922010-02-26 02:47:27 -0800590 mInput = AudioSystem::getInput(mInputSource,
Eric Laurent49f02be2009-11-19 09:00:56 -0800591 mCblk->sampleRate,
592 mFormat, mChannels,
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700593 (audio_in_acoustics_t)mFlags);
Eric Laurent47d0a922010-02-26 02:47:27 -0800594 return mInput;
Eric Laurent49f02be2009-11-19 09:00:56 -0800595}
596
Eric Laurent65b65452010-06-01 23:49:17 -0700597int AudioRecord::getSessionId()
598{
599 return mSessionId;
600}
601
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800602// -------------------------------------------------------------------------
603
604ssize_t AudioRecord::read(void* buffer, size_t userSize)
605{
606 ssize_t read = 0;
607 Buffer audioBuffer;
608 int8_t *dst = static_cast<int8_t*>(buffer);
609
610 if (ssize_t(userSize) < 0) {
611 // sanity-check. user is most-likely passing an error code.
612 LOGE("AudioRecord::read(buffer=%p, size=%u (%d)",
613 buffer, userSize, userSize);
614 return BAD_VALUE;
615 }
616
Eric Laurent421ddc02011-03-07 14:52:59 -0800617 mLock.lock();
618 // acquire a strong reference on the IAudioRecord and IMemory so that they cannot be destroyed
619 // while we are accessing the cblk
620 sp <IAudioRecord> audioRecord = mAudioRecord;
621 sp <IMemory> iMem = mCblkMemory;
622 mLock.unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800623
624 do {
625
Eric Laurenta553c252009-07-17 12:17:14 -0700626 audioBuffer.frameCount = userSize/frameSize();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800627
Eric Laurentba8811f2010-03-02 18:38:06 -0800628 // By using a wait count corresponding to twice the timeout period in
629 // obtainBuffer() we give a chance to recover once for a read timeout
630 // (if media_server crashed for instance) before returning a length of
631 // 0 bytes read to the client
632 status_t err = obtainBuffer(&audioBuffer, ((2 * MAX_RUN_TIMEOUT_MS) / WAIT_PERIOD_MS));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800633 if (err < 0) {
634 // out of buffers, return #bytes written
635 if (err == status_t(NO_MORE_BUFFERS))
636 break;
Eric Laurentba8811f2010-03-02 18:38:06 -0800637 if (err == status_t(TIMED_OUT))
638 err = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800639 return ssize_t(err);
640 }
641
642 size_t bytesRead = audioBuffer.size;
643 memcpy(dst, audioBuffer.i8, bytesRead);
644
645 dst += bytesRead;
646 userSize -= bytesRead;
647 read += bytesRead;
648
649 releaseBuffer(&audioBuffer);
650 } while (userSize);
651
652 return read;
653}
654
655// -------------------------------------------------------------------------
656
657bool AudioRecord::processAudioBuffer(const sp<ClientRecordThread>& thread)
658{
659 Buffer audioBuffer;
660 uint32_t frames = mRemainingFrames;
661 size_t readSize;
662
Eric Laurent421ddc02011-03-07 14:52:59 -0800663 mLock.lock();
664 // acquire a strong reference on the IAudioRecord and IMemory so that they cannot be destroyed
665 // while we are accessing the cblk
666 sp <IAudioRecord> audioRecord = mAudioRecord;
667 sp <IMemory> iMem = mCblkMemory;
668 audio_track_cblk_t* cblk = mCblk;
669 mLock.unlock();
670
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800671 // Manage marker callback
Jean-Michel Trivi78c13142009-03-24 19:48:58 -0700672 if (!mMarkerReached && (mMarkerPosition > 0)) {
Eric Laurent421ddc02011-03-07 14:52:59 -0800673 if (cblk->user >= mMarkerPosition) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800674 mCbf(EVENT_MARKER, mUserData, (void *)&mMarkerPosition);
Jean-Michel Trivi78c13142009-03-24 19:48:58 -0700675 mMarkerReached = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800676 }
677 }
678
679 // Manage new position callback
680 if (mUpdatePeriod > 0) {
Eric Laurent421ddc02011-03-07 14:52:59 -0800681 while (cblk->user >= mNewPosition) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800682 mCbf(EVENT_NEW_POS, mUserData, (void *)&mNewPosition);
683 mNewPosition += mUpdatePeriod;
684 }
685 }
686
687 do {
688 audioBuffer.frameCount = frames;
Eric Laurenta553c252009-07-17 12:17:14 -0700689 // Calling obtainBuffer() with a wait count of 1
690 // limits wait time to WAIT_PERIOD_MS. This prevents from being
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800691 // stuck here not being able to handle timed events (position, markers).
692 status_t err = obtainBuffer(&audioBuffer, 1);
693 if (err < NO_ERROR) {
694 if (err != TIMED_OUT) {
Eric Laurentef028272009-04-21 07:56:33 -0700695 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 -0800696 return false;
697 }
698 break;
699 }
700 if (err == status_t(STOPPED)) return false;
701
702 size_t reqSize = audioBuffer.size;
703 mCbf(EVENT_MORE_DATA, mUserData, &audioBuffer);
704 readSize = audioBuffer.size;
705
706 // Sanity check on returned size
Eric Laurent272beb62009-03-24 21:23:54 -0700707 if (ssize_t(readSize) <= 0) {
708 // The callback is done filling buffers
709 // Keep this thread going to handle timed events and
710 // still try to get more data in intervals of WAIT_PERIOD_MS
711 // but don't just loop and block the CPU, so wait
712 usleep(WAIT_PERIOD_MS*1000);
713 break;
714 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800715 if (readSize > reqSize) readSize = reqSize;
716
717 audioBuffer.size = readSize;
Eric Laurenta553c252009-07-17 12:17:14 -0700718 audioBuffer.frameCount = readSize/frameSize();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800719 frames -= audioBuffer.frameCount;
720
721 releaseBuffer(&audioBuffer);
722
723 } while (frames);
724
Eric Laurenta553c252009-07-17 12:17:14 -0700725
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800726 // Manage overrun callback
Eric Laurent421ddc02011-03-07 14:52:59 -0800727 if (mActive && (cblk->framesAvailable() == 0)) {
728 LOGV("Overrun user: %x, server: %x, flags %04x", cblk->user, cblk->server, cblk->flags);
Eric Laurentae29b762011-03-28 18:37:07 -0700729 if (!(android_atomic_or(CBLK_UNDERRUN_ON, &cblk->flags) & CBLK_UNDERRUN_MSK)) {
Eric Laurent913af0b2011-03-17 09:36:51 -0700730 mCbf(EVENT_OVERRUN, mUserData, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800731 }
732 }
733
734 if (frames == 0) {
735 mRemainingFrames = mNotificationFrames;
736 } else {
737 mRemainingFrames = frames;
738 }
739 return true;
740}
741
Eric Laurent421ddc02011-03-07 14:52:59 -0800742// must be called with mLock and cblk.lock held. Callers must also hold strong references on
743// the IAudioRecord and IMemory in case they are recreated here.
744// If the IAudioRecord is successfully restored, the cblk pointer is updated
745status_t AudioRecord::restoreRecord_l(audio_track_cblk_t*& cblk)
746{
747 status_t result;
748
Eric Laurentae29b762011-03-28 18:37:07 -0700749 if (!(android_atomic_or(CBLK_RESTORING_ON, &cblk->flags) & CBLK_RESTORING_MSK)) {
Eric Laurent421ddc02011-03-07 14:52:59 -0800750 LOGW("dead IAudioRecord, creating a new one");
Eric Laurent421ddc02011-03-07 14:52:59 -0800751 // signal old cblk condition so that other threads waiting for available buffers stop
752 // waiting now
753 cblk->cv.broadcast();
754 cblk->lock.unlock();
755
756 // if the new IAudioRecord is created, openRecord_l() will modify the
757 // following member variables: mAudioRecord, mCblkMemory and mCblk.
758 // It will also delete the strong references on previous IAudioRecord and IMemory
759 result = openRecord_l(cblk->sampleRate, mFormat, mChannelCount,
760 mFrameCount, mFlags, getInput_l());
761 if (result == NO_ERROR) {
762 result = mAudioRecord->start();
763 }
764 if (result != NO_ERROR) {
765 mActive = false;
766 }
767
768 // signal old cblk condition for other threads waiting for restore completion
Eric Laurentae29b762011-03-28 18:37:07 -0700769 android_atomic_or(CBLK_RESTORED_ON, &cblk->flags);
Eric Laurent421ddc02011-03-07 14:52:59 -0800770 cblk->cv.broadcast();
Eric Laurent421ddc02011-03-07 14:52:59 -0800771 } else {
772 if (!(cblk->flags & CBLK_RESTORED_MSK)) {
773 LOGW("dead IAudioRecord, waiting for a new one to be created");
774 mLock.unlock();
775 result = cblk->cv.waitRelative(cblk->lock, milliseconds(RESTORE_TIMEOUT_MS));
776 cblk->lock.unlock();
777 mLock.lock();
778 } else {
779 LOGW("dead IAudioRecord, already restored");
780 result = NO_ERROR;
781 cblk->lock.unlock();
782 }
783 if (result != NO_ERROR || mActive == 0) {
784 result = status_t(STOPPED);
785 }
786 }
787 LOGV("restoreRecord_l() status %d mActive %d cblk %p, old cblk %p flags %08x old flags %08x",
788 result, mActive, mCblk, cblk, mCblk->flags, cblk->flags);
789
790 if (result == NO_ERROR) {
791 // from now on we switch to the newly created cblk
792 cblk = mCblk;
793 }
794 cblk->lock.lock();
795
796 LOGW_IF(result != NO_ERROR, "restoreRecord_l() error %d", result);
797
798 return result;
799}
800
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800801// =========================================================================
802
803AudioRecord::ClientRecordThread::ClientRecordThread(AudioRecord& receiver, bool bCanCallJava)
804 : Thread(bCanCallJava), mReceiver(receiver)
805{
806}
807
808bool AudioRecord::ClientRecordThread::threadLoop()
809{
810 return mReceiver.processAudioBuffer(this);
811}
812
813// -------------------------------------------------------------------------
814
815}; // namespace android
816