blob: f32929ef27f3364767c6c24b1e385c2d0ca49463 [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 Zavin34bb4192011-05-11 14:15:23 -070040#include <system/audio.h>
Dima Zavin24fc2fb2011-04-19 22:30:36 -070041#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)) {
Eric Laurentc310dcb2011-06-16 21:30:45 -070073 size /= channelCount * audio_bytes_per_sample(format);
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,
Jean-Michel Trivi54392232011-05-24 15:53:33 -070091 uint32_t channelMask,
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{
Jean-Michel Trivi54392232011-05-24 15:53:33 -0700100 mStatus = set(inputSource, sampleRate, format, channelMask,
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();
Marco Nelissenc74b93f2011-08-02 13:33:41 -0700117 AudioSystem::releaseAudioSessionId(mSessionId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800118 }
119}
120
121status_t AudioRecord::set(
Eric Laurent4bc035a2009-05-22 09:18:15 -0700122 int inputSource,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800123 uint32_t sampleRate,
124 int format,
Jean-Michel Trivi54392232011-05-24 15:53:33 -0700125 uint32_t channelMask,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126 int frameCount,
127 uint32_t flags,
128 callback_t cbf,
129 void* user,
130 int notificationFrames,
Eric Laurent65b65452010-06-01 23:49:17 -0700131 bool threadCanCallJava,
132 int sessionId)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133{
134
Steve Block71f2cf12011-10-20 11:56:00 +0100135 ALOGV("set(): sampleRate %d, channelMask %d, frameCount %d",sampleRate, channelMask, frameCount);
Eric Laurent421ddc02011-03-07 14:52:59 -0800136
137 AutoMutex lock(mLock);
138
Eric Laurentef028272009-04-21 07:56:33 -0700139 if (mAudioRecord != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140 return INVALID_OPERATION;
141 }
142
Eric Laurenta553c252009-07-17 12:17:14 -0700143 if (inputSource == AUDIO_SOURCE_DEFAULT) {
144 inputSource = AUDIO_SOURCE_MIC;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800145 }
146
147 if (sampleRate == 0) {
148 sampleRate = DEFAULT_SAMPLE_RATE;
149 }
150 // these below should probably come from the audioFlinger too...
151 if (format == 0) {
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700152 format = AUDIO_FORMAT_PCM_16_BIT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800153 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800154 // validate parameters
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700155 if (!audio_is_valid_format(format)) {
Eric Laurenta553c252009-07-17 12:17:14 -0700156 LOGE("Invalid format");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800157 return BAD_VALUE;
158 }
Eric Laurenta553c252009-07-17 12:17:14 -0700159
Jean-Michel Trivi54392232011-05-24 15:53:33 -0700160 if (!audio_is_input_channel(channelMask)) {
Eric Laurenta553c252009-07-17 12:17:14 -0700161 return BAD_VALUE;
162 }
Eric Laurent65b65452010-06-01 23:49:17 -0700163
Jean-Michel Trivi54392232011-05-24 15:53:33 -0700164 int channelCount = popcount(channelMask);
Eric Laurenta553c252009-07-17 12:17:14 -0700165
Eric Laurent464d5b32011-06-17 21:29:58 -0700166 if (sessionId == 0 ) {
167 mSessionId = AudioSystem::newAudioSessionId();
168 } else {
169 mSessionId = sessionId;
170 }
Steve Block71f2cf12011-10-20 11:56:00 +0100171 ALOGV("set(): mSessionId %d", mSessionId);
Eric Laurent464d5b32011-06-17 21:29:58 -0700172
Eric Laurent49f02be2009-11-19 09:00:56 -0800173 audio_io_handle_t input = AudioSystem::getInput(inputSource,
Eric Laurent464d5b32011-06-17 21:29:58 -0700174 sampleRate,
175 format,
176 channelMask,
177 (audio_in_acoustics_t)flags,
178 mSessionId);
Eric Laurent49f02be2009-11-19 09:00:56 -0800179 if (input == 0) {
Eric Laurent9cc489a22009-12-05 05:20:01 -0800180 LOGE("Could not get audio input for record source %d", inputSource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800181 return BAD_VALUE;
182 }
183
184 // validate framecount
Chia-chi Yeh97d61f72010-06-22 08:01:13 +0800185 int minFrameCount = 0;
186 status_t status = getMinFrameCount(&minFrameCount, sampleRate, format, channelCount);
187 if (status != NO_ERROR) {
188 return status;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800189 }
Steve Block71f2cf12011-10-20 11:56:00 +0100190 ALOGV("AudioRecord::set() minFrameCount = %d", minFrameCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800191
192 if (frameCount == 0) {
193 frameCount = minFrameCount;
194 } else if (frameCount < minFrameCount) {
195 return BAD_VALUE;
196 }
197
198 if (notificationFrames == 0) {
199 notificationFrames = frameCount/2;
200 }
201
Eric Laurentbda74692009-11-04 08:27:26 -0800202 // create the IAudioRecord
Jean-Michel Trivi54392232011-05-24 15:53:33 -0700203 status = openRecord_l(sampleRate, format, channelMask,
Chia-chi Yeh97d61f72010-06-22 08:01:13 +0800204 frameCount, flags, input);
Eric Laurentbda74692009-11-04 08:27:26 -0800205 if (status != NO_ERROR) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800206 return status;
207 }
Eric Laurentbda74692009-11-04 08:27:26 -0800208
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800209 if (cbf != 0) {
210 mClientRecordThread = new ClientRecordThread(*this, threadCanCallJava);
211 if (mClientRecordThread == 0) {
212 return NO_INIT;
213 }
214 }
215
216 mStatus = NO_ERROR;
217
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800218 mFormat = format;
219 // Update buffer size in case it has been limited by AudioFlinger during track creation
220 mFrameCount = mCblk->frameCount;
Eric Laurenta553c252009-07-17 12:17:14 -0700221 mChannelCount = (uint8_t)channelCount;
Jean-Michel Trivi54392232011-05-24 15:53:33 -0700222 mChannelMask = channelMask;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800223 mActive = 0;
224 mCbf = cbf;
225 mNotificationFrames = notificationFrames;
226 mRemainingFrames = notificationFrames;
227 mUserData = user;
228 // TODO: add audio hardware input latency here
Eric Laurent88e209d2009-07-07 07:10:45 -0700229 mLatency = (1000*mFrameCount) / sampleRate;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800230 mMarkerPosition = 0;
Jean-Michel Trivi78c13142009-03-24 19:48:58 -0700231 mMarkerReached = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800232 mNewPosition = 0;
233 mUpdatePeriod = 0;
Eric Laurent4bc035a2009-05-22 09:18:15 -0700234 mInputSource = (uint8_t)inputSource;
Eric Laurentbda74692009-11-04 08:27:26 -0800235 mFlags = flags;
Eric Laurent47d0a922010-02-26 02:47:27 -0800236 mInput = input;
Marco Nelissenc74b93f2011-08-02 13:33:41 -0700237 AudioSystem::acquireAudioSessionId(mSessionId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800238
239 return NO_ERROR;
240}
241
242status_t AudioRecord::initCheck() const
243{
244 return mStatus;
245}
246
247// -------------------------------------------------------------------------
248
249uint32_t AudioRecord::latency() const
250{
251 return mLatency;
252}
253
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800254int AudioRecord::format() const
255{
256 return mFormat;
257}
258
259int AudioRecord::channelCount() const
260{
261 return mChannelCount;
262}
263
264uint32_t AudioRecord::frameCount() const
265{
266 return mFrameCount;
267}
268
269int AudioRecord::frameSize() const
270{
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700271 if (audio_is_linear_pcm(mFormat)) {
Eric Laurentc310dcb2011-06-16 21:30:45 -0700272 return channelCount()*audio_bytes_per_sample(mFormat);
Eric Laurenta553c252009-07-17 12:17:14 -0700273 } else {
274 return sizeof(uint8_t);
275 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800276}
277
Eric Laurent4bc035a2009-05-22 09:18:15 -0700278int AudioRecord::inputSource() const
279{
280 return (int)mInputSource;
281}
282
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800283// -------------------------------------------------------------------------
284
285status_t AudioRecord::start()
286{
287 status_t ret = NO_ERROR;
288 sp<ClientRecordThread> t = mClientRecordThread;
289
Steve Block71f2cf12011-10-20 11:56:00 +0100290 ALOGV("start");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800291
292 if (t != 0) {
293 if (t->exitPending()) {
294 if (t->requestExitAndWait() == WOULD_BLOCK) {
295 LOGE("AudioRecord::start called from thread");
296 return WOULD_BLOCK;
297 }
298 }
299 t->mLock.lock();
300 }
301
Eric Laurentf3d6dd02010-11-18 08:40:16 -0800302 AutoMutex lock(mLock);
Eric Laurent421ddc02011-03-07 14:52:59 -0800303 // acquire a strong reference on the IAudioRecord and IMemory so that they cannot be destroyed
304 // while we are accessing the cblk
305 sp <IAudioRecord> audioRecord = mAudioRecord;
306 sp <IMemory> iMem = mCblkMemory;
307 audio_track_cblk_t* cblk = mCblk;
Eric Laurentf3d6dd02010-11-18 08:40:16 -0800308 if (mActive == 0) {
309 mActive = 1;
Eric Laurent421ddc02011-03-07 14:52:59 -0800310
311 cblk->lock.lock();
312 if (!(cblk->flags & CBLK_INVALID_MSK)) {
313 cblk->lock.unlock();
314 ret = mAudioRecord->start();
315 cblk->lock.lock();
316 if (ret == DEAD_OBJECT) {
Eric Laurentae29b762011-03-28 18:37:07 -0700317 android_atomic_or(CBLK_INVALID_ON, &cblk->flags);
Eric Laurentbda74692009-11-04 08:27:26 -0800318 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800319 }
Eric Laurent421ddc02011-03-07 14:52:59 -0800320 if (cblk->flags & CBLK_INVALID_MSK) {
321 ret = restoreRecord_l(cblk);
322 }
323 cblk->lock.unlock();
Eric Laurent49f02be2009-11-19 09:00:56 -0800324 if (ret == NO_ERROR) {
Eric Laurent421ddc02011-03-07 14:52:59 -0800325 mNewPosition = cblk->user + mUpdatePeriod;
326 cblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
327 cblk->waitTimeMs = 0;
Eric Laurent49f02be2009-11-19 09:00:56 -0800328 if (t != 0) {
Glenn Kasten993fcce2011-06-01 16:46:29 -0700329 t->run("ClientRecordThread", ANDROID_PRIORITY_AUDIO);
Eric Laurent49f02be2009-11-19 09:00:56 -0800330 } else {
Glenn Kasten993fcce2011-06-01 16:46:29 -0700331 setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO);
Eric Laurent49f02be2009-11-19 09:00:56 -0800332 }
333 } else {
Eric Laurentf3d6dd02010-11-18 08:40:16 -0800334 mActive = 0;
Eric Laurent49f02be2009-11-19 09:00:56 -0800335 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800336 }
337
338 if (t != 0) {
339 t->mLock.unlock();
340 }
341
342 return ret;
343}
344
345status_t AudioRecord::stop()
346{
347 sp<ClientRecordThread> t = mClientRecordThread;
348
Steve Block71f2cf12011-10-20 11:56:00 +0100349 ALOGV("stop");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800350
351 if (t != 0) {
352 t->mLock.lock();
Eric Laurentf3d6dd02010-11-18 08:40:16 -0800353 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800354
Eric Laurentf3d6dd02010-11-18 08:40:16 -0800355 AutoMutex lock(mLock);
356 if (mActive == 1) {
357 mActive = 0;
Eric Laurentef028272009-04-21 07:56:33 -0700358 mCblk->cv.signal();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800359 mAudioRecord->stop();
Jean-Michel Trivi78c13142009-03-24 19:48:58 -0700360 // the record head position will reset to 0, so if a marker is set, we need
361 // to activate it again
362 mMarkerReached = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800363 if (t != 0) {
364 t->requestExit();
365 } else {
366 setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL);
367 }
368 }
369
370 if (t != 0) {
371 t->mLock.unlock();
372 }
373
374 return NO_ERROR;
375}
376
377bool AudioRecord::stopped() const
378{
379 return !mActive;
380}
381
Eric Laurent88e209d2009-07-07 07:10:45 -0700382uint32_t AudioRecord::getSampleRate()
383{
Eric Laurent421ddc02011-03-07 14:52:59 -0800384 AutoMutex lock(mLock);
Eric Laurent88e209d2009-07-07 07:10:45 -0700385 return mCblk->sampleRate;
386}
387
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800388status_t AudioRecord::setMarkerPosition(uint32_t marker)
389{
390 if (mCbf == 0) return INVALID_OPERATION;
391
392 mMarkerPosition = marker;
Jean-Michel Trivi78c13142009-03-24 19:48:58 -0700393 mMarkerReached = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800394
395 return NO_ERROR;
396}
397
398status_t AudioRecord::getMarkerPosition(uint32_t *marker)
399{
400 if (marker == 0) return BAD_VALUE;
401
402 *marker = mMarkerPosition;
403
404 return NO_ERROR;
405}
406
407status_t AudioRecord::setPositionUpdatePeriod(uint32_t updatePeriod)
408{
409 if (mCbf == 0) return INVALID_OPERATION;
410
411 uint32_t curPosition;
412 getPosition(&curPosition);
413 mNewPosition = curPosition + updatePeriod;
414 mUpdatePeriod = updatePeriod;
415
416 return NO_ERROR;
417}
418
419status_t AudioRecord::getPositionUpdatePeriod(uint32_t *updatePeriod)
420{
421 if (updatePeriod == 0) return BAD_VALUE;
422
423 *updatePeriod = mUpdatePeriod;
424
425 return NO_ERROR;
426}
427
428status_t AudioRecord::getPosition(uint32_t *position)
429{
430 if (position == 0) return BAD_VALUE;
431
Eric Laurent421ddc02011-03-07 14:52:59 -0800432 AutoMutex lock(mLock);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800433 *position = mCblk->user;
434
435 return NO_ERROR;
436}
437
Eric Laurent47d0a922010-02-26 02:47:27 -0800438unsigned int AudioRecord::getInputFramesLost()
439{
440 if (mActive)
441 return AudioSystem::getInputFramesLost(mInput);
442 else
443 return 0;
444}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800445
446// -------------------------------------------------------------------------
447
Eric Laurent421ddc02011-03-07 14:52:59 -0800448// must be called with mLock held
449status_t AudioRecord::openRecord_l(
Eric Laurentbda74692009-11-04 08:27:26 -0800450 uint32_t sampleRate,
Jean-Michel Trivi54392232011-05-24 15:53:33 -0700451 uint32_t format,
452 uint32_t channelMask,
Eric Laurentbda74692009-11-04 08:27:26 -0800453 int frameCount,
Eric Laurent49f02be2009-11-19 09:00:56 -0800454 uint32_t flags,
455 audio_io_handle_t input)
Eric Laurentbda74692009-11-04 08:27:26 -0800456{
457 status_t status;
458 const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
459 if (audioFlinger == 0) {
460 return NO_INIT;
461 }
462
Eric Laurent49f02be2009-11-19 09:00:56 -0800463 sp<IAudioRecord> record = audioFlinger->openRecord(getpid(), input,
Eric Laurentbda74692009-11-04 08:27:26 -0800464 sampleRate, format,
Jean-Michel Trivi54392232011-05-24 15:53:33 -0700465 channelMask,
Eric Laurentbda74692009-11-04 08:27:26 -0800466 frameCount,
467 ((uint16_t)flags) << 16,
Eric Laurent65b65452010-06-01 23:49:17 -0700468 &mSessionId,
Eric Laurentbda74692009-11-04 08:27:26 -0800469 &status);
Marco Nelissenc74b93f2011-08-02 13:33:41 -0700470
Eric Laurentbda74692009-11-04 08:27:26 -0800471 if (record == 0) {
472 LOGE("AudioFlinger could not create record track, status: %d", status);
473 return status;
474 }
475 sp<IMemory> cblk = record->getCblk();
476 if (cblk == 0) {
477 LOGE("Could not get control block");
478 return NO_INIT;
479 }
480 mAudioRecord.clear();
481 mAudioRecord = record;
482 mCblkMemory.clear();
483 mCblkMemory = cblk;
484 mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer());
485 mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
Eric Laurentae29b762011-03-28 18:37:07 -0700486 android_atomic_and(~CBLK_DIRECTION_MSK, &mCblk->flags);
Eric Laurent49f02be2009-11-19 09:00:56 -0800487 mCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
488 mCblk->waitTimeMs = 0;
Eric Laurentbda74692009-11-04 08:27:26 -0800489 return NO_ERROR;
490}
491
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800492status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
493{
Eric Laurent421ddc02011-03-07 14:52:59 -0800494 AutoMutex lock(mLock);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800495 int active;
Glenn Kasten028ab992011-06-22 16:18:04 -0700496 status_t result = NO_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800497 audio_track_cblk_t* cblk = mCblk;
498 uint32_t framesReq = audioBuffer->frameCount;
Eric Laurentef028272009-04-21 07:56:33 -0700499 uint32_t waitTimeMs = (waitCount < 0) ? cblk->bufferTimeoutMs : WAIT_PERIOD_MS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800500
501 audioBuffer->frameCount = 0;
502 audioBuffer->size = 0;
503
504 uint32_t framesReady = cblk->framesReady();
505
506 if (framesReady == 0) {
Eric Laurentbda74692009-11-04 08:27:26 -0800507 cblk->lock.lock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800508 goto start_loop_here;
509 while (framesReady == 0) {
510 active = mActive;
Eric Laurentbda74692009-11-04 08:27:26 -0800511 if (UNLIKELY(!active)) {
512 cblk->lock.unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800513 return NO_MORE_BUFFERS;
Eric Laurentbda74692009-11-04 08:27:26 -0800514 }
515 if (UNLIKELY(!waitCount)) {
516 cblk->lock.unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800517 return WOULD_BLOCK;
Eric Laurentbda74692009-11-04 08:27:26 -0800518 }
Eric Laurent421ddc02011-03-07 14:52:59 -0800519 if (!(cblk->flags & CBLK_INVALID_MSK)) {
520 mLock.unlock();
521 result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs));
522 cblk->lock.unlock();
523 mLock.lock();
524 if (mActive == 0) {
525 return status_t(STOPPED);
526 }
527 cblk->lock.lock();
528 }
529 if (cblk->flags & CBLK_INVALID_MSK) {
530 goto create_new_record;
531 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800532 if (__builtin_expect(result!=NO_ERROR, false)) {
Eric Laurentef028272009-04-21 07:56:33 -0700533 cblk->waitTimeMs += waitTimeMs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800534 if (cblk->waitTimeMs >= cblk->bufferTimeoutMs) {
535 LOGW( "obtainBuffer timed out (is the CPU pegged?) "
536 "user=%08x, server=%08x", cblk->user, cblk->server);
Eric Laurentbda74692009-11-04 08:27:26 -0800537 cblk->lock.unlock();
538 result = mAudioRecord->start();
Eric Laurentbda74692009-11-04 08:27:26 -0800539 cblk->lock.lock();
Eric Laurent421ddc02011-03-07 14:52:59 -0800540 if (result == DEAD_OBJECT) {
Eric Laurentae29b762011-03-28 18:37:07 -0700541 android_atomic_or(CBLK_INVALID_ON, &cblk->flags);
Eric Laurent421ddc02011-03-07 14:52:59 -0800542create_new_record:
543 result = AudioRecord::restoreRecord_l(cblk);
544 }
545 if (result != NO_ERROR) {
546 LOGW("obtainBuffer create Track error %d", result);
547 cblk->lock.unlock();
548 return result;
549 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800550 cblk->waitTimeMs = 0;
551 }
552 if (--waitCount == 0) {
Eric Laurentbda74692009-11-04 08:27:26 -0800553 cblk->lock.unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800554 return TIMED_OUT;
555 }
556 }
557 // read the server count again
558 start_loop_here:
559 framesReady = cblk->framesReady();
560 }
Eric Laurentbda74692009-11-04 08:27:26 -0800561 cblk->lock.unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800562 }
563
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800564 cblk->waitTimeMs = 0;
Eric Laurenta553c252009-07-17 12:17:14 -0700565
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800566 if (framesReq > framesReady) {
567 framesReq = framesReady;
568 }
569
570 uint32_t u = cblk->user;
571 uint32_t bufferEnd = cblk->userBase + cblk->frameCount;
572
573 if (u + framesReq > bufferEnd) {
574 framesReq = bufferEnd - u;
575 }
576
577 audioBuffer->flags = 0;
578 audioBuffer->channelCount= mChannelCount;
579 audioBuffer->format = mFormat;
580 audioBuffer->frameCount = framesReq;
Eric Laurenta553c252009-07-17 12:17:14 -0700581 audioBuffer->size = framesReq*cblk->frameSize;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800582 audioBuffer->raw = (int8_t*)cblk->buffer(u);
583 active = mActive;
584 return active ? status_t(NO_ERROR) : status_t(STOPPED);
585}
586
587void AudioRecord::releaseBuffer(Buffer* audioBuffer)
588{
Eric Laurent421ddc02011-03-07 14:52:59 -0800589 AutoMutex lock(mLock);
590 mCblk->stepUser(audioBuffer->frameCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800591}
592
Eric Laurent49f02be2009-11-19 09:00:56 -0800593audio_io_handle_t AudioRecord::getInput()
594{
Eric Laurent421ddc02011-03-07 14:52:59 -0800595 AutoMutex lock(mLock);
Eric Laurent678cc952011-07-26 20:32:28 -0700596 return mInput;
Eric Laurent421ddc02011-03-07 14:52:59 -0800597}
598
599// must be called with mLock held
600audio_io_handle_t AudioRecord::getInput_l()
601{
Eric Laurent47d0a922010-02-26 02:47:27 -0800602 mInput = AudioSystem::getInput(mInputSource,
Eric Laurent49f02be2009-11-19 09:00:56 -0800603 mCblk->sampleRate,
Eric Laurent464d5b32011-06-17 21:29:58 -0700604 mFormat,
605 mChannelMask,
606 (audio_in_acoustics_t)mFlags,
607 mSessionId);
Eric Laurent47d0a922010-02-26 02:47:27 -0800608 return mInput;
Eric Laurent49f02be2009-11-19 09:00:56 -0800609}
610
Eric Laurent65b65452010-06-01 23:49:17 -0700611int AudioRecord::getSessionId()
612{
613 return mSessionId;
614}
615
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800616// -------------------------------------------------------------------------
617
618ssize_t AudioRecord::read(void* buffer, size_t userSize)
619{
620 ssize_t read = 0;
621 Buffer audioBuffer;
622 int8_t *dst = static_cast<int8_t*>(buffer);
623
624 if (ssize_t(userSize) < 0) {
625 // sanity-check. user is most-likely passing an error code.
626 LOGE("AudioRecord::read(buffer=%p, size=%u (%d)",
627 buffer, userSize, userSize);
628 return BAD_VALUE;
629 }
630
Eric Laurent421ddc02011-03-07 14:52:59 -0800631 mLock.lock();
632 // acquire a strong reference on the IAudioRecord and IMemory so that they cannot be destroyed
633 // while we are accessing the cblk
634 sp <IAudioRecord> audioRecord = mAudioRecord;
635 sp <IMemory> iMem = mCblkMemory;
636 mLock.unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800637
638 do {
639
Eric Laurenta553c252009-07-17 12:17:14 -0700640 audioBuffer.frameCount = userSize/frameSize();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800641
Eric Laurentba8811f2010-03-02 18:38:06 -0800642 // By using a wait count corresponding to twice the timeout period in
643 // obtainBuffer() we give a chance to recover once for a read timeout
644 // (if media_server crashed for instance) before returning a length of
645 // 0 bytes read to the client
646 status_t err = obtainBuffer(&audioBuffer, ((2 * MAX_RUN_TIMEOUT_MS) / WAIT_PERIOD_MS));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800647 if (err < 0) {
648 // out of buffers, return #bytes written
649 if (err == status_t(NO_MORE_BUFFERS))
650 break;
Eric Laurentba8811f2010-03-02 18:38:06 -0800651 if (err == status_t(TIMED_OUT))
652 err = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800653 return ssize_t(err);
654 }
655
656 size_t bytesRead = audioBuffer.size;
657 memcpy(dst, audioBuffer.i8, bytesRead);
658
659 dst += bytesRead;
660 userSize -= bytesRead;
661 read += bytesRead;
662
663 releaseBuffer(&audioBuffer);
664 } while (userSize);
665
666 return read;
667}
668
669// -------------------------------------------------------------------------
670
671bool AudioRecord::processAudioBuffer(const sp<ClientRecordThread>& thread)
672{
673 Buffer audioBuffer;
674 uint32_t frames = mRemainingFrames;
675 size_t readSize;
676
Eric Laurent421ddc02011-03-07 14:52:59 -0800677 mLock.lock();
678 // acquire a strong reference on the IAudioRecord and IMemory so that they cannot be destroyed
679 // while we are accessing the cblk
680 sp <IAudioRecord> audioRecord = mAudioRecord;
681 sp <IMemory> iMem = mCblkMemory;
682 audio_track_cblk_t* cblk = mCblk;
683 mLock.unlock();
684
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800685 // Manage marker callback
Jean-Michel Trivi78c13142009-03-24 19:48:58 -0700686 if (!mMarkerReached && (mMarkerPosition > 0)) {
Eric Laurent421ddc02011-03-07 14:52:59 -0800687 if (cblk->user >= mMarkerPosition) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800688 mCbf(EVENT_MARKER, mUserData, (void *)&mMarkerPosition);
Jean-Michel Trivi78c13142009-03-24 19:48:58 -0700689 mMarkerReached = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800690 }
691 }
692
693 // Manage new position callback
694 if (mUpdatePeriod > 0) {
Eric Laurent421ddc02011-03-07 14:52:59 -0800695 while (cblk->user >= mNewPosition) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800696 mCbf(EVENT_NEW_POS, mUserData, (void *)&mNewPosition);
697 mNewPosition += mUpdatePeriod;
698 }
699 }
700
701 do {
702 audioBuffer.frameCount = frames;
Eric Laurenta553c252009-07-17 12:17:14 -0700703 // Calling obtainBuffer() with a wait count of 1
704 // limits wait time to WAIT_PERIOD_MS. This prevents from being
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800705 // stuck here not being able to handle timed events (position, markers).
706 status_t err = obtainBuffer(&audioBuffer, 1);
707 if (err < NO_ERROR) {
708 if (err != TIMED_OUT) {
Eric Laurentef028272009-04-21 07:56:33 -0700709 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 -0800710 return false;
711 }
712 break;
713 }
714 if (err == status_t(STOPPED)) return false;
715
716 size_t reqSize = audioBuffer.size;
717 mCbf(EVENT_MORE_DATA, mUserData, &audioBuffer);
718 readSize = audioBuffer.size;
719
720 // Sanity check on returned size
Eric Laurent272beb62009-03-24 21:23:54 -0700721 if (ssize_t(readSize) <= 0) {
722 // The callback is done filling buffers
723 // Keep this thread going to handle timed events and
724 // still try to get more data in intervals of WAIT_PERIOD_MS
725 // but don't just loop and block the CPU, so wait
726 usleep(WAIT_PERIOD_MS*1000);
727 break;
728 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800729 if (readSize > reqSize) readSize = reqSize;
730
731 audioBuffer.size = readSize;
Eric Laurenta553c252009-07-17 12:17:14 -0700732 audioBuffer.frameCount = readSize/frameSize();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800733 frames -= audioBuffer.frameCount;
734
735 releaseBuffer(&audioBuffer);
736
737 } while (frames);
738
Eric Laurenta553c252009-07-17 12:17:14 -0700739
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800740 // Manage overrun callback
Eric Laurent421ddc02011-03-07 14:52:59 -0800741 if (mActive && (cblk->framesAvailable() == 0)) {
Steve Block71f2cf12011-10-20 11:56:00 +0100742 ALOGV("Overrun user: %x, server: %x, flags %04x", cblk->user, cblk->server, cblk->flags);
Eric Laurentae29b762011-03-28 18:37:07 -0700743 if (!(android_atomic_or(CBLK_UNDERRUN_ON, &cblk->flags) & CBLK_UNDERRUN_MSK)) {
Eric Laurent913af0b2011-03-17 09:36:51 -0700744 mCbf(EVENT_OVERRUN, mUserData, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800745 }
746 }
747
748 if (frames == 0) {
749 mRemainingFrames = mNotificationFrames;
750 } else {
751 mRemainingFrames = frames;
752 }
753 return true;
754}
755
Eric Laurent421ddc02011-03-07 14:52:59 -0800756// must be called with mLock and cblk.lock held. Callers must also hold strong references on
757// the IAudioRecord and IMemory in case they are recreated here.
758// If the IAudioRecord is successfully restored, the cblk pointer is updated
759status_t AudioRecord::restoreRecord_l(audio_track_cblk_t*& cblk)
760{
761 status_t result;
762
Eric Laurentae29b762011-03-28 18:37:07 -0700763 if (!(android_atomic_or(CBLK_RESTORING_ON, &cblk->flags) & CBLK_RESTORING_MSK)) {
Eric Laurent421ddc02011-03-07 14:52:59 -0800764 LOGW("dead IAudioRecord, creating a new one");
Eric Laurent421ddc02011-03-07 14:52:59 -0800765 // signal old cblk condition so that other threads waiting for available buffers stop
766 // waiting now
767 cblk->cv.broadcast();
768 cblk->lock.unlock();
769
770 // if the new IAudioRecord is created, openRecord_l() will modify the
771 // following member variables: mAudioRecord, mCblkMemory and mCblk.
772 // It will also delete the strong references on previous IAudioRecord and IMemory
Jean-Michel Trivi54392232011-05-24 15:53:33 -0700773 result = openRecord_l(cblk->sampleRate, mFormat, mChannelMask,
Eric Laurent421ddc02011-03-07 14:52:59 -0800774 mFrameCount, mFlags, getInput_l());
775 if (result == NO_ERROR) {
776 result = mAudioRecord->start();
777 }
778 if (result != NO_ERROR) {
779 mActive = false;
780 }
781
782 // signal old cblk condition for other threads waiting for restore completion
Eric Laurentae29b762011-03-28 18:37:07 -0700783 android_atomic_or(CBLK_RESTORED_ON, &cblk->flags);
Eric Laurent421ddc02011-03-07 14:52:59 -0800784 cblk->cv.broadcast();
Eric Laurent421ddc02011-03-07 14:52:59 -0800785 } else {
786 if (!(cblk->flags & CBLK_RESTORED_MSK)) {
787 LOGW("dead IAudioRecord, waiting for a new one to be created");
788 mLock.unlock();
789 result = cblk->cv.waitRelative(cblk->lock, milliseconds(RESTORE_TIMEOUT_MS));
790 cblk->lock.unlock();
791 mLock.lock();
792 } else {
793 LOGW("dead IAudioRecord, already restored");
794 result = NO_ERROR;
795 cblk->lock.unlock();
796 }
797 if (result != NO_ERROR || mActive == 0) {
798 result = status_t(STOPPED);
799 }
800 }
Steve Block71f2cf12011-10-20 11:56:00 +0100801 ALOGV("restoreRecord_l() status %d mActive %d cblk %p, old cblk %p flags %08x old flags %08x",
Eric Laurent421ddc02011-03-07 14:52:59 -0800802 result, mActive, mCblk, cblk, mCblk->flags, cblk->flags);
803
804 if (result == NO_ERROR) {
805 // from now on we switch to the newly created cblk
806 cblk = mCblk;
807 }
808 cblk->lock.lock();
809
810 LOGW_IF(result != NO_ERROR, "restoreRecord_l() error %d", result);
811
812 return result;
813}
814
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800815// =========================================================================
816
817AudioRecord::ClientRecordThread::ClientRecordThread(AudioRecord& receiver, bool bCanCallJava)
818 : Thread(bCanCallJava), mReceiver(receiver)
819{
820}
821
822bool AudioRecord::ClientRecordThread::threadLoop()
823{
824 return mReceiver.processAudioBuffer(this);
825}
826
827// -------------------------------------------------------------------------
828
829}; // namespace android
830