From d776ac63ce9c013c9626226e43f7db606e035838 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Wed, 7 May 2014 09:16:09 -0700 Subject: IAudioFlinger::openRecord returns IMemory(s) openRecord() now explicitly returns the control block and data buffer as separate IMemory references. If the IMemory for data buffer is 0, this means it immediately follows the control block. Change-Id: Ic098f88f0e037f8fbe30006689e18cacacf09d06 --- include/media/AudioRecord.h | 4 +++- include/media/IAudioFlinger.h | 2 ++ media/libmedia/AudioRecord.cpp | 32 +++++++++++++++++++++-------- media/libmedia/IAudioFlinger.cpp | 34 +++++++++++++++++++++++++++---- services/audioflinger/AudioFlinger.cpp | 8 ++++++++ services/audioflinger/AudioFlinger.h | 2 ++ services/audioflinger/RecordTracks.h | 3 ++- services/audioflinger/Threads.cpp | 3 ++- services/audioflinger/TrackBase.h | 6 +++++- services/audioflinger/Tracks.cpp | 37 +++++++++++++++++++++++++--------- 10 files changed, 106 insertions(+), 25 deletions(-) diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h index b3c44a8..6a68c94 100644 --- a/include/media/AudioRecord.h +++ b/include/media/AudioRecord.h @@ -490,10 +490,12 @@ private: int mSessionId; transfer_type mTransfer; - // Next 4 fields may be changed if IAudioRecord is re-created, but always != 0 + // Next 5 fields may be changed if IAudioRecord is re-created, but always != 0 + // provided the initial set() was successful sp mAudioRecord; sp mCblkMemory; audio_track_cblk_t* mCblk; // re-load after mLock.unlock() + sp mBufferMemory; audio_io_handle_t mInput; // returned by AudioSystem::getInput() int mPreviousPriority; // before start() diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h index 9101f06..7db6a48 100644 --- a/include/media/IAudioFlinger.h +++ b/include/media/IAudioFlinger.h @@ -88,6 +88,8 @@ public: track_flags_t *flags, pid_t tid, // -1 means unused, otherwise must be valid non-0 int *sessionId, + sp& cblk, + sp& buffers, // return value 0 means it follows cblk status_t *status) = 0; /* query the audio hardware state. This state never changes, diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 2c8605c..97ab8f8 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -484,6 +484,8 @@ status_t AudioRecord::openRecord_l(size_t epoch) size_t temp = frameCount; // temp may be replaced by a revised value of frameCount, // but we will still need the original value also int originalSessionId = mSessionId; + sp iMem; // for cblk + sp bufferMem; sp record = audioFlinger->openRecord(input, mSampleRate, mFormat, mChannelMask, @@ -491,6 +493,8 @@ status_t AudioRecord::openRecord_l(size_t epoch) &trackFlags, tid, &mSessionId, + iMem, + bufferMem, &status); ALOGE_IF(originalSessionId != AUDIO_SESSION_ALLOCATE && mSessionId != originalSessionId, "session ID changed from %d to %d", originalSessionId, mSessionId); @@ -504,7 +508,6 @@ status_t AudioRecord::openRecord_l(size_t epoch) // AudioFlinger now owns the reference to the I/O handle, // so we are no longer responsible for releasing it. - sp iMem = record->getCblk(); if (iMem == 0) { ALOGE("Could not get control block"); return NO_INIT; @@ -514,6 +517,22 @@ status_t AudioRecord::openRecord_l(size_t epoch) ALOGE("Could not get control block pointer"); return NO_INIT; } + audio_track_cblk_t* cblk = static_cast(iMemPointer); + + // Starting address of buffers in shared memory. + // The buffers are either immediately after the control block, + // or in a separate area at discretion of server. + void *buffers; + if (bufferMem == 0) { + buffers = cblk + 1; + } else { + buffers = bufferMem->pointer(); + if (buffers == NULL) { + ALOGE("Could not get buffer pointer"); + return NO_INIT; + } + } + // invariant that mAudioRecord != 0 is true only after set() returns successfully if (mAudioRecord != 0) { mAudioRecord->asBinder()->unlinkToDeath(mDeathNotifier, this); @@ -522,7 +541,7 @@ status_t AudioRecord::openRecord_l(size_t epoch) mAudioRecord = record; mCblkMemory = iMem; - audio_track_cblk_t* cblk = static_cast(iMemPointer); + mBufferMemory = bufferMem; mCblk = cblk; // note that temp is the (possibly revised) value of frameCount if (temp < frameCount || (frameCount == 0 && temp == 0)) { @@ -552,11 +571,6 @@ status_t AudioRecord::openRecord_l(size_t epoch) mInput = input; mRefreshRemaining = true; - // Starting address of buffers in shared memory, immediately after the control block. This - // address is for the mapping within client address space. AudioFlinger::TrackBase::mBuffer - // is for the server address space. - void *buffers = (char*)cblk + sizeof(audio_track_cblk_t); - mFrameCount = frameCount; // If IAudioRecord is re-created, don't let the requested frameCount // decrease. This can confuse clients that cache frameCount(). @@ -631,6 +645,7 @@ status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, const struct timespec *r // keep them from going away if another thread re-creates the track during obtainBuffer() sp proxy; sp iMem; + sp bufferMem; { // start of lock scope AutoMutex lock(mLock); @@ -654,6 +669,7 @@ status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, const struct timespec *r // Keep the extra references proxy = mProxy; iMem = mCblkMemory; + bufferMem = mBufferMemory; // Non-blocking if track is stopped if (!mActive) { @@ -986,7 +1002,7 @@ status_t AudioRecord::restoreRecord_l(const char *from) status_t result; // if the new IAudioRecord is created, openRecord_l() will modify the - // following member variables: mAudioRecord, mCblkMemory and mCblk. + // following member variables: mAudioRecord, mCblkMemory, mCblk, mBufferMemory. // It will also delete the strong references on previous IAudioRecord and IMemory size_t position = mProxy->getPosition(); mNewPosition = position + mUpdatePeriod; diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp index 1940fe7..0e2463e 100644 --- a/media/libmedia/IAudioFlinger.cpp +++ b/media/libmedia/IAudioFlinger.cpp @@ -169,6 +169,8 @@ public: track_flags_t *flags, pid_t tid, int *sessionId, + sp& cblk, + sp& buffers, status_t *status) { Parcel data, reply; @@ -188,6 +190,8 @@ public: lSessionId = *sessionId; } data.writeInt32(lSessionId); + cblk.clear(); + buffers.clear(); status_t lStatus = remote()->transact(OPEN_RECORD, data, &reply); if (lStatus != NO_ERROR) { ALOGE("openRecord error: %s", strerror(-lStatus)); @@ -206,17 +210,34 @@ public: } lStatus = reply.readInt32(); record = interface_cast(reply.readStrongBinder()); + cblk = interface_cast(reply.readStrongBinder()); + if (cblk != 0 && cblk->pointer() == NULL) { + cblk.clear(); + } + buffers = interface_cast(reply.readStrongBinder()); + if (buffers != 0 && buffers->pointer() == NULL) { + buffers.clear(); + } if (lStatus == NO_ERROR) { if (record == 0) { ALOGE("openRecord should have returned an IAudioRecord"); lStatus = UNKNOWN_ERROR; + } else if (cblk == 0) { + ALOGE("openRecord should have returned a cblk"); + lStatus = NO_MEMORY; } + // buffers is permitted to be 0 } else { - if (record != 0) { - ALOGE("openRecord returned an IAudioRecord but with status %d", lStatus); - record.clear(); + if (record != 0 || cblk != 0 || buffers != 0) { + ALOGE("openRecord returned an IAudioRecord, cblk, " + "or buffers but with status %d", lStatus); } } + if (lStatus != NO_ERROR) { + record.clear(); + cblk.clear(); + buffers.clear(); + } } if (status != NULL) { *status = lStatus; @@ -838,15 +859,20 @@ status_t BnAudioFlinger::onTransact( track_flags_t flags = (track_flags_t) data.readInt32(); pid_t tid = (pid_t) data.readInt32(); int sessionId = data.readInt32(); + sp cblk; + sp buffers; status_t status; sp record = openRecord(input, - sampleRate, format, channelMask, &frameCount, &flags, tid, &sessionId, &status); + sampleRate, format, channelMask, &frameCount, &flags, tid, &sessionId, + cblk, buffers, &status); LOG_ALWAYS_FATAL_IF((record != 0) != (status == NO_ERROR)); reply->writeInt64(frameCount); reply->writeInt32(flags); reply->writeInt32(sessionId); reply->writeInt32(status); reply->writeStrongBinder(record->asBinder()); + reply->writeStrongBinder(cblk->asBinder()); + reply->writeStrongBinder(buffers->asBinder()); return NO_ERROR; } break; case SAMPLE_RATE: { diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index eb00c82..c1c95f8 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -1313,6 +1313,8 @@ sp AudioFlinger::openRecord( IAudioFlinger::track_flags_t *flags, pid_t tid, int *sessionId, + sp& cblk, + sp& buffers, status_t *status) { sp recordTrack; @@ -1321,6 +1323,9 @@ sp AudioFlinger::openRecord( status_t lStatus; int lSessionId; + cblk.clear(); + buffers.clear(); + // check calling permissions if (!recordingAllowed()) { ALOGE("openRecord() permission denied: recording not allowed"); @@ -1396,6 +1401,9 @@ sp AudioFlinger::openRecord( goto Exit; } + cblk = recordTrack->getCblk(); + buffers = recordTrack->getBuffers(); + // return handle to client recordHandle = new RecordHandle(recordTrack); diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h index ec32edd..462f9e2 100644 --- a/services/audioflinger/AudioFlinger.h +++ b/services/audioflinger/AudioFlinger.h @@ -120,6 +120,8 @@ public: IAudioFlinger::track_flags_t *flags, pid_t tid, int *sessionId, + sp& cblk, + sp& buffers, status_t *status /*non-NULL*/); virtual uint32_t sampleRate(audio_io_handle_t output) const; diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h index 6fc06d8..4ca2ad4 100644 --- a/services/audioflinger/RecordTracks.h +++ b/services/audioflinger/RecordTracks.h @@ -29,7 +29,8 @@ public: audio_channel_mask_t channelMask, size_t frameCount, int sessionId, - int uid); + int uid, + bool isFast); virtual ~RecordTrack(); virtual status_t start(AudioSystem::sync_event_t event, int triggerSession); diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index 2c5a0eb..be7d725 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -5163,7 +5163,8 @@ sp AudioFlinger::RecordThread::createRe Mutex::Autolock _l(mLock); track = new RecordTrack(this, client, sampleRate, - format, channelMask, frameCount, sessionId, uid); + format, channelMask, frameCount, sessionId, uid, + (*flags & IAudioFlinger::TRACK_FAST) != 0); lStatus = track->initCheck(); if (lStatus != NO_ERROR) { diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h index 58705c4..06023fd 100644 --- a/services/audioflinger/TrackBase.h +++ b/services/audioflinger/TrackBase.h @@ -48,7 +48,8 @@ public: const sp& sharedBuffer, int sessionId, int uid, - bool isOut); + bool isOut, + bool useReadOnlyHeap = false); virtual ~TrackBase(); virtual status_t initCheck() const { return getCblk() != 0 ? NO_ERROR : NO_MEMORY; } @@ -61,6 +62,8 @@ public: int uid() const { return mUid; } virtual status_t setSyncEvent(const sp& event); + sp getBuffers() const { return mBufferMemory; } + protected: TrackBase(const TrackBase&); TrackBase& operator = (const TrackBase&); @@ -112,6 +115,7 @@ protected: /*const*/ sp mClient; // see explanation at ~TrackBase() why not const sp mCblkMemory; audio_track_cblk_t* mCblk; + sp mBufferMemory; // currently non-0 for fast RecordTrack only void* mBuffer; // start of track buffer, typically in shared memory // except for OutputTrack when it is in local memory // we don't really need a lock for these diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp index 1064fd1..5889567 100644 --- a/services/audioflinger/Tracks.cpp +++ b/services/audioflinger/Tracks.cpp @@ -69,7 +69,8 @@ AudioFlinger::ThreadBase::TrackBase::TrackBase( const sp& sharedBuffer, int sessionId, int clientUid, - bool isOut) + bool isOut, + bool useReadOnlyHeap) : RefBase(), mThread(thread), mClient(client), @@ -110,7 +111,7 @@ AudioFlinger::ThreadBase::TrackBase::TrackBase( // ALOGD("Creating track with %d buffers @ %d bytes", bufferCount, bufferSize); size_t size = sizeof(audio_track_cblk_t); size_t bufferSize = (sharedBuffer == 0 ? roundup(frameCount) : frameCount) * mFrameSize; - if (sharedBuffer == 0) { + if (sharedBuffer == 0 && !useReadOnlyHeap) { size += bufferSize; } @@ -132,15 +133,31 @@ AudioFlinger::ThreadBase::TrackBase::TrackBase( // construct the shared structure in-place. if (mCblk != NULL) { new(mCblk) audio_track_cblk_t(); - // clear all buffers - if (sharedBuffer == 0) { - mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t); + if (useReadOnlyHeap) { + const sp roHeap(thread->readOnlyHeap()); + if (roHeap == 0 || + (mBufferMemory = roHeap->allocate(bufferSize)) == 0 || + (mBuffer = mBufferMemory->pointer()) == NULL) { + ALOGE("not enough memory for read-only buffer size=%zu", bufferSize); + if (roHeap != 0) { + roHeap->dump("buffer"); + } + mCblkMemory.clear(); + mBufferMemory.clear(); + return; + } memset(mBuffer, 0, bufferSize); } else { - mBuffer = sharedBuffer->pointer(); + // clear all buffers + if (sharedBuffer == 0) { + mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t); + memset(mBuffer, 0, bufferSize); + } else { + mBuffer = sharedBuffer->pointer(); #if 0 - mCblk->mFlags = CBLK_FORCEREADY; // FIXME hack, need to fix the track ready logic + mCblk->mFlags = CBLK_FORCEREADY; // FIXME hack, need to fix the track ready logic #endif + } } #ifdef TEE_SINK @@ -1819,9 +1836,11 @@ AudioFlinger::RecordThread::RecordTrack::RecordTrack( audio_channel_mask_t channelMask, size_t frameCount, int sessionId, - int uid) + int uid, + bool isFast) : TrackBase(thread, client, sampleRate, format, - channelMask, frameCount, 0 /*sharedBuffer*/, sessionId, uid, false /*isOut*/), + channelMask, frameCount, 0 /*sharedBuffer*/, sessionId, uid, false /*isOut*/, + isFast /*useReadOnlyHeap*/), mOverflow(false), mResampler(NULL), mRsmpOutBuffer(NULL), mRsmpOutFrameCount(0), // See real initialization of mRsmpInFront at RecordThread::start() mRsmpInUnrel(0), mRsmpInFront(0), mFramesToDrop(0), mResamplerBufferProvider(NULL) -- cgit v1.1