blob: 22c3a1870d1058d4542cb92f5599665db5fba111 [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,
Glenn Kasten0a204ed2012-01-12 12:27:51 -080051 audio_format_t format,
Chia-chi Yeh97d61f72010-06-22 08:01:13 +080052 int channelCount)
53{
54 size_t size = 0;
55 if (AudioSystem::getInputBufferSize(sampleRate, format, channelCount, &size)
56 != NO_ERROR) {
Steve Block3762c312012-01-06 19:20:56 +000057 ALOGE("AudioSystem could not query the input buffer size.");
Chia-chi Yeh97d61f72010-06-22 08:01:13 +080058 return NO_INIT;
59 }
60
61 if (size == 0) {
Steve Block3762c312012-01-06 19:20:56 +000062 ALOGE("Unsupported configuration: sampleRate %d, format %d, channelCount %d",
Chia-chi Yeh97d61f72010-06-22 08:01:13 +080063 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(
Glenn Kasten0f0fbd92012-01-23 13:58:49 -080087 audio_source_t inputSource,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088 uint32_t sampleRate,
Glenn Kasten0a204ed2012-01-12 12:27:51 -080089 audio_format_t 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,
Glenn Kastenf60a5d72012-03-07 09:04:02 -080092 record_flags flags,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093 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(
Glenn Kasten0f0fbd92012-01-23 13:58:49 -0800122 audio_source_t inputSource,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800123 uint32_t sampleRate,
Glenn Kasten0a204ed2012-01-12 12:27:51 -0800124 audio_format_t 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,
Glenn Kastenf60a5d72012-03-07 09:04:02 -0800127 record_flags flags,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800128 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...
Glenn Kasten0a204ed2012-01-12 12:27:51 -0800151 if (format == AUDIO_FORMAT_DEFAULT) {
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)) {
Steve Block3762c312012-01-06 19:20:56 +0000156 ALOGE("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) {
Steve Block3762c312012-01-06 19:20:56 +0000180 ALOGE("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
Glenn Kasten3694ec12012-01-27 16:47:15 -0800209 if (cbf != NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800210 mClientRecordThread = new ClientRecordThread(*this, threadCanCallJava);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800211 }
212
213 mStatus = NO_ERROR;
214
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800215 mFormat = format;
216 // Update buffer size in case it has been limited by AudioFlinger during track creation
217 mFrameCount = mCblk->frameCount;
Eric Laurenta553c252009-07-17 12:17:14 -0700218 mChannelCount = (uint8_t)channelCount;
Jean-Michel Trivi54392232011-05-24 15:53:33 -0700219 mChannelMask = channelMask;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800220 mActive = 0;
221 mCbf = cbf;
222 mNotificationFrames = notificationFrames;
223 mRemainingFrames = notificationFrames;
224 mUserData = user;
225 // TODO: add audio hardware input latency here
Eric Laurent88e209d2009-07-07 07:10:45 -0700226 mLatency = (1000*mFrameCount) / sampleRate;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800227 mMarkerPosition = 0;
Jean-Michel Trivi78c13142009-03-24 19:48:58 -0700228 mMarkerReached = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800229 mNewPosition = 0;
230 mUpdatePeriod = 0;
Glenn Kasten0f0fbd92012-01-23 13:58:49 -0800231 mInputSource = inputSource;
Eric Laurentbda74692009-11-04 08:27:26 -0800232 mFlags = flags;
Eric Laurent47d0a922010-02-26 02:47:27 -0800233 mInput = input;
Marco Nelissenc74b93f2011-08-02 13:33:41 -0700234 AudioSystem::acquireAudioSessionId(mSessionId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800235
236 return NO_ERROR;
237}
238
239status_t AudioRecord::initCheck() const
240{
241 return mStatus;
242}
243
244// -------------------------------------------------------------------------
245
246uint32_t AudioRecord::latency() const
247{
248 return mLatency;
249}
250
Glenn Kasten0a204ed2012-01-12 12:27:51 -0800251audio_format_t AudioRecord::format() const
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800252{
253 return mFormat;
254}
255
256int AudioRecord::channelCount() const
257{
258 return mChannelCount;
259}
260
261uint32_t AudioRecord::frameCount() const
262{
263 return mFrameCount;
264}
265
Glenn Kastenfaf354d2012-01-11 09:48:27 -0800266size_t AudioRecord::frameSize() const
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800267{
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700268 if (audio_is_linear_pcm(mFormat)) {
Eric Laurentc310dcb2011-06-16 21:30:45 -0700269 return channelCount()*audio_bytes_per_sample(mFormat);
Eric Laurenta553c252009-07-17 12:17:14 -0700270 } else {
271 return sizeof(uint8_t);
272 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800273}
274
Glenn Kasten0f0fbd92012-01-23 13:58:49 -0800275audio_source_t AudioRecord::inputSource() const
Eric Laurent4bc035a2009-05-22 09:18:15 -0700276{
Glenn Kasten0f0fbd92012-01-23 13:58:49 -0800277 return mInputSource;
Eric Laurent4bc035a2009-05-22 09:18:15 -0700278}
279
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800280// -------------------------------------------------------------------------
281
282status_t AudioRecord::start()
283{
284 status_t ret = NO_ERROR;
285 sp<ClientRecordThread> t = mClientRecordThread;
286
Steve Block71f2cf12011-10-20 11:56:00 +0100287 ALOGV("start");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800288
289 if (t != 0) {
290 if (t->exitPending()) {
291 if (t->requestExitAndWait() == WOULD_BLOCK) {
Steve Block3762c312012-01-06 19:20:56 +0000292 ALOGE("AudioRecord::start called from thread");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800293 return WOULD_BLOCK;
294 }
295 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800296 }
297
Eric Laurentf3d6dd02010-11-18 08:40:16 -0800298 AutoMutex lock(mLock);
Eric Laurent421ddc02011-03-07 14:52:59 -0800299 // acquire a strong reference on the IAudioRecord and IMemory so that they cannot be destroyed
300 // while we are accessing the cblk
301 sp <IAudioRecord> audioRecord = mAudioRecord;
302 sp <IMemory> iMem = mCblkMemory;
303 audio_track_cblk_t* cblk = mCblk;
Eric Laurentf3d6dd02010-11-18 08:40:16 -0800304 if (mActive == 0) {
305 mActive = 1;
Eric Laurent421ddc02011-03-07 14:52:59 -0800306
Glenn Kasten6a20b262012-02-02 10:56:47 -0800307 pid_t tid;
308 if (t != 0) {
309 mReadyToRun = WOULD_BLOCK;
Glenn Kasten86e33622012-02-28 12:30:08 -0800310 t->run("AudioRecord", ANDROID_PRIORITY_AUDIO);
Glenn Kasten6a20b262012-02-02 10:56:47 -0800311 tid = t->getTid(); // pid_t is unknown until run()
312 ALOGV("getTid=%d", tid);
313 if (tid == -1) {
314 tid = 0;
315 }
316 // thread blocks in readyToRun()
317 } else {
318 tid = 0; // not gettid()
319 }
320
Eric Laurent421ddc02011-03-07 14:52:59 -0800321 cblk->lock.lock();
322 if (!(cblk->flags & CBLK_INVALID_MSK)) {
323 cblk->lock.unlock();
Glenn Kasten6a20b262012-02-02 10:56:47 -0800324 ALOGV("mAudioRecord->start(tid=%d)", tid);
325 ret = mAudioRecord->start(tid);
Eric Laurent421ddc02011-03-07 14:52:59 -0800326 cblk->lock.lock();
327 if (ret == DEAD_OBJECT) {
Eric Laurentae29b762011-03-28 18:37:07 -0700328 android_atomic_or(CBLK_INVALID_ON, &cblk->flags);
Eric Laurentbda74692009-11-04 08:27:26 -0800329 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800330 }
Eric Laurent421ddc02011-03-07 14:52:59 -0800331 if (cblk->flags & CBLK_INVALID_MSK) {
332 ret = restoreRecord_l(cblk);
333 }
334 cblk->lock.unlock();
Eric Laurent49f02be2009-11-19 09:00:56 -0800335 if (ret == NO_ERROR) {
Eric Laurent421ddc02011-03-07 14:52:59 -0800336 mNewPosition = cblk->user + mUpdatePeriod;
337 cblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
338 cblk->waitTimeMs = 0;
Eric Laurent49f02be2009-11-19 09:00:56 -0800339 if (t != 0) {
Glenn Kasten6a20b262012-02-02 10:56:47 -0800340 // thread unblocks in readyToRun() and returns NO_ERROR
341 mReadyToRun = NO_ERROR;
342 mCondition.signal();
Eric Laurent49f02be2009-11-19 09:00:56 -0800343 } else {
Glenn Kasten99d54432011-06-22 16:15:25 -0700344 mPreviousPriority = getpriority(PRIO_PROCESS, 0);
345 mPreviousSchedulingGroup = androidGetThreadSchedulingGroup(0);
346 androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO);
Eric Laurent49f02be2009-11-19 09:00:56 -0800347 }
348 } else {
Eric Laurentf3d6dd02010-11-18 08:40:16 -0800349 mActive = 0;
Glenn Kasten6a20b262012-02-02 10:56:47 -0800350 // thread unblocks in readyToRun() and returns NO_INIT
351 mReadyToRun = NO_INIT;
352 mCondition.signal();
Eric Laurent49f02be2009-11-19 09:00:56 -0800353 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800354 }
355
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800356 return ret;
357}
358
359status_t AudioRecord::stop()
360{
361 sp<ClientRecordThread> t = mClientRecordThread;
362
Steve Block71f2cf12011-10-20 11:56:00 +0100363 ALOGV("stop");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800364
Eric Laurentf3d6dd02010-11-18 08:40:16 -0800365 AutoMutex lock(mLock);
366 if (mActive == 1) {
367 mActive = 0;
Eric Laurentef028272009-04-21 07:56:33 -0700368 mCblk->cv.signal();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800369 mAudioRecord->stop();
Jean-Michel Trivi78c13142009-03-24 19:48:58 -0700370 // the record head position will reset to 0, so if a marker is set, we need
371 // to activate it again
372 mMarkerReached = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800373 if (t != 0) {
374 t->requestExit();
375 } else {
Glenn Kasten99d54432011-06-22 16:15:25 -0700376 setpriority(PRIO_PROCESS, 0, mPreviousPriority);
377 androidSetThreadSchedulingGroup(0, mPreviousSchedulingGroup);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800378 }
379 }
380
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800381 return NO_ERROR;
382}
383
384bool AudioRecord::stopped() const
385{
386 return !mActive;
387}
388
Glenn Kastenbd714b62012-02-24 16:33:14 -0800389uint32_t AudioRecord::getSampleRate() const
Eric Laurent88e209d2009-07-07 07:10:45 -0700390{
Eric Laurent421ddc02011-03-07 14:52:59 -0800391 AutoMutex lock(mLock);
Eric Laurent88e209d2009-07-07 07:10:45 -0700392 return mCblk->sampleRate;
393}
394
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800395status_t AudioRecord::setMarkerPosition(uint32_t marker)
396{
Glenn Kasten3694ec12012-01-27 16:47:15 -0800397 if (mCbf == NULL) return INVALID_OPERATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800398
399 mMarkerPosition = marker;
Jean-Michel Trivi78c13142009-03-24 19:48:58 -0700400 mMarkerReached = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800401
402 return NO_ERROR;
403}
404
Glenn Kastenbd714b62012-02-24 16:33:14 -0800405status_t AudioRecord::getMarkerPosition(uint32_t *marker) const
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800406{
Glenn Kasten3694ec12012-01-27 16:47:15 -0800407 if (marker == NULL) return BAD_VALUE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800408
409 *marker = mMarkerPosition;
410
411 return NO_ERROR;
412}
413
414status_t AudioRecord::setPositionUpdatePeriod(uint32_t updatePeriod)
415{
Glenn Kasten3694ec12012-01-27 16:47:15 -0800416 if (mCbf == NULL) return INVALID_OPERATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800417
418 uint32_t curPosition;
419 getPosition(&curPosition);
420 mNewPosition = curPosition + updatePeriod;
421 mUpdatePeriod = updatePeriod;
422
423 return NO_ERROR;
424}
425
Glenn Kastenbd714b62012-02-24 16:33:14 -0800426status_t AudioRecord::getPositionUpdatePeriod(uint32_t *updatePeriod) const
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800427{
Glenn Kasten3694ec12012-01-27 16:47:15 -0800428 if (updatePeriod == NULL) return BAD_VALUE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800429
430 *updatePeriod = mUpdatePeriod;
431
432 return NO_ERROR;
433}
434
Glenn Kastenbd714b62012-02-24 16:33:14 -0800435status_t AudioRecord::getPosition(uint32_t *position) const
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800436{
Glenn Kasten3694ec12012-01-27 16:47:15 -0800437 if (position == NULL) return BAD_VALUE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800438
Eric Laurent421ddc02011-03-07 14:52:59 -0800439 AutoMutex lock(mLock);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800440 *position = mCblk->user;
441
442 return NO_ERROR;
443}
444
Glenn Kastenbd714b62012-02-24 16:33:14 -0800445unsigned int AudioRecord::getInputFramesLost() const
Eric Laurent47d0a922010-02-26 02:47:27 -0800446{
447 if (mActive)
448 return AudioSystem::getInputFramesLost(mInput);
449 else
450 return 0;
451}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800452
453// -------------------------------------------------------------------------
454
Eric Laurent421ddc02011-03-07 14:52:59 -0800455// must be called with mLock held
456status_t AudioRecord::openRecord_l(
Eric Laurentbda74692009-11-04 08:27:26 -0800457 uint32_t sampleRate,
Glenn Kasten0a204ed2012-01-12 12:27:51 -0800458 audio_format_t format,
Jean-Michel Trivi54392232011-05-24 15:53:33 -0700459 uint32_t channelMask,
Eric Laurentbda74692009-11-04 08:27:26 -0800460 int frameCount,
Eric Laurent49f02be2009-11-19 09:00:56 -0800461 uint32_t flags,
462 audio_io_handle_t input)
Eric Laurentbda74692009-11-04 08:27:26 -0800463{
464 status_t status;
465 const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
466 if (audioFlinger == 0) {
467 return NO_INIT;
468 }
469
Eric Laurent49f02be2009-11-19 09:00:56 -0800470 sp<IAudioRecord> record = audioFlinger->openRecord(getpid(), input,
Eric Laurentbda74692009-11-04 08:27:26 -0800471 sampleRate, format,
Jean-Michel Trivi54392232011-05-24 15:53:33 -0700472 channelMask,
Eric Laurentbda74692009-11-04 08:27:26 -0800473 frameCount,
474 ((uint16_t)flags) << 16,
Eric Laurent65b65452010-06-01 23:49:17 -0700475 &mSessionId,
Eric Laurentbda74692009-11-04 08:27:26 -0800476 &status);
Marco Nelissenc74b93f2011-08-02 13:33:41 -0700477
Eric Laurentbda74692009-11-04 08:27:26 -0800478 if (record == 0) {
Steve Block3762c312012-01-06 19:20:56 +0000479 ALOGE("AudioFlinger could not create record track, status: %d", status);
Eric Laurentbda74692009-11-04 08:27:26 -0800480 return status;
481 }
482 sp<IMemory> cblk = record->getCblk();
483 if (cblk == 0) {
Steve Block3762c312012-01-06 19:20:56 +0000484 ALOGE("Could not get control block");
Eric Laurentbda74692009-11-04 08:27:26 -0800485 return NO_INIT;
486 }
487 mAudioRecord.clear();
488 mAudioRecord = record;
489 mCblkMemory.clear();
490 mCblkMemory = cblk;
491 mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer());
492 mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
Eric Laurentae29b762011-03-28 18:37:07 -0700493 android_atomic_and(~CBLK_DIRECTION_MSK, &mCblk->flags);
Eric Laurent49f02be2009-11-19 09:00:56 -0800494 mCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
495 mCblk->waitTimeMs = 0;
Eric Laurentbda74692009-11-04 08:27:26 -0800496 return NO_ERROR;
497}
498
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800499status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
500{
Eric Laurent421ddc02011-03-07 14:52:59 -0800501 AutoMutex lock(mLock);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800502 int active;
Glenn Kasten028ab992011-06-22 16:18:04 -0700503 status_t result = NO_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800504 audio_track_cblk_t* cblk = mCblk;
505 uint32_t framesReq = audioBuffer->frameCount;
Eric Laurentef028272009-04-21 07:56:33 -0700506 uint32_t waitTimeMs = (waitCount < 0) ? cblk->bufferTimeoutMs : WAIT_PERIOD_MS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800507
508 audioBuffer->frameCount = 0;
509 audioBuffer->size = 0;
510
511 uint32_t framesReady = cblk->framesReady();
512
513 if (framesReady == 0) {
Eric Laurentbda74692009-11-04 08:27:26 -0800514 cblk->lock.lock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800515 goto start_loop_here;
516 while (framesReady == 0) {
517 active = mActive;
Glenn Kastene80a4cc2011-12-15 09:51:17 -0800518 if (CC_UNLIKELY(!active)) {
Eric Laurentbda74692009-11-04 08:27:26 -0800519 cblk->lock.unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800520 return NO_MORE_BUFFERS;
Eric Laurentbda74692009-11-04 08:27:26 -0800521 }
Glenn Kastene80a4cc2011-12-15 09:51:17 -0800522 if (CC_UNLIKELY(!waitCount)) {
Eric Laurentbda74692009-11-04 08:27:26 -0800523 cblk->lock.unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800524 return WOULD_BLOCK;
Eric Laurentbda74692009-11-04 08:27:26 -0800525 }
Eric Laurent421ddc02011-03-07 14:52:59 -0800526 if (!(cblk->flags & CBLK_INVALID_MSK)) {
527 mLock.unlock();
528 result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs));
529 cblk->lock.unlock();
530 mLock.lock();
531 if (mActive == 0) {
532 return status_t(STOPPED);
533 }
534 cblk->lock.lock();
535 }
536 if (cblk->flags & CBLK_INVALID_MSK) {
537 goto create_new_record;
538 }
Glenn Kastene80a4cc2011-12-15 09:51:17 -0800539 if (CC_UNLIKELY(result != NO_ERROR)) {
Eric Laurentef028272009-04-21 07:56:33 -0700540 cblk->waitTimeMs += waitTimeMs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800541 if (cblk->waitTimeMs >= cblk->bufferTimeoutMs) {
Steve Block8564c8d2012-01-05 23:22:43 +0000542 ALOGW( "obtainBuffer timed out (is the CPU pegged?) "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800543 "user=%08x, server=%08x", cblk->user, cblk->server);
Eric Laurentbda74692009-11-04 08:27:26 -0800544 cblk->lock.unlock();
Glenn Kasten6a20b262012-02-02 10:56:47 -0800545 result = mAudioRecord->start(0); // callback thread hasn't changed
Eric Laurentbda74692009-11-04 08:27:26 -0800546 cblk->lock.lock();
Eric Laurent421ddc02011-03-07 14:52:59 -0800547 if (result == DEAD_OBJECT) {
Eric Laurentae29b762011-03-28 18:37:07 -0700548 android_atomic_or(CBLK_INVALID_ON, &cblk->flags);
Eric Laurent421ddc02011-03-07 14:52:59 -0800549create_new_record:
550 result = AudioRecord::restoreRecord_l(cblk);
551 }
552 if (result != NO_ERROR) {
Steve Block8564c8d2012-01-05 23:22:43 +0000553 ALOGW("obtainBuffer create Track error %d", result);
Eric Laurent421ddc02011-03-07 14:52:59 -0800554 cblk->lock.unlock();
555 return result;
556 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800557 cblk->waitTimeMs = 0;
558 }
559 if (--waitCount == 0) {
Eric Laurentbda74692009-11-04 08:27:26 -0800560 cblk->lock.unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800561 return TIMED_OUT;
562 }
563 }
564 // read the server count again
565 start_loop_here:
566 framesReady = cblk->framesReady();
567 }
Eric Laurentbda74692009-11-04 08:27:26 -0800568 cblk->lock.unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800569 }
570
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800571 cblk->waitTimeMs = 0;
Eric Laurenta553c252009-07-17 12:17:14 -0700572
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800573 if (framesReq > framesReady) {
574 framesReq = framesReady;
575 }
576
577 uint32_t u = cblk->user;
578 uint32_t bufferEnd = cblk->userBase + cblk->frameCount;
579
580 if (u + framesReq > bufferEnd) {
581 framesReq = bufferEnd - u;
582 }
583
584 audioBuffer->flags = 0;
585 audioBuffer->channelCount= mChannelCount;
586 audioBuffer->format = mFormat;
587 audioBuffer->frameCount = framesReq;
Eric Laurenta553c252009-07-17 12:17:14 -0700588 audioBuffer->size = framesReq*cblk->frameSize;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800589 audioBuffer->raw = (int8_t*)cblk->buffer(u);
590 active = mActive;
591 return active ? status_t(NO_ERROR) : status_t(STOPPED);
592}
593
594void AudioRecord::releaseBuffer(Buffer* audioBuffer)
595{
Eric Laurent421ddc02011-03-07 14:52:59 -0800596 AutoMutex lock(mLock);
597 mCblk->stepUser(audioBuffer->frameCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800598}
599
Glenn Kastenbd714b62012-02-24 16:33:14 -0800600audio_io_handle_t AudioRecord::getInput() const
Eric Laurent49f02be2009-11-19 09:00:56 -0800601{
Eric Laurent421ddc02011-03-07 14:52:59 -0800602 AutoMutex lock(mLock);
Eric Laurent678cc952011-07-26 20:32:28 -0700603 return mInput;
Eric Laurent421ddc02011-03-07 14:52:59 -0800604}
605
606// must be called with mLock held
607audio_io_handle_t AudioRecord::getInput_l()
608{
Eric Laurent47d0a922010-02-26 02:47:27 -0800609 mInput = AudioSystem::getInput(mInputSource,
Eric Laurent49f02be2009-11-19 09:00:56 -0800610 mCblk->sampleRate,
Eric Laurent464d5b32011-06-17 21:29:58 -0700611 mFormat,
612 mChannelMask,
613 (audio_in_acoustics_t)mFlags,
614 mSessionId);
Eric Laurent47d0a922010-02-26 02:47:27 -0800615 return mInput;
Eric Laurent49f02be2009-11-19 09:00:56 -0800616}
617
Glenn Kastenbd714b62012-02-24 16:33:14 -0800618int AudioRecord::getSessionId() const
Eric Laurent65b65452010-06-01 23:49:17 -0700619{
620 return mSessionId;
621}
622
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800623// -------------------------------------------------------------------------
624
625ssize_t AudioRecord::read(void* buffer, size_t userSize)
626{
627 ssize_t read = 0;
628 Buffer audioBuffer;
629 int8_t *dst = static_cast<int8_t*>(buffer);
630
631 if (ssize_t(userSize) < 0) {
632 // sanity-check. user is most-likely passing an error code.
Steve Block3762c312012-01-06 19:20:56 +0000633 ALOGE("AudioRecord::read(buffer=%p, size=%u (%d)",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800634 buffer, userSize, userSize);
635 return BAD_VALUE;
636 }
637
Eric Laurent421ddc02011-03-07 14:52:59 -0800638 mLock.lock();
639 // acquire a strong reference on the IAudioRecord and IMemory so that they cannot be destroyed
640 // while we are accessing the cblk
641 sp <IAudioRecord> audioRecord = mAudioRecord;
642 sp <IMemory> iMem = mCblkMemory;
643 mLock.unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800644
645 do {
646
Eric Laurenta553c252009-07-17 12:17:14 -0700647 audioBuffer.frameCount = userSize/frameSize();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800648
Eric Laurentba8811f2010-03-02 18:38:06 -0800649 // By using a wait count corresponding to twice the timeout period in
650 // obtainBuffer() we give a chance to recover once for a read timeout
651 // (if media_server crashed for instance) before returning a length of
652 // 0 bytes read to the client
653 status_t err = obtainBuffer(&audioBuffer, ((2 * MAX_RUN_TIMEOUT_MS) / WAIT_PERIOD_MS));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800654 if (err < 0) {
655 // out of buffers, return #bytes written
656 if (err == status_t(NO_MORE_BUFFERS))
657 break;
Eric Laurentba8811f2010-03-02 18:38:06 -0800658 if (err == status_t(TIMED_OUT))
659 err = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800660 return ssize_t(err);
661 }
662
663 size_t bytesRead = audioBuffer.size;
664 memcpy(dst, audioBuffer.i8, bytesRead);
665
666 dst += bytesRead;
667 userSize -= bytesRead;
668 read += bytesRead;
669
670 releaseBuffer(&audioBuffer);
671 } while (userSize);
672
673 return read;
674}
675
676// -------------------------------------------------------------------------
677
678bool AudioRecord::processAudioBuffer(const sp<ClientRecordThread>& thread)
679{
680 Buffer audioBuffer;
681 uint32_t frames = mRemainingFrames;
682 size_t readSize;
683
Eric Laurent421ddc02011-03-07 14:52:59 -0800684 mLock.lock();
685 // acquire a strong reference on the IAudioRecord and IMemory so that they cannot be destroyed
686 // while we are accessing the cblk
687 sp <IAudioRecord> audioRecord = mAudioRecord;
688 sp <IMemory> iMem = mCblkMemory;
689 audio_track_cblk_t* cblk = mCblk;
690 mLock.unlock();
691
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800692 // Manage marker callback
Jean-Michel Trivi78c13142009-03-24 19:48:58 -0700693 if (!mMarkerReached && (mMarkerPosition > 0)) {
Eric Laurent421ddc02011-03-07 14:52:59 -0800694 if (cblk->user >= mMarkerPosition) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800695 mCbf(EVENT_MARKER, mUserData, (void *)&mMarkerPosition);
Jean-Michel Trivi78c13142009-03-24 19:48:58 -0700696 mMarkerReached = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800697 }
698 }
699
700 // Manage new position callback
701 if (mUpdatePeriod > 0) {
Eric Laurent421ddc02011-03-07 14:52:59 -0800702 while (cblk->user >= mNewPosition) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800703 mCbf(EVENT_NEW_POS, mUserData, (void *)&mNewPosition);
704 mNewPosition += mUpdatePeriod;
705 }
706 }
707
708 do {
709 audioBuffer.frameCount = frames;
Eric Laurenta553c252009-07-17 12:17:14 -0700710 // Calling obtainBuffer() with a wait count of 1
711 // limits wait time to WAIT_PERIOD_MS. This prevents from being
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800712 // stuck here not being able to handle timed events (position, markers).
713 status_t err = obtainBuffer(&audioBuffer, 1);
714 if (err < NO_ERROR) {
715 if (err != TIMED_OUT) {
Steve Block3762c312012-01-06 19:20:56 +0000716 ALOGE_IF(err != status_t(NO_MORE_BUFFERS), "Error obtaining an audio buffer, giving up.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800717 return false;
718 }
719 break;
720 }
721 if (err == status_t(STOPPED)) return false;
722
723 size_t reqSize = audioBuffer.size;
724 mCbf(EVENT_MORE_DATA, mUserData, &audioBuffer);
725 readSize = audioBuffer.size;
726
727 // Sanity check on returned size
Eric Laurent272beb62009-03-24 21:23:54 -0700728 if (ssize_t(readSize) <= 0) {
729 // The callback is done filling buffers
730 // Keep this thread going to handle timed events and
731 // still try to get more data in intervals of WAIT_PERIOD_MS
732 // but don't just loop and block the CPU, so wait
733 usleep(WAIT_PERIOD_MS*1000);
734 break;
735 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800736 if (readSize > reqSize) readSize = reqSize;
737
738 audioBuffer.size = readSize;
Eric Laurenta553c252009-07-17 12:17:14 -0700739 audioBuffer.frameCount = readSize/frameSize();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800740 frames -= audioBuffer.frameCount;
741
742 releaseBuffer(&audioBuffer);
743
744 } while (frames);
745
Eric Laurenta553c252009-07-17 12:17:14 -0700746
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800747 // Manage overrun callback
Eric Laurent421ddc02011-03-07 14:52:59 -0800748 if (mActive && (cblk->framesAvailable() == 0)) {
Steve Block71f2cf12011-10-20 11:56:00 +0100749 ALOGV("Overrun user: %x, server: %x, flags %04x", cblk->user, cblk->server, cblk->flags);
Eric Laurentae29b762011-03-28 18:37:07 -0700750 if (!(android_atomic_or(CBLK_UNDERRUN_ON, &cblk->flags) & CBLK_UNDERRUN_MSK)) {
Eric Laurent913af0b2011-03-17 09:36:51 -0700751 mCbf(EVENT_OVERRUN, mUserData, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800752 }
753 }
754
755 if (frames == 0) {
756 mRemainingFrames = mNotificationFrames;
757 } else {
758 mRemainingFrames = frames;
759 }
760 return true;
761}
762
Eric Laurent421ddc02011-03-07 14:52:59 -0800763// must be called with mLock and cblk.lock held. Callers must also hold strong references on
764// the IAudioRecord and IMemory in case they are recreated here.
765// If the IAudioRecord is successfully restored, the cblk pointer is updated
766status_t AudioRecord::restoreRecord_l(audio_track_cblk_t*& cblk)
767{
768 status_t result;
769
Eric Laurentae29b762011-03-28 18:37:07 -0700770 if (!(android_atomic_or(CBLK_RESTORING_ON, &cblk->flags) & CBLK_RESTORING_MSK)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000771 ALOGW("dead IAudioRecord, creating a new one");
Eric Laurent421ddc02011-03-07 14:52:59 -0800772 // signal old cblk condition so that other threads waiting for available buffers stop
773 // waiting now
774 cblk->cv.broadcast();
775 cblk->lock.unlock();
776
777 // if the new IAudioRecord is created, openRecord_l() will modify the
778 // following member variables: mAudioRecord, mCblkMemory and mCblk.
779 // It will also delete the strong references on previous IAudioRecord and IMemory
Jean-Michel Trivi54392232011-05-24 15:53:33 -0700780 result = openRecord_l(cblk->sampleRate, mFormat, mChannelMask,
Eric Laurent421ddc02011-03-07 14:52:59 -0800781 mFrameCount, mFlags, getInput_l());
782 if (result == NO_ERROR) {
Glenn Kasten6a20b262012-02-02 10:56:47 -0800783 result = mAudioRecord->start(0); // callback thread hasn't changed
Eric Laurent421ddc02011-03-07 14:52:59 -0800784 }
785 if (result != NO_ERROR) {
786 mActive = false;
787 }
788
789 // signal old cblk condition for other threads waiting for restore completion
Eric Laurentae29b762011-03-28 18:37:07 -0700790 android_atomic_or(CBLK_RESTORED_ON, &cblk->flags);
Eric Laurent421ddc02011-03-07 14:52:59 -0800791 cblk->cv.broadcast();
Eric Laurent421ddc02011-03-07 14:52:59 -0800792 } else {
793 if (!(cblk->flags & CBLK_RESTORED_MSK)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000794 ALOGW("dead IAudioRecord, waiting for a new one to be created");
Eric Laurent421ddc02011-03-07 14:52:59 -0800795 mLock.unlock();
796 result = cblk->cv.waitRelative(cblk->lock, milliseconds(RESTORE_TIMEOUT_MS));
797 cblk->lock.unlock();
798 mLock.lock();
799 } else {
Steve Block8564c8d2012-01-05 23:22:43 +0000800 ALOGW("dead IAudioRecord, already restored");
Eric Laurent421ddc02011-03-07 14:52:59 -0800801 result = NO_ERROR;
802 cblk->lock.unlock();
803 }
804 if (result != NO_ERROR || mActive == 0) {
805 result = status_t(STOPPED);
806 }
807 }
Steve Block71f2cf12011-10-20 11:56:00 +0100808 ALOGV("restoreRecord_l() status %d mActive %d cblk %p, old cblk %p flags %08x old flags %08x",
Eric Laurent421ddc02011-03-07 14:52:59 -0800809 result, mActive, mCblk, cblk, mCblk->flags, cblk->flags);
810
811 if (result == NO_ERROR) {
812 // from now on we switch to the newly created cblk
813 cblk = mCblk;
814 }
815 cblk->lock.lock();
816
Steve Block8564c8d2012-01-05 23:22:43 +0000817 ALOGW_IF(result != NO_ERROR, "restoreRecord_l() error %d", result);
Eric Laurent421ddc02011-03-07 14:52:59 -0800818
819 return result;
820}
821
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800822// =========================================================================
823
824AudioRecord::ClientRecordThread::ClientRecordThread(AudioRecord& receiver, bool bCanCallJava)
825 : Thread(bCanCallJava), mReceiver(receiver)
826{
827}
828
829bool AudioRecord::ClientRecordThread::threadLoop()
830{
831 return mReceiver.processAudioBuffer(this);
832}
833
Glenn Kasten6a20b262012-02-02 10:56:47 -0800834status_t AudioRecord::ClientRecordThread::readyToRun()
835{
836 AutoMutex(mReceiver.mLock);
837 while (mReceiver.mReadyToRun == WOULD_BLOCK) {
838 mReceiver.mCondition.wait(mReceiver.mLock);
839 }
840 return mReceiver.mReadyToRun;
841}
842
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800843// -------------------------------------------------------------------------
844
845}; // namespace android
846