diff options
Diffstat (limited to 'media/libmedia/AudioRecord.cpp')
-rw-r--r-- | media/libmedia/AudioRecord.cpp | 81 |
1 files changed, 55 insertions, 26 deletions
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 666fafa..a999e7e 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -71,7 +71,7 @@ status_t AudioRecord::getMinFrameCount( // --------------------------------------------------------------------------- AudioRecord::AudioRecord() - : mStatus(NO_INIT), mSessionId(0), + : mStatus(NO_INIT), mSessionId(AUDIO_SESSION_ALLOCATE), mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT) { } @@ -88,7 +88,7 @@ AudioRecord::AudioRecord( int sessionId, transfer_type transferType, audio_input_flags_t flags) - : mStatus(NO_INIT), mSessionId(0), + : mStatus(NO_INIT), mSessionId(AUDIO_SESSION_ALLOCATE), mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT), mProxy(NULL) @@ -233,7 +233,7 @@ status_t AudioRecord::set( mNotificationFramesReq = notificationFrames; mNotificationFramesAct = 0; - if (sessionId == 0 ) { + if (sessionId == AUDIO_SESSION_ALLOCATE) { mSessionId = AudioSystem::newAudioSessionId(); } else { mSessionId = sessionId; @@ -244,7 +244,7 @@ status_t AudioRecord::set( // create the IAudioRecord status = openRecord_l(0 /*epoch*/); - if (status) { + if (status != NO_ERROR) { return status; } @@ -255,9 +255,6 @@ status_t AudioRecord::set( mStatus = NO_ERROR; - // Update buffer size in case it has been limited by AudioFlinger during track creation - mFrameCount = mCblk->frameCount_; - mActive = false; mCbf = cbf; mRefreshRemaining = true; @@ -289,6 +286,9 @@ status_t AudioRecord::start(AudioSystem::sync_event_t event, int triggerSession) // reset current position as seen by client to 0 mProxy->setEpoch(mProxy->getEpoch() - mProxy->getPosition()); + // force refresh of remaining frames by processAudioBuffer() as last + // read before stop could be partial. + mRefreshRemaining = true; mNewPosition = mProxy->getPosition() + mUpdatePeriod; int32_t flags = android_atomic_acquire_load(&mCblk->mFlags); @@ -352,6 +352,7 @@ bool AudioRecord::stopped() const status_t AudioRecord::setMarkerPosition(uint32_t marker) { + // The only purpose of setting marker position is to get a callback if (mCbf == NULL) { return INVALID_OPERATION; } @@ -377,6 +378,7 @@ status_t AudioRecord::getMarkerPosition(uint32_t *marker) const status_t AudioRecord::setPositionUpdatePeriod(uint32_t updatePeriod) { + // The only purpose of setting position update period is to get a callback if (mCbf == NULL) { return INVALID_OPERATION; } @@ -412,7 +414,7 @@ status_t AudioRecord::getPosition(uint32_t *position) const return NO_ERROR; } -unsigned int AudioRecord::getInputFramesLost() const +uint32_t AudioRecord::getInputFramesLost() const { // no need to check mActive, because if inactive this will return 0, which is what we want return AudioSystem::getInputFramesLost(getInput()); @@ -461,24 +463,31 @@ status_t AudioRecord::openRecord_l(size_t epoch) ALOGE("Could not get audio input for record source %d", mInputSource); return BAD_VALUE; } + { + // Now that we have a reference to an I/O handle and have not yet handed it off to AudioFlinger, + // we must release it ourselves if anything goes wrong. + size_t temp = mFrameCount; // temp may be replaced by a revised value of frameCount, + // but we will still need the original value also int originalSessionId = mSessionId; sp<IAudioRecord> record = audioFlinger->openRecord(input, mSampleRate, mFormat, mChannelMask, - mFrameCount, + &temp, &trackFlags, tid, &mSessionId, &status); - ALOGE_IF(originalSessionId != 0 && mSessionId != originalSessionId, + ALOGE_IF(originalSessionId != AUDIO_SESSION_ALLOCATE && mSessionId != originalSessionId, "session ID changed from %d to %d", originalSessionId, mSessionId); if (record == 0 || status != NO_ERROR) { ALOGE("AudioFlinger could not create record track, status: %d", status); - AudioSystem::releaseInput(input); - return status; + goto release; } + // AudioFlinger now owns the reference to the I/O handle, + // so we are no longer responsible for releasing it. + sp<IMemory> iMem = record->getCblk(); if (iMem == 0) { ALOGE("Could not get control block"); @@ -493,11 +502,19 @@ status_t AudioRecord::openRecord_l(size_t epoch) mAudioRecord->asBinder()->unlinkToDeath(mDeathNotifier, this); mDeathNotifier.clear(); } + + // We retain a copy of the I/O handle, but don't own the reference mInput = input; mAudioRecord = record; mCblkMemory = iMem; audio_track_cblk_t* cblk = static_cast<audio_track_cblk_t*>(iMemPointer); mCblk = cblk; + // note that temp is the (possibly revised) value of mFrameCount + if (temp < mFrameCount || (mFrameCount == 0 && temp == 0)) { + ALOGW("Requested frameCount %u but received frameCount %u", mFrameCount, temp); + } + mFrameCount = temp; + // FIXME missing fast track frameCount logic mAwaitBoost = false; if (mFlags & AUDIO_INPUT_FLAG_FAST) { @@ -530,6 +547,14 @@ status_t AudioRecord::openRecord_l(size_t epoch) mAudioRecord->asBinder()->linkToDeath(mDeathNotifier, this); return NO_ERROR; + } + +release: + AudioSystem::releaseInput(input); + if (status == NO_ERROR) { + status = NO_INIT; + } + return status; } status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) @@ -591,6 +616,9 @@ status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, const struct timespec *r if (newSequence == oldSequence) { status = restoreRecord_l("obtainBuffer"); if (status != NO_ERROR) { + buffer.mFrameCount = 0; + buffer.mRaw = NULL; + buffer.mNonContig = 0; break; } } @@ -692,7 +720,7 @@ ssize_t AudioRecord::read(void* buffer, size_t userSize) // ------------------------------------------------------------------------- -nsecs_t AudioRecord::processAudioBuffer(const sp<AudioRecordThread>& thread) +nsecs_t AudioRecord::processAudioBuffer() { mLock.lock(); if (mAwaitBoost) { @@ -767,10 +795,10 @@ nsecs_t AudioRecord::processAudioBuffer(const sp<AudioRecordThread>& thread) mRetryOnPartialBuffer = false; } size_t misalignment = mProxy->getMisalignment(); - int32_t sequence = mSequence; + uint32_t sequence = mSequence; // These fields don't need to be cached, because they are assigned only by set(): - // mTransfer, mCbf, mUserData, mSampleRate + // mTransfer, mCbf, mUserData, mSampleRate, mFrameSize mLock.unlock(); @@ -844,8 +872,8 @@ nsecs_t AudioRecord::processAudioBuffer(const sp<AudioRecordThread>& thread) "obtainBuffer() err=%d frameCount=%u", err, audioBuffer.frameCount); requested = &ClientProxy::kNonBlocking; size_t avail = audioBuffer.frameCount + nonContig; - ALOGV("obtainBuffer(%u) returned %u = %u + %u", - mRemainingFrames, avail, audioBuffer.frameCount, nonContig); + ALOGV("obtainBuffer(%u) returned %u = %u + %u err %d", + mRemainingFrames, avail, audioBuffer.frameCount, nonContig, err); if (err != NO_ERROR) { if (err == TIMED_OUT || err == WOULD_BLOCK || err == -EINTR) { break; @@ -954,7 +982,7 @@ status_t AudioRecord::restoreRecord_l(const char *from) // ========================================================================= -void AudioRecord::DeathNotifier::binderDied(const wp<IBinder>& who) +void AudioRecord::DeathNotifier::binderDied(const wp<IBinder>& who __unused) { sp<AudioRecord> audioRecord = mAudioRecord.promote(); if (audioRecord != 0) { @@ -966,7 +994,8 @@ void AudioRecord::DeathNotifier::binderDied(const wp<IBinder>& who) // ========================================================================= AudioRecord::AudioRecordThread::AudioRecordThread(AudioRecord& receiver, bool bCanCallJava) - : Thread(bCanCallJava), mReceiver(receiver), mPaused(true), mPausedInt(false), mPausedNs(0LL) + : Thread(bCanCallJava), mReceiver(receiver), mPaused(true), mPausedInt(false), mPausedNs(0LL), + mIgnoreNextPausedInt(false) { } @@ -983,6 +1012,10 @@ bool AudioRecord::AudioRecordThread::threadLoop() // caller will check for exitPending() return true; } + if (mIgnoreNextPausedInt) { + mIgnoreNextPausedInt = false; + mPausedInt = false; + } if (mPausedInt) { if (mPausedNs > 0) { (void) mMyCond.waitRelative(mMyLock, mPausedNs); @@ -993,7 +1026,7 @@ bool AudioRecord::AudioRecordThread::threadLoop() return true; } } - nsecs_t ns = mReceiver.processAudioBuffer(this); + nsecs_t ns = mReceiver.processAudioBuffer(); switch (ns) { case 0: return true; @@ -1017,12 +1050,7 @@ void AudioRecord::AudioRecordThread::requestExit() { // must be in this order to avoid a race condition Thread::requestExit(); - AutoMutex _l(mMyLock); - if (mPaused || mPausedInt) { - mPaused = false; - mPausedInt = false; - mMyCond.signal(); - } + resume(); } void AudioRecord::AudioRecordThread::pause() @@ -1034,6 +1062,7 @@ void AudioRecord::AudioRecordThread::pause() void AudioRecord::AudioRecordThread::resume() { AutoMutex _l(mMyLock); + mIgnoreNextPausedInt = true; if (mPaused || mPausedInt) { mPaused = false; mPausedInt = false; |