blob: dd1c6a5021390e77467fdd854b909b41e25e3e14 [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>
Glenn Kastene80a4cc2011-12-15 09:51:17 -080042#include <cutils/compiler.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043
44namespace android {
Chia-chi Yeh97d61f72010-06-22 08:01:13 +080045// ---------------------------------------------------------------------------
46
47// static
48status_t AudioRecord::getMinFrameCount(
49 int* frameCount,
50 uint32_t sampleRate,
51 int format,
52 int channelCount)
53{
54 size_t size = 0;
55 if (AudioSystem::getInputBufferSize(sampleRate, format, channelCount, &size)
56 != NO_ERROR) {
57 LOGE("AudioSystem could not query the input buffer size.");
58 return NO_INIT;
59 }
60
61 if (size == 0) {
62 LOGE("Unsupported configuration: sampleRate %d, format %d, channelCount %d",
63 sampleRate, format, channelCount);
64 return BAD_VALUE;
65 }
66
67 // We double the size of input buffer for ping pong use of record buffer.
68 size <<= 1;
69
Dima Zavin24fc2fb2011-04-19 22:30:36 -070070 if (audio_is_linear_pcm(format)) {
Eric Laurentc310dcb2011-06-16 21:30:45 -070071 size /= channelCount * audio_bytes_per_sample(format);
Chia-chi Yeh97d61f72010-06-22 08:01:13 +080072 }
73
74 *frameCount = size;
75 return NO_ERROR;
76}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080077
78// ---------------------------------------------------------------------------
79
80AudioRecord::AudioRecord()
Glenn Kasten99d54432011-06-22 16:15:25 -070081 : mStatus(NO_INIT), mSessionId(0),
82 mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(ANDROID_TGROUP_DEFAULT)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083{
84}
85
86AudioRecord::AudioRecord(
Eric Laurent4bc035a2009-05-22 09:18:15 -070087 int inputSource,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088 uint32_t sampleRate,
89 int format,
Jean-Michel Trivi54392232011-05-24 15:53:33 -070090 uint32_t channelMask,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091 int frameCount,
92 uint32_t flags,
93 callback_t cbf,
94 void* user,
Eric Laurent65b65452010-06-01 23:49:17 -070095 int notificationFrames,
96 int sessionId)
Glenn Kasten99d54432011-06-22 16:15:25 -070097 : mStatus(NO_INIT), mSessionId(0),
98 mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(ANDROID_TGROUP_DEFAULT)
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 Laurent9cc489a2009-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 Kasten99d54432011-06-22 16:15:25 -0700329 t->run("ClientRecordThread", ANDROID_PRIORITY_AUDIO);
Eric Laurent49f02be2009-11-19 09:00:56 -0800330 } else {
Glenn Kasten99d54432011-06-22 16:15:25 -0700331 mPreviousPriority = getpriority(PRIO_PROCESS, 0);
332 mPreviousSchedulingGroup = androidGetThreadSchedulingGroup(0);
333 androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO);
Eric Laurent49f02be2009-11-19 09:00:56 -0800334 }
335 } else {
Eric Laurentf3d6dd02010-11-18 08:40:16 -0800336 mActive = 0;
Eric Laurent49f02be2009-11-19 09:00:56 -0800337 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800338 }
339
340 if (t != 0) {
341 t->mLock.unlock();
342 }
343
344 return ret;
345}
346
347status_t AudioRecord::stop()
348{
349 sp<ClientRecordThread> t = mClientRecordThread;
350
Steve Block71f2cf12011-10-20 11:56:00 +0100351 ALOGV("stop");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800352
353 if (t != 0) {
354 t->mLock.lock();
Eric Laurentf3d6dd02010-11-18 08:40:16 -0800355 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800356
Eric Laurentf3d6dd02010-11-18 08:40:16 -0800357 AutoMutex lock(mLock);
358 if (mActive == 1) {
359 mActive = 0;
Eric Laurentef028272009-04-21 07:56:33 -0700360 mCblk->cv.signal();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800361 mAudioRecord->stop();
Jean-Michel Trivi78c13142009-03-24 19:48:58 -0700362 // the record head position will reset to 0, so if a marker is set, we need
363 // to activate it again
364 mMarkerReached = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800365 if (t != 0) {
366 t->requestExit();
367 } else {
Glenn Kasten99d54432011-06-22 16:15:25 -0700368 setpriority(PRIO_PROCESS, 0, mPreviousPriority);
369 androidSetThreadSchedulingGroup(0, mPreviousSchedulingGroup);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800370 }
371 }
372
373 if (t != 0) {
374 t->mLock.unlock();
375 }
376
377 return NO_ERROR;
378}
379
380bool AudioRecord::stopped() const
381{
382 return !mActive;
383}
384
Eric Laurent88e209d2009-07-07 07:10:45 -0700385uint32_t AudioRecord::getSampleRate()
386{
Eric Laurent421ddc02011-03-07 14:52:59 -0800387 AutoMutex lock(mLock);
Eric Laurent88e209d2009-07-07 07:10:45 -0700388 return mCblk->sampleRate;
389}
390
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800391status_t AudioRecord::setMarkerPosition(uint32_t marker)
392{
393 if (mCbf == 0) return INVALID_OPERATION;
394
395 mMarkerPosition = marker;
Jean-Michel Trivi78c13142009-03-24 19:48:58 -0700396 mMarkerReached = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800397
398 return NO_ERROR;
399}
400
401status_t AudioRecord::getMarkerPosition(uint32_t *marker)
402{
403 if (marker == 0) return BAD_VALUE;
404
405 *marker = mMarkerPosition;
406
407 return NO_ERROR;
408}
409
410status_t AudioRecord::setPositionUpdatePeriod(uint32_t updatePeriod)
411{
412 if (mCbf == 0) return INVALID_OPERATION;
413
414 uint32_t curPosition;
415 getPosition(&curPosition);
416 mNewPosition = curPosition + updatePeriod;
417 mUpdatePeriod = updatePeriod;
418
419 return NO_ERROR;
420}
421
422status_t AudioRecord::getPositionUpdatePeriod(uint32_t *updatePeriod)
423{
424 if (updatePeriod == 0) return BAD_VALUE;
425
426 *updatePeriod = mUpdatePeriod;
427
428 return NO_ERROR;
429}
430
431status_t AudioRecord::getPosition(uint32_t *position)
432{
433 if (position == 0) return BAD_VALUE;
434
Eric Laurent421ddc02011-03-07 14:52:59 -0800435 AutoMutex lock(mLock);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800436 *position = mCblk->user;
437
438 return NO_ERROR;
439}
440
Eric Laurent47d0a922010-02-26 02:47:27 -0800441unsigned int AudioRecord::getInputFramesLost()
442{
443 if (mActive)
444 return AudioSystem::getInputFramesLost(mInput);
445 else
446 return 0;
447}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800448
449// -------------------------------------------------------------------------
450
Eric Laurent421ddc02011-03-07 14:52:59 -0800451// must be called with mLock held
452status_t AudioRecord::openRecord_l(
Eric Laurentbda74692009-11-04 08:27:26 -0800453 uint32_t sampleRate,
Jean-Michel Trivi54392232011-05-24 15:53:33 -0700454 uint32_t format,
455 uint32_t channelMask,
Eric Laurentbda74692009-11-04 08:27:26 -0800456 int frameCount,
Eric Laurent49f02be2009-11-19 09:00:56 -0800457 uint32_t flags,
458 audio_io_handle_t input)
Eric Laurentbda74692009-11-04 08:27:26 -0800459{
460 status_t status;
461 const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
462 if (audioFlinger == 0) {
463 return NO_INIT;
464 }
465
Eric Laurent49f02be2009-11-19 09:00:56 -0800466 sp<IAudioRecord> record = audioFlinger->openRecord(getpid(), input,
Eric Laurentbda74692009-11-04 08:27:26 -0800467 sampleRate, format,
Jean-Michel Trivi54392232011-05-24 15:53:33 -0700468 channelMask,
Eric Laurentbda74692009-11-04 08:27:26 -0800469 frameCount,
470 ((uint16_t)flags) << 16,
Eric Laurent65b65452010-06-01 23:49:17 -0700471 &mSessionId,
Eric Laurentbda74692009-11-04 08:27:26 -0800472 &status);
Marco Nelissenc74b93f2011-08-02 13:33:41 -0700473
Eric Laurentbda74692009-11-04 08:27:26 -0800474 if (record == 0) {
475 LOGE("AudioFlinger could not create record track, status: %d", status);
476 return status;
477 }
478 sp<IMemory> cblk = record->getCblk();
479 if (cblk == 0) {
480 LOGE("Could not get control block");
481 return NO_INIT;
482 }
483 mAudioRecord.clear();
484 mAudioRecord = record;
485 mCblkMemory.clear();
486 mCblkMemory = cblk;
487 mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer());
488 mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
Eric Laurentae29b762011-03-28 18:37:07 -0700489 android_atomic_and(~CBLK_DIRECTION_MSK, &mCblk->flags);
Eric Laurent49f02be2009-11-19 09:00:56 -0800490 mCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
491 mCblk->waitTimeMs = 0;
Eric Laurentbda74692009-11-04 08:27:26 -0800492 return NO_ERROR;
493}
494
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800495status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
496{
Eric Laurent421ddc02011-03-07 14:52:59 -0800497 AutoMutex lock(mLock);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800498 int active;
Glenn Kasten028ab992011-06-22 16:18:04 -0700499 status_t result = NO_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800500 audio_track_cblk_t* cblk = mCblk;
501 uint32_t framesReq = audioBuffer->frameCount;
Eric Laurentef028272009-04-21 07:56:33 -0700502 uint32_t waitTimeMs = (waitCount < 0) ? cblk->bufferTimeoutMs : WAIT_PERIOD_MS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800503
504 audioBuffer->frameCount = 0;
505 audioBuffer->size = 0;
506
507 uint32_t framesReady = cblk->framesReady();
508
509 if (framesReady == 0) {
Eric Laurentbda74692009-11-04 08:27:26 -0800510 cblk->lock.lock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800511 goto start_loop_here;
512 while (framesReady == 0) {
513 active = mActive;
Glenn Kastene80a4cc2011-12-15 09:51:17 -0800514 if (CC_UNLIKELY(!active)) {
Eric Laurentbda74692009-11-04 08:27:26 -0800515 cblk->lock.unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800516 return NO_MORE_BUFFERS;
Eric Laurentbda74692009-11-04 08:27:26 -0800517 }
Glenn Kastene80a4cc2011-12-15 09:51:17 -0800518 if (CC_UNLIKELY(!waitCount)) {
Eric Laurentbda74692009-11-04 08:27:26 -0800519 cblk->lock.unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800520 return WOULD_BLOCK;
Eric Laurentbda74692009-11-04 08:27:26 -0800521 }
Eric Laurent421ddc02011-03-07 14:52:59 -0800522 if (!(cblk->flags & CBLK_INVALID_MSK)) {
523 mLock.unlock();
524 result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs));
525 cblk->lock.unlock();
526 mLock.lock();
527 if (mActive == 0) {
528 return status_t(STOPPED);
529 }
530 cblk->lock.lock();
531 }
532 if (cblk->flags & CBLK_INVALID_MSK) {
533 goto create_new_record;
534 }
Glenn Kastene80a4cc2011-12-15 09:51:17 -0800535 if (CC_UNLIKELY(result != NO_ERROR)) {
Eric Laurentef028272009-04-21 07:56:33 -0700536 cblk->waitTimeMs += waitTimeMs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800537 if (cblk->waitTimeMs >= cblk->bufferTimeoutMs) {
538 LOGW( "obtainBuffer timed out (is the CPU pegged?) "
539 "user=%08x, server=%08x", cblk->user, cblk->server);
Eric Laurentbda74692009-11-04 08:27:26 -0800540 cblk->lock.unlock();
541 result = mAudioRecord->start();
Eric Laurentbda74692009-11-04 08:27:26 -0800542 cblk->lock.lock();
Eric Laurent421ddc02011-03-07 14:52:59 -0800543 if (result == DEAD_OBJECT) {
Eric Laurentae29b762011-03-28 18:37:07 -0700544 android_atomic_or(CBLK_INVALID_ON, &cblk->flags);
Eric Laurent421ddc02011-03-07 14:52:59 -0800545create_new_record:
546 result = AudioRecord::restoreRecord_l(cblk);
547 }
548 if (result != NO_ERROR) {
549 LOGW("obtainBuffer create Track error %d", result);
550 cblk->lock.unlock();
551 return result;
552 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800553 cblk->waitTimeMs = 0;
554 }
555 if (--waitCount == 0) {
Eric Laurentbda74692009-11-04 08:27:26 -0800556 cblk->lock.unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800557 return TIMED_OUT;
558 }
559 }
560 // read the server count again
561 start_loop_here:
562 framesReady = cblk->framesReady();
563 }
Eric Laurentbda74692009-11-04 08:27:26 -0800564 cblk->lock.unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800565 }
566
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800567 cblk->waitTimeMs = 0;
Eric Laurenta553c252009-07-17 12:17:14 -0700568
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800569 if (framesReq > framesReady) {
570 framesReq = framesReady;
571 }
572
573 uint32_t u = cblk->user;
574 uint32_t bufferEnd = cblk->userBase + cblk->frameCount;
575
576 if (u + framesReq > bufferEnd) {
577 framesReq = bufferEnd - u;
578 }
579
580 audioBuffer->flags = 0;
581 audioBuffer->channelCount= mChannelCount;
582 audioBuffer->format = mFormat;
583 audioBuffer->frameCount = framesReq;
Eric Laurenta553c252009-07-17 12:17:14 -0700584 audioBuffer->size = framesReq*cblk->frameSize;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800585 audioBuffer->raw = (int8_t*)cblk->buffer(u);
586 active = mActive;
587 return active ? status_t(NO_ERROR) : status_t(STOPPED);
588}
589
590void AudioRecord::releaseBuffer(Buffer* audioBuffer)
591{
Eric Laurent421ddc02011-03-07 14:52:59 -0800592 AutoMutex lock(mLock);
593 mCblk->stepUser(audioBuffer->frameCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800594}
595
Eric Laurent49f02be2009-11-19 09:00:56 -0800596audio_io_handle_t AudioRecord::getInput()
597{
Eric Laurent421ddc02011-03-07 14:52:59 -0800598 AutoMutex lock(mLock);
Eric Laurent678cc952011-07-26 20:32:28 -0700599 return mInput;
Eric Laurent421ddc02011-03-07 14:52:59 -0800600}
601
602// must be called with mLock held
603audio_io_handle_t AudioRecord::getInput_l()
604{
Eric Laurent47d0a922010-02-26 02:47:27 -0800605 mInput = AudioSystem::getInput(mInputSource,
Eric Laurent49f02be2009-11-19 09:00:56 -0800606 mCblk->sampleRate,
Eric Laurent464d5b32011-06-17 21:29:58 -0700607 mFormat,
608 mChannelMask,
609 (audio_in_acoustics_t)mFlags,
610 mSessionId);
Eric Laurent47d0a922010-02-26 02:47:27 -0800611 return mInput;
Eric Laurent49f02be2009-11-19 09:00:56 -0800612}
613
Eric Laurent65b65452010-06-01 23:49:17 -0700614int AudioRecord::getSessionId()
615{
616 return mSessionId;
617}
618
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800619// -------------------------------------------------------------------------
620
621ssize_t AudioRecord::read(void* buffer, size_t userSize)
622{
623 ssize_t read = 0;
624 Buffer audioBuffer;
625 int8_t *dst = static_cast<int8_t*>(buffer);
626
627 if (ssize_t(userSize) < 0) {
628 // sanity-check. user is most-likely passing an error code.
629 LOGE("AudioRecord::read(buffer=%p, size=%u (%d)",
630 buffer, userSize, userSize);
631 return BAD_VALUE;
632 }
633
Eric Laurent421ddc02011-03-07 14:52:59 -0800634 mLock.lock();
635 // acquire a strong reference on the IAudioRecord and IMemory so that they cannot be destroyed
636 // while we are accessing the cblk
637 sp <IAudioRecord> audioRecord = mAudioRecord;
638 sp <IMemory> iMem = mCblkMemory;
639 mLock.unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800640
641 do {
642
Eric Laurenta553c252009-07-17 12:17:14 -0700643 audioBuffer.frameCount = userSize/frameSize();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800644
Eric Laurentba8811f2010-03-02 18:38:06 -0800645 // By using a wait count corresponding to twice the timeout period in
646 // obtainBuffer() we give a chance to recover once for a read timeout
647 // (if media_server crashed for instance) before returning a length of
648 // 0 bytes read to the client
649 status_t err = obtainBuffer(&audioBuffer, ((2 * MAX_RUN_TIMEOUT_MS) / WAIT_PERIOD_MS));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800650 if (err < 0) {
651 // out of buffers, return #bytes written
652 if (err == status_t(NO_MORE_BUFFERS))
653 break;
Eric Laurentba8811f2010-03-02 18:38:06 -0800654 if (err == status_t(TIMED_OUT))
655 err = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800656 return ssize_t(err);
657 }
658
659 size_t bytesRead = audioBuffer.size;
660 memcpy(dst, audioBuffer.i8, bytesRead);
661
662 dst += bytesRead;
663 userSize -= bytesRead;
664 read += bytesRead;
665
666 releaseBuffer(&audioBuffer);
667 } while (userSize);
668
669 return read;
670}
671
672// -------------------------------------------------------------------------
673
674bool AudioRecord::processAudioBuffer(const sp<ClientRecordThread>& thread)
675{
676 Buffer audioBuffer;
677 uint32_t frames = mRemainingFrames;
678 size_t readSize;
679
Eric Laurent421ddc02011-03-07 14:52:59 -0800680 mLock.lock();
681 // acquire a strong reference on the IAudioRecord and IMemory so that they cannot be destroyed
682 // while we are accessing the cblk
683 sp <IAudioRecord> audioRecord = mAudioRecord;
684 sp <IMemory> iMem = mCblkMemory;
685 audio_track_cblk_t* cblk = mCblk;
686 mLock.unlock();
687
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800688 // Manage marker callback
Jean-Michel Trivi78c13142009-03-24 19:48:58 -0700689 if (!mMarkerReached && (mMarkerPosition > 0)) {
Eric Laurent421ddc02011-03-07 14:52:59 -0800690 if (cblk->user >= mMarkerPosition) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800691 mCbf(EVENT_MARKER, mUserData, (void *)&mMarkerPosition);
Jean-Michel Trivi78c13142009-03-24 19:48:58 -0700692 mMarkerReached = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800693 }
694 }
695
696 // Manage new position callback
697 if (mUpdatePeriod > 0) {
Eric Laurent421ddc02011-03-07 14:52:59 -0800698 while (cblk->user >= mNewPosition) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800699 mCbf(EVENT_NEW_POS, mUserData, (void *)&mNewPosition);
700 mNewPosition += mUpdatePeriod;
701 }
702 }
703
704 do {
705 audioBuffer.frameCount = frames;
Eric Laurenta553c252009-07-17 12:17:14 -0700706 // Calling obtainBuffer() with a wait count of 1
707 // limits wait time to WAIT_PERIOD_MS. This prevents from being
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800708 // stuck here not being able to handle timed events (position, markers).
709 status_t err = obtainBuffer(&audioBuffer, 1);
710 if (err < NO_ERROR) {
711 if (err != TIMED_OUT) {
Eric Laurentef028272009-04-21 07:56:33 -0700712 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 -0800713 return false;
714 }
715 break;
716 }
717 if (err == status_t(STOPPED)) return false;
718
719 size_t reqSize = audioBuffer.size;
720 mCbf(EVENT_MORE_DATA, mUserData, &audioBuffer);
721 readSize = audioBuffer.size;
722
723 // Sanity check on returned size
Eric Laurent272beb62009-03-24 21:23:54 -0700724 if (ssize_t(readSize) <= 0) {
725 // The callback is done filling buffers
726 // Keep this thread going to handle timed events and
727 // still try to get more data in intervals of WAIT_PERIOD_MS
728 // but don't just loop and block the CPU, so wait
729 usleep(WAIT_PERIOD_MS*1000);
730 break;
731 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800732 if (readSize > reqSize) readSize = reqSize;
733
734 audioBuffer.size = readSize;
Eric Laurenta553c252009-07-17 12:17:14 -0700735 audioBuffer.frameCount = readSize/frameSize();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800736 frames -= audioBuffer.frameCount;
737
738 releaseBuffer(&audioBuffer);
739
740 } while (frames);
741
Eric Laurenta553c252009-07-17 12:17:14 -0700742
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800743 // Manage overrun callback
Eric Laurent421ddc02011-03-07 14:52:59 -0800744 if (mActive && (cblk->framesAvailable() == 0)) {
Steve Block71f2cf12011-10-20 11:56:00 +0100745 ALOGV("Overrun user: %x, server: %x, flags %04x", cblk->user, cblk->server, cblk->flags);
Eric Laurentae29b762011-03-28 18:37:07 -0700746 if (!(android_atomic_or(CBLK_UNDERRUN_ON, &cblk->flags) & CBLK_UNDERRUN_MSK)) {
Eric Laurent913af0b2011-03-17 09:36:51 -0700747 mCbf(EVENT_OVERRUN, mUserData, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800748 }
749 }
750
751 if (frames == 0) {
752 mRemainingFrames = mNotificationFrames;
753 } else {
754 mRemainingFrames = frames;
755 }
756 return true;
757}
758
Eric Laurent421ddc02011-03-07 14:52:59 -0800759// must be called with mLock and cblk.lock held. Callers must also hold strong references on
760// the IAudioRecord and IMemory in case they are recreated here.
761// If the IAudioRecord is successfully restored, the cblk pointer is updated
762status_t AudioRecord::restoreRecord_l(audio_track_cblk_t*& cblk)
763{
764 status_t result;
765
Eric Laurentae29b762011-03-28 18:37:07 -0700766 if (!(android_atomic_or(CBLK_RESTORING_ON, &cblk->flags) & CBLK_RESTORING_MSK)) {
Eric Laurent421ddc02011-03-07 14:52:59 -0800767 LOGW("dead IAudioRecord, creating a new one");
Eric Laurent421ddc02011-03-07 14:52:59 -0800768 // signal old cblk condition so that other threads waiting for available buffers stop
769 // waiting now
770 cblk->cv.broadcast();
771 cblk->lock.unlock();
772
773 // if the new IAudioRecord is created, openRecord_l() will modify the
774 // following member variables: mAudioRecord, mCblkMemory and mCblk.
775 // It will also delete the strong references on previous IAudioRecord and IMemory
Jean-Michel Trivi54392232011-05-24 15:53:33 -0700776 result = openRecord_l(cblk->sampleRate, mFormat, mChannelMask,
Eric Laurent421ddc02011-03-07 14:52:59 -0800777 mFrameCount, mFlags, getInput_l());
778 if (result == NO_ERROR) {
779 result = mAudioRecord->start();
780 }
781 if (result != NO_ERROR) {
782 mActive = false;
783 }
784
785 // signal old cblk condition for other threads waiting for restore completion
Eric Laurentae29b762011-03-28 18:37:07 -0700786 android_atomic_or(CBLK_RESTORED_ON, &cblk->flags);
Eric Laurent421ddc02011-03-07 14:52:59 -0800787 cblk->cv.broadcast();
Eric Laurent421ddc02011-03-07 14:52:59 -0800788 } else {
789 if (!(cblk->flags & CBLK_RESTORED_MSK)) {
790 LOGW("dead IAudioRecord, waiting for a new one to be created");
791 mLock.unlock();
792 result = cblk->cv.waitRelative(cblk->lock, milliseconds(RESTORE_TIMEOUT_MS));
793 cblk->lock.unlock();
794 mLock.lock();
795 } else {
796 LOGW("dead IAudioRecord, already restored");
797 result = NO_ERROR;
798 cblk->lock.unlock();
799 }
800 if (result != NO_ERROR || mActive == 0) {
801 result = status_t(STOPPED);
802 }
803 }
Steve Block71f2cf12011-10-20 11:56:00 +0100804 ALOGV("restoreRecord_l() status %d mActive %d cblk %p, old cblk %p flags %08x old flags %08x",
Eric Laurent421ddc02011-03-07 14:52:59 -0800805 result, mActive, mCblk, cblk, mCblk->flags, cblk->flags);
806
807 if (result == NO_ERROR) {
808 // from now on we switch to the newly created cblk
809 cblk = mCblk;
810 }
811 cblk->lock.lock();
812
813 LOGW_IF(result != NO_ERROR, "restoreRecord_l() error %d", result);
814
815 return result;
816}
817
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800818// =========================================================================
819
820AudioRecord::ClientRecordThread::ClientRecordThread(AudioRecord& receiver, bool bCanCallJava)
821 : Thread(bCanCallJava), mReceiver(receiver)
822{
823}
824
825bool AudioRecord::ClientRecordThread::threadLoop()
826{
827 return mReceiver.processAudioBuffer(this);
828}
829
830// -------------------------------------------------------------------------
831
832}; // namespace android
833