blob: 1d8e15bac77ebbb7a7faf40655e952cf28af2dae [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()
Glenn Kasten99d54432011-06-22 16:15:25 -070083 : mStatus(NO_INIT), mSessionId(0),
84 mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(ANDROID_TGROUP_DEFAULT)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085{
86}
87
88AudioRecord::AudioRecord(
Eric Laurent4bc035a2009-05-22 09:18:15 -070089 int inputSource,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090 uint32_t sampleRate,
91 int format,
Jean-Michel Trivi54392232011-05-24 15:53:33 -070092 uint32_t channelMask,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093 int frameCount,
94 uint32_t flags,
95 callback_t cbf,
96 void* user,
Eric Laurent65b65452010-06-01 23:49:17 -070097 int notificationFrames,
98 int sessionId)
Glenn Kasten99d54432011-06-22 16:15:25 -070099 : mStatus(NO_INIT), mSessionId(0),
100 mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(ANDROID_TGROUP_DEFAULT)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800101{
Jean-Michel Trivi54392232011-05-24 15:53:33 -0700102 mStatus = set(inputSource, sampleRate, format, channelMask,
Eric Laurent65b65452010-06-01 23:49:17 -0700103 frameCount, flags, cbf, user, notificationFrames, sessionId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104}
105
106AudioRecord::~AudioRecord()
107{
108 if (mStatus == NO_ERROR) {
109 // Make sure that callback function exits in the case where
110 // it is looping on buffer empty condition in obtainBuffer().
111 // Otherwise the callback thread will never exit.
112 stop();
113 if (mClientRecordThread != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800114 mClientRecordThread->requestExitAndWait();
115 mClientRecordThread.clear();
116 }
117 mAudioRecord.clear();
118 IPCThreadState::self()->flushCommands();
Marco Nelissenc74b93f2011-08-02 13:33:41 -0700119 AudioSystem::releaseAudioSessionId(mSessionId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800120 }
121}
122
123status_t AudioRecord::set(
Eric Laurent4bc035a2009-05-22 09:18:15 -0700124 int inputSource,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125 uint32_t sampleRate,
126 int format,
Jean-Michel Trivi54392232011-05-24 15:53:33 -0700127 uint32_t channelMask,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800128 int frameCount,
129 uint32_t flags,
130 callback_t cbf,
131 void* user,
132 int notificationFrames,
Eric Laurent65b65452010-06-01 23:49:17 -0700133 bool threadCanCallJava,
134 int sessionId)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800135{
136
Steve Block71f2cf12011-10-20 11:56:00 +0100137 ALOGV("set(): sampleRate %d, channelMask %d, frameCount %d",sampleRate, channelMask, frameCount);
Eric Laurent421ddc02011-03-07 14:52:59 -0800138
139 AutoMutex lock(mLock);
140
Eric Laurentef028272009-04-21 07:56:33 -0700141 if (mAudioRecord != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800142 return INVALID_OPERATION;
143 }
144
Eric Laurenta553c252009-07-17 12:17:14 -0700145 if (inputSource == AUDIO_SOURCE_DEFAULT) {
146 inputSource = AUDIO_SOURCE_MIC;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800147 }
148
149 if (sampleRate == 0) {
150 sampleRate = DEFAULT_SAMPLE_RATE;
151 }
152 // these below should probably come from the audioFlinger too...
153 if (format == 0) {
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700154 format = AUDIO_FORMAT_PCM_16_BIT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800155 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800156 // validate parameters
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700157 if (!audio_is_valid_format(format)) {
Eric Laurenta553c252009-07-17 12:17:14 -0700158 LOGE("Invalid format");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800159 return BAD_VALUE;
160 }
Eric Laurenta553c252009-07-17 12:17:14 -0700161
Jean-Michel Trivi54392232011-05-24 15:53:33 -0700162 if (!audio_is_input_channel(channelMask)) {
Eric Laurenta553c252009-07-17 12:17:14 -0700163 return BAD_VALUE;
164 }
Eric Laurent65b65452010-06-01 23:49:17 -0700165
Jean-Michel Trivi54392232011-05-24 15:53:33 -0700166 int channelCount = popcount(channelMask);
Eric Laurenta553c252009-07-17 12:17:14 -0700167
Eric Laurent464d5b32011-06-17 21:29:58 -0700168 if (sessionId == 0 ) {
169 mSessionId = AudioSystem::newAudioSessionId();
170 } else {
171 mSessionId = sessionId;
172 }
Steve Block71f2cf12011-10-20 11:56:00 +0100173 ALOGV("set(): mSessionId %d", mSessionId);
Eric Laurent464d5b32011-06-17 21:29:58 -0700174
Eric Laurent49f02be2009-11-19 09:00:56 -0800175 audio_io_handle_t input = AudioSystem::getInput(inputSource,
Eric Laurent464d5b32011-06-17 21:29:58 -0700176 sampleRate,
177 format,
178 channelMask,
179 (audio_in_acoustics_t)flags,
180 mSessionId);
Eric Laurent49f02be2009-11-19 09:00:56 -0800181 if (input == 0) {
Eric Laurent9cc489a2009-12-05 05:20:01 -0800182 LOGE("Could not get audio input for record source %d", inputSource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800183 return BAD_VALUE;
184 }
185
186 // validate framecount
Chia-chi Yeh97d61f72010-06-22 08:01:13 +0800187 int minFrameCount = 0;
188 status_t status = getMinFrameCount(&minFrameCount, sampleRate, format, channelCount);
189 if (status != NO_ERROR) {
190 return status;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800191 }
Steve Block71f2cf12011-10-20 11:56:00 +0100192 ALOGV("AudioRecord::set() minFrameCount = %d", minFrameCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800193
194 if (frameCount == 0) {
195 frameCount = minFrameCount;
196 } else if (frameCount < minFrameCount) {
197 return BAD_VALUE;
198 }
199
200 if (notificationFrames == 0) {
201 notificationFrames = frameCount/2;
202 }
203
Eric Laurentbda74692009-11-04 08:27:26 -0800204 // create the IAudioRecord
Jean-Michel Trivi54392232011-05-24 15:53:33 -0700205 status = openRecord_l(sampleRate, format, channelMask,
Chia-chi Yeh97d61f72010-06-22 08:01:13 +0800206 frameCount, flags, input);
Eric Laurentbda74692009-11-04 08:27:26 -0800207 if (status != NO_ERROR) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800208 return status;
209 }
Eric Laurentbda74692009-11-04 08:27:26 -0800210
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800211 if (cbf != 0) {
212 mClientRecordThread = new ClientRecordThread(*this, threadCanCallJava);
213 if (mClientRecordThread == 0) {
214 return NO_INIT;
215 }
216 }
217
218 mStatus = NO_ERROR;
219
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800220 mFormat = format;
221 // Update buffer size in case it has been limited by AudioFlinger during track creation
222 mFrameCount = mCblk->frameCount;
Eric Laurenta553c252009-07-17 12:17:14 -0700223 mChannelCount = (uint8_t)channelCount;
Jean-Michel Trivi54392232011-05-24 15:53:33 -0700224 mChannelMask = channelMask;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800225 mActive = 0;
226 mCbf = cbf;
227 mNotificationFrames = notificationFrames;
228 mRemainingFrames = notificationFrames;
229 mUserData = user;
230 // TODO: add audio hardware input latency here
Eric Laurent88e209d2009-07-07 07:10:45 -0700231 mLatency = (1000*mFrameCount) / sampleRate;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800232 mMarkerPosition = 0;
Jean-Michel Trivi78c13142009-03-24 19:48:58 -0700233 mMarkerReached = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800234 mNewPosition = 0;
235 mUpdatePeriod = 0;
Eric Laurent4bc035a2009-05-22 09:18:15 -0700236 mInputSource = (uint8_t)inputSource;
Eric Laurentbda74692009-11-04 08:27:26 -0800237 mFlags = flags;
Eric Laurent47d0a922010-02-26 02:47:27 -0800238 mInput = input;
Marco Nelissenc74b93f2011-08-02 13:33:41 -0700239 AudioSystem::acquireAudioSessionId(mSessionId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800240
241 return NO_ERROR;
242}
243
244status_t AudioRecord::initCheck() const
245{
246 return mStatus;
247}
248
249// -------------------------------------------------------------------------
250
251uint32_t AudioRecord::latency() const
252{
253 return mLatency;
254}
255
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800256int AudioRecord::format() const
257{
258 return mFormat;
259}
260
261int AudioRecord::channelCount() const
262{
263 return mChannelCount;
264}
265
266uint32_t AudioRecord::frameCount() const
267{
268 return mFrameCount;
269}
270
271int AudioRecord::frameSize() const
272{
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700273 if (audio_is_linear_pcm(mFormat)) {
Eric Laurentc310dcb2011-06-16 21:30:45 -0700274 return channelCount()*audio_bytes_per_sample(mFormat);
Eric Laurenta553c252009-07-17 12:17:14 -0700275 } else {
276 return sizeof(uint8_t);
277 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800278}
279
Eric Laurent4bc035a2009-05-22 09:18:15 -0700280int AudioRecord::inputSource() const
281{
282 return (int)mInputSource;
283}
284
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800285// -------------------------------------------------------------------------
286
287status_t AudioRecord::start()
288{
289 status_t ret = NO_ERROR;
290 sp<ClientRecordThread> t = mClientRecordThread;
291
Steve Block71f2cf12011-10-20 11:56:00 +0100292 ALOGV("start");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800293
294 if (t != 0) {
295 if (t->exitPending()) {
296 if (t->requestExitAndWait() == WOULD_BLOCK) {
297 LOGE("AudioRecord::start called from thread");
298 return WOULD_BLOCK;
299 }
300 }
301 t->mLock.lock();
302 }
303
Eric Laurentf3d6dd02010-11-18 08:40:16 -0800304 AutoMutex lock(mLock);
Eric Laurent421ddc02011-03-07 14:52:59 -0800305 // acquire a strong reference on the IAudioRecord and IMemory so that they cannot be destroyed
306 // while we are accessing the cblk
307 sp <IAudioRecord> audioRecord = mAudioRecord;
308 sp <IMemory> iMem = mCblkMemory;
309 audio_track_cblk_t* cblk = mCblk;
Eric Laurentf3d6dd02010-11-18 08:40:16 -0800310 if (mActive == 0) {
311 mActive = 1;
Eric Laurent421ddc02011-03-07 14:52:59 -0800312
313 cblk->lock.lock();
314 if (!(cblk->flags & CBLK_INVALID_MSK)) {
315 cblk->lock.unlock();
316 ret = mAudioRecord->start();
317 cblk->lock.lock();
318 if (ret == DEAD_OBJECT) {
Eric Laurentae29b762011-03-28 18:37:07 -0700319 android_atomic_or(CBLK_INVALID_ON, &cblk->flags);
Eric Laurentbda74692009-11-04 08:27:26 -0800320 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800321 }
Eric Laurent421ddc02011-03-07 14:52:59 -0800322 if (cblk->flags & CBLK_INVALID_MSK) {
323 ret = restoreRecord_l(cblk);
324 }
325 cblk->lock.unlock();
Eric Laurent49f02be2009-11-19 09:00:56 -0800326 if (ret == NO_ERROR) {
Eric Laurent421ddc02011-03-07 14:52:59 -0800327 mNewPosition = cblk->user + mUpdatePeriod;
328 cblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
329 cblk->waitTimeMs = 0;
Eric Laurent49f02be2009-11-19 09:00:56 -0800330 if (t != 0) {
Glenn Kasten99d54432011-06-22 16:15:25 -0700331 t->run("ClientRecordThread", ANDROID_PRIORITY_AUDIO);
Eric Laurent49f02be2009-11-19 09:00:56 -0800332 } else {
Glenn Kasten99d54432011-06-22 16:15:25 -0700333 mPreviousPriority = getpriority(PRIO_PROCESS, 0);
334 mPreviousSchedulingGroup = androidGetThreadSchedulingGroup(0);
335 androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO);
Eric Laurent49f02be2009-11-19 09:00:56 -0800336 }
337 } else {
Eric Laurentf3d6dd02010-11-18 08:40:16 -0800338 mActive = 0;
Eric Laurent49f02be2009-11-19 09:00:56 -0800339 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800340 }
341
342 if (t != 0) {
343 t->mLock.unlock();
344 }
345
346 return ret;
347}
348
349status_t AudioRecord::stop()
350{
351 sp<ClientRecordThread> t = mClientRecordThread;
352
Steve Block71f2cf12011-10-20 11:56:00 +0100353 ALOGV("stop");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800354
355 if (t != 0) {
356 t->mLock.lock();
Eric Laurentf3d6dd02010-11-18 08:40:16 -0800357 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800358
Eric Laurentf3d6dd02010-11-18 08:40:16 -0800359 AutoMutex lock(mLock);
360 if (mActive == 1) {
361 mActive = 0;
Eric Laurentef028272009-04-21 07:56:33 -0700362 mCblk->cv.signal();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800363 mAudioRecord->stop();
Jean-Michel Trivi78c13142009-03-24 19:48:58 -0700364 // the record head position will reset to 0, so if a marker is set, we need
365 // to activate it again
366 mMarkerReached = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800367 if (t != 0) {
368 t->requestExit();
369 } else {
Glenn Kasten99d54432011-06-22 16:15:25 -0700370 setpriority(PRIO_PROCESS, 0, mPreviousPriority);
371 androidSetThreadSchedulingGroup(0, mPreviousSchedulingGroup);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800372 }
373 }
374
375 if (t != 0) {
376 t->mLock.unlock();
377 }
378
379 return NO_ERROR;
380}
381
382bool AudioRecord::stopped() const
383{
384 return !mActive;
385}
386
Eric Laurent88e209d2009-07-07 07:10:45 -0700387uint32_t AudioRecord::getSampleRate()
388{
Eric Laurent421ddc02011-03-07 14:52:59 -0800389 AutoMutex lock(mLock);
Eric Laurent88e209d2009-07-07 07:10:45 -0700390 return mCblk->sampleRate;
391}
392
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800393status_t AudioRecord::setMarkerPosition(uint32_t marker)
394{
395 if (mCbf == 0) return INVALID_OPERATION;
396
397 mMarkerPosition = marker;
Jean-Michel Trivi78c13142009-03-24 19:48:58 -0700398 mMarkerReached = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800399
400 return NO_ERROR;
401}
402
403status_t AudioRecord::getMarkerPosition(uint32_t *marker)
404{
405 if (marker == 0) return BAD_VALUE;
406
407 *marker = mMarkerPosition;
408
409 return NO_ERROR;
410}
411
412status_t AudioRecord::setPositionUpdatePeriod(uint32_t updatePeriod)
413{
414 if (mCbf == 0) return INVALID_OPERATION;
415
416 uint32_t curPosition;
417 getPosition(&curPosition);
418 mNewPosition = curPosition + updatePeriod;
419 mUpdatePeriod = updatePeriod;
420
421 return NO_ERROR;
422}
423
424status_t AudioRecord::getPositionUpdatePeriod(uint32_t *updatePeriod)
425{
426 if (updatePeriod == 0) return BAD_VALUE;
427
428 *updatePeriod = mUpdatePeriod;
429
430 return NO_ERROR;
431}
432
433status_t AudioRecord::getPosition(uint32_t *position)
434{
435 if (position == 0) return BAD_VALUE;
436
Eric Laurent421ddc02011-03-07 14:52:59 -0800437 AutoMutex lock(mLock);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800438 *position = mCblk->user;
439
440 return NO_ERROR;
441}
442
Eric Laurent47d0a922010-02-26 02:47:27 -0800443unsigned int AudioRecord::getInputFramesLost()
444{
445 if (mActive)
446 return AudioSystem::getInputFramesLost(mInput);
447 else
448 return 0;
449}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800450
451// -------------------------------------------------------------------------
452
Eric Laurent421ddc02011-03-07 14:52:59 -0800453// must be called with mLock held
454status_t AudioRecord::openRecord_l(
Eric Laurentbda74692009-11-04 08:27:26 -0800455 uint32_t sampleRate,
Jean-Michel Trivi54392232011-05-24 15:53:33 -0700456 uint32_t format,
457 uint32_t channelMask,
Eric Laurentbda74692009-11-04 08:27:26 -0800458 int frameCount,
Eric Laurent49f02be2009-11-19 09:00:56 -0800459 uint32_t flags,
460 audio_io_handle_t input)
Eric Laurentbda74692009-11-04 08:27:26 -0800461{
462 status_t status;
463 const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
464 if (audioFlinger == 0) {
465 return NO_INIT;
466 }
467
Eric Laurent49f02be2009-11-19 09:00:56 -0800468 sp<IAudioRecord> record = audioFlinger->openRecord(getpid(), input,
Eric Laurentbda74692009-11-04 08:27:26 -0800469 sampleRate, format,
Jean-Michel Trivi54392232011-05-24 15:53:33 -0700470 channelMask,
Eric Laurentbda74692009-11-04 08:27:26 -0800471 frameCount,
472 ((uint16_t)flags) << 16,
Eric Laurent65b65452010-06-01 23:49:17 -0700473 &mSessionId,
Eric Laurentbda74692009-11-04 08:27:26 -0800474 &status);
Marco Nelissenc74b93f2011-08-02 13:33:41 -0700475
Eric Laurentbda74692009-11-04 08:27:26 -0800476 if (record == 0) {
477 LOGE("AudioFlinger could not create record track, status: %d", status);
478 return status;
479 }
480 sp<IMemory> cblk = record->getCblk();
481 if (cblk == 0) {
482 LOGE("Could not get control block");
483 return NO_INIT;
484 }
485 mAudioRecord.clear();
486 mAudioRecord = record;
487 mCblkMemory.clear();
488 mCblkMemory = cblk;
489 mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer());
490 mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
Eric Laurentae29b762011-03-28 18:37:07 -0700491 android_atomic_and(~CBLK_DIRECTION_MSK, &mCblk->flags);
Eric Laurent49f02be2009-11-19 09:00:56 -0800492 mCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
493 mCblk->waitTimeMs = 0;
Eric Laurentbda74692009-11-04 08:27:26 -0800494 return NO_ERROR;
495}
496
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800497status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
498{
Eric Laurent421ddc02011-03-07 14:52:59 -0800499 AutoMutex lock(mLock);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800500 int active;
Glenn Kasten028ab992011-06-22 16:18:04 -0700501 status_t result = NO_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800502 audio_track_cblk_t* cblk = mCblk;
503 uint32_t framesReq = audioBuffer->frameCount;
Eric Laurentef028272009-04-21 07:56:33 -0700504 uint32_t waitTimeMs = (waitCount < 0) ? cblk->bufferTimeoutMs : WAIT_PERIOD_MS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800505
506 audioBuffer->frameCount = 0;
507 audioBuffer->size = 0;
508
509 uint32_t framesReady = cblk->framesReady();
510
511 if (framesReady == 0) {
Eric Laurentbda74692009-11-04 08:27:26 -0800512 cblk->lock.lock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800513 goto start_loop_here;
514 while (framesReady == 0) {
515 active = mActive;
Eric Laurentbda74692009-11-04 08:27:26 -0800516 if (UNLIKELY(!active)) {
517 cblk->lock.unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800518 return NO_MORE_BUFFERS;
Eric Laurentbda74692009-11-04 08:27:26 -0800519 }
520 if (UNLIKELY(!waitCount)) {
521 cblk->lock.unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800522 return WOULD_BLOCK;
Eric Laurentbda74692009-11-04 08:27:26 -0800523 }
Eric Laurent421ddc02011-03-07 14:52:59 -0800524 if (!(cblk->flags & CBLK_INVALID_MSK)) {
525 mLock.unlock();
526 result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs));
527 cblk->lock.unlock();
528 mLock.lock();
529 if (mActive == 0) {
530 return status_t(STOPPED);
531 }
532 cblk->lock.lock();
533 }
534 if (cblk->flags & CBLK_INVALID_MSK) {
535 goto create_new_record;
536 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800537 if (__builtin_expect(result!=NO_ERROR, false)) {
Eric Laurentef028272009-04-21 07:56:33 -0700538 cblk->waitTimeMs += waitTimeMs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800539 if (cblk->waitTimeMs >= cblk->bufferTimeoutMs) {
540 LOGW( "obtainBuffer timed out (is the CPU pegged?) "
541 "user=%08x, server=%08x", cblk->user, cblk->server);
Eric Laurentbda74692009-11-04 08:27:26 -0800542 cblk->lock.unlock();
543 result = mAudioRecord->start();
Eric Laurentbda74692009-11-04 08:27:26 -0800544 cblk->lock.lock();
Eric Laurent421ddc02011-03-07 14:52:59 -0800545 if (result == DEAD_OBJECT) {
Eric Laurentae29b762011-03-28 18:37:07 -0700546 android_atomic_or(CBLK_INVALID_ON, &cblk->flags);
Eric Laurent421ddc02011-03-07 14:52:59 -0800547create_new_record:
548 result = AudioRecord::restoreRecord_l(cblk);
549 }
550 if (result != NO_ERROR) {
551 LOGW("obtainBuffer create Track error %d", result);
552 cblk->lock.unlock();
553 return result;
554 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800555 cblk->waitTimeMs = 0;
556 }
557 if (--waitCount == 0) {
Eric Laurentbda74692009-11-04 08:27:26 -0800558 cblk->lock.unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800559 return TIMED_OUT;
560 }
561 }
562 // read the server count again
563 start_loop_here:
564 framesReady = cblk->framesReady();
565 }
Eric Laurentbda74692009-11-04 08:27:26 -0800566 cblk->lock.unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800567 }
568
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800569 cblk->waitTimeMs = 0;
Eric Laurenta553c252009-07-17 12:17:14 -0700570
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800571 if (framesReq > framesReady) {
572 framesReq = framesReady;
573 }
574
575 uint32_t u = cblk->user;
576 uint32_t bufferEnd = cblk->userBase + cblk->frameCount;
577
578 if (u + framesReq > bufferEnd) {
579 framesReq = bufferEnd - u;
580 }
581
582 audioBuffer->flags = 0;
583 audioBuffer->channelCount= mChannelCount;
584 audioBuffer->format = mFormat;
585 audioBuffer->frameCount = framesReq;
Eric Laurenta553c252009-07-17 12:17:14 -0700586 audioBuffer->size = framesReq*cblk->frameSize;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800587 audioBuffer->raw = (int8_t*)cblk->buffer(u);
588 active = mActive;
589 return active ? status_t(NO_ERROR) : status_t(STOPPED);
590}
591
592void AudioRecord::releaseBuffer(Buffer* audioBuffer)
593{
Eric Laurent421ddc02011-03-07 14:52:59 -0800594 AutoMutex lock(mLock);
595 mCblk->stepUser(audioBuffer->frameCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800596}
597
Eric Laurent49f02be2009-11-19 09:00:56 -0800598audio_io_handle_t AudioRecord::getInput()
599{
Eric Laurent421ddc02011-03-07 14:52:59 -0800600 AutoMutex lock(mLock);
Eric Laurent678cc952011-07-26 20:32:28 -0700601 return mInput;
Eric Laurent421ddc02011-03-07 14:52:59 -0800602}
603
604// must be called with mLock held
605audio_io_handle_t AudioRecord::getInput_l()
606{
Eric Laurent47d0a922010-02-26 02:47:27 -0800607 mInput = AudioSystem::getInput(mInputSource,
Eric Laurent49f02be2009-11-19 09:00:56 -0800608 mCblk->sampleRate,
Eric Laurent464d5b32011-06-17 21:29:58 -0700609 mFormat,
610 mChannelMask,
611 (audio_in_acoustics_t)mFlags,
612 mSessionId);
Eric Laurent47d0a922010-02-26 02:47:27 -0800613 return mInput;
Eric Laurent49f02be2009-11-19 09:00:56 -0800614}
615
Eric Laurent65b65452010-06-01 23:49:17 -0700616int AudioRecord::getSessionId()
617{
618 return mSessionId;
619}
620
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800621// -------------------------------------------------------------------------
622
623ssize_t AudioRecord::read(void* buffer, size_t userSize)
624{
625 ssize_t read = 0;
626 Buffer audioBuffer;
627 int8_t *dst = static_cast<int8_t*>(buffer);
628
629 if (ssize_t(userSize) < 0) {
630 // sanity-check. user is most-likely passing an error code.
631 LOGE("AudioRecord::read(buffer=%p, size=%u (%d)",
632 buffer, userSize, userSize);
633 return BAD_VALUE;
634 }
635
Eric Laurent421ddc02011-03-07 14:52:59 -0800636 mLock.lock();
637 // acquire a strong reference on the IAudioRecord and IMemory so that they cannot be destroyed
638 // while we are accessing the cblk
639 sp <IAudioRecord> audioRecord = mAudioRecord;
640 sp <IMemory> iMem = mCblkMemory;
641 mLock.unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800642
643 do {
644
Eric Laurenta553c252009-07-17 12:17:14 -0700645 audioBuffer.frameCount = userSize/frameSize();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800646
Eric Laurentba8811f2010-03-02 18:38:06 -0800647 // By using a wait count corresponding to twice the timeout period in
648 // obtainBuffer() we give a chance to recover once for a read timeout
649 // (if media_server crashed for instance) before returning a length of
650 // 0 bytes read to the client
651 status_t err = obtainBuffer(&audioBuffer, ((2 * MAX_RUN_TIMEOUT_MS) / WAIT_PERIOD_MS));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800652 if (err < 0) {
653 // out of buffers, return #bytes written
654 if (err == status_t(NO_MORE_BUFFERS))
655 break;
Eric Laurentba8811f2010-03-02 18:38:06 -0800656 if (err == status_t(TIMED_OUT))
657 err = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800658 return ssize_t(err);
659 }
660
661 size_t bytesRead = audioBuffer.size;
662 memcpy(dst, audioBuffer.i8, bytesRead);
663
664 dst += bytesRead;
665 userSize -= bytesRead;
666 read += bytesRead;
667
668 releaseBuffer(&audioBuffer);
669 } while (userSize);
670
671 return read;
672}
673
674// -------------------------------------------------------------------------
675
676bool AudioRecord::processAudioBuffer(const sp<ClientRecordThread>& thread)
677{
678 Buffer audioBuffer;
679 uint32_t frames = mRemainingFrames;
680 size_t readSize;
681
Eric Laurent421ddc02011-03-07 14:52:59 -0800682 mLock.lock();
683 // acquire a strong reference on the IAudioRecord and IMemory so that they cannot be destroyed
684 // while we are accessing the cblk
685 sp <IAudioRecord> audioRecord = mAudioRecord;
686 sp <IMemory> iMem = mCblkMemory;
687 audio_track_cblk_t* cblk = mCblk;
688 mLock.unlock();
689
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800690 // Manage marker callback
Jean-Michel Trivi78c13142009-03-24 19:48:58 -0700691 if (!mMarkerReached && (mMarkerPosition > 0)) {
Eric Laurent421ddc02011-03-07 14:52:59 -0800692 if (cblk->user >= mMarkerPosition) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800693 mCbf(EVENT_MARKER, mUserData, (void *)&mMarkerPosition);
Jean-Michel Trivi78c13142009-03-24 19:48:58 -0700694 mMarkerReached = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800695 }
696 }
697
698 // Manage new position callback
699 if (mUpdatePeriod > 0) {
Eric Laurent421ddc02011-03-07 14:52:59 -0800700 while (cblk->user >= mNewPosition) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800701 mCbf(EVENT_NEW_POS, mUserData, (void *)&mNewPosition);
702 mNewPosition += mUpdatePeriod;
703 }
704 }
705
706 do {
707 audioBuffer.frameCount = frames;
Eric Laurenta553c252009-07-17 12:17:14 -0700708 // Calling obtainBuffer() with a wait count of 1
709 // limits wait time to WAIT_PERIOD_MS. This prevents from being
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800710 // stuck here not being able to handle timed events (position, markers).
711 status_t err = obtainBuffer(&audioBuffer, 1);
712 if (err < NO_ERROR) {
713 if (err != TIMED_OUT) {
Eric Laurentef028272009-04-21 07:56:33 -0700714 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 -0800715 return false;
716 }
717 break;
718 }
719 if (err == status_t(STOPPED)) return false;
720
721 size_t reqSize = audioBuffer.size;
722 mCbf(EVENT_MORE_DATA, mUserData, &audioBuffer);
723 readSize = audioBuffer.size;
724
725 // Sanity check on returned size
Eric Laurent272beb62009-03-24 21:23:54 -0700726 if (ssize_t(readSize) <= 0) {
727 // The callback is done filling buffers
728 // Keep this thread going to handle timed events and
729 // still try to get more data in intervals of WAIT_PERIOD_MS
730 // but don't just loop and block the CPU, so wait
731 usleep(WAIT_PERIOD_MS*1000);
732 break;
733 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800734 if (readSize > reqSize) readSize = reqSize;
735
736 audioBuffer.size = readSize;
Eric Laurenta553c252009-07-17 12:17:14 -0700737 audioBuffer.frameCount = readSize/frameSize();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800738 frames -= audioBuffer.frameCount;
739
740 releaseBuffer(&audioBuffer);
741
742 } while (frames);
743
Eric Laurenta553c252009-07-17 12:17:14 -0700744
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800745 // Manage overrun callback
Eric Laurent421ddc02011-03-07 14:52:59 -0800746 if (mActive && (cblk->framesAvailable() == 0)) {
Steve Block71f2cf12011-10-20 11:56:00 +0100747 ALOGV("Overrun user: %x, server: %x, flags %04x", cblk->user, cblk->server, cblk->flags);
Eric Laurentae29b762011-03-28 18:37:07 -0700748 if (!(android_atomic_or(CBLK_UNDERRUN_ON, &cblk->flags) & CBLK_UNDERRUN_MSK)) {
Eric Laurent913af0b2011-03-17 09:36:51 -0700749 mCbf(EVENT_OVERRUN, mUserData, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800750 }
751 }
752
753 if (frames == 0) {
754 mRemainingFrames = mNotificationFrames;
755 } else {
756 mRemainingFrames = frames;
757 }
758 return true;
759}
760
Eric Laurent421ddc02011-03-07 14:52:59 -0800761// must be called with mLock and cblk.lock held. Callers must also hold strong references on
762// the IAudioRecord and IMemory in case they are recreated here.
763// If the IAudioRecord is successfully restored, the cblk pointer is updated
764status_t AudioRecord::restoreRecord_l(audio_track_cblk_t*& cblk)
765{
766 status_t result;
767
Eric Laurentae29b762011-03-28 18:37:07 -0700768 if (!(android_atomic_or(CBLK_RESTORING_ON, &cblk->flags) & CBLK_RESTORING_MSK)) {
Eric Laurent421ddc02011-03-07 14:52:59 -0800769 LOGW("dead IAudioRecord, creating a new one");
Eric Laurent421ddc02011-03-07 14:52:59 -0800770 // signal old cblk condition so that other threads waiting for available buffers stop
771 // waiting now
772 cblk->cv.broadcast();
773 cblk->lock.unlock();
774
775 // if the new IAudioRecord is created, openRecord_l() will modify the
776 // following member variables: mAudioRecord, mCblkMemory and mCblk.
777 // It will also delete the strong references on previous IAudioRecord and IMemory
Jean-Michel Trivi54392232011-05-24 15:53:33 -0700778 result = openRecord_l(cblk->sampleRate, mFormat, mChannelMask,
Eric Laurent421ddc02011-03-07 14:52:59 -0800779 mFrameCount, mFlags, getInput_l());
780 if (result == NO_ERROR) {
781 result = mAudioRecord->start();
782 }
783 if (result != NO_ERROR) {
784 mActive = false;
785 }
786
787 // signal old cblk condition for other threads waiting for restore completion
Eric Laurentae29b762011-03-28 18:37:07 -0700788 android_atomic_or(CBLK_RESTORED_ON, &cblk->flags);
Eric Laurent421ddc02011-03-07 14:52:59 -0800789 cblk->cv.broadcast();
Eric Laurent421ddc02011-03-07 14:52:59 -0800790 } else {
791 if (!(cblk->flags & CBLK_RESTORED_MSK)) {
792 LOGW("dead IAudioRecord, waiting for a new one to be created");
793 mLock.unlock();
794 result = cblk->cv.waitRelative(cblk->lock, milliseconds(RESTORE_TIMEOUT_MS));
795 cblk->lock.unlock();
796 mLock.lock();
797 } else {
798 LOGW("dead IAudioRecord, already restored");
799 result = NO_ERROR;
800 cblk->lock.unlock();
801 }
802 if (result != NO_ERROR || mActive == 0) {
803 result = status_t(STOPPED);
804 }
805 }
Steve Block71f2cf12011-10-20 11:56:00 +0100806 ALOGV("restoreRecord_l() status %d mActive %d cblk %p, old cblk %p flags %08x old flags %08x",
Eric Laurent421ddc02011-03-07 14:52:59 -0800807 result, mActive, mCblk, cblk, mCblk->flags, cblk->flags);
808
809 if (result == NO_ERROR) {
810 // from now on we switch to the newly created cblk
811 cblk = mCblk;
812 }
813 cblk->lock.lock();
814
815 LOGW_IF(result != NO_ERROR, "restoreRecord_l() error %d", result);
816
817 return result;
818}
819
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800820// =========================================================================
821
822AudioRecord::ClientRecordThread::ClientRecordThread(AudioRecord& receiver, bool bCanCallJava)
823 : Thread(bCanCallJava), mReceiver(receiver)
824{
825}
826
827bool AudioRecord::ClientRecordThread::threadLoop()
828{
829 return mReceiver.processAudioBuffer(this);
830}
831
832// -------------------------------------------------------------------------
833
834}; // namespace android
835