diff options
-rw-r--r-- | include/media/AudioRecord.h | 4 | ||||
-rw-r--r-- | include/media/IAudioFlinger.h | 2 | ||||
-rw-r--r-- | media/libmedia/AudioRecord.cpp | 32 | ||||
-rw-r--r-- | media/libmedia/IAudioFlinger.cpp | 34 | ||||
-rw-r--r-- | services/audioflinger/AudioFlinger.cpp | 8 | ||||
-rw-r--r-- | services/audioflinger/AudioFlinger.h | 2 | ||||
-rw-r--r-- | services/audioflinger/RecordTracks.h | 3 | ||||
-rw-r--r-- | services/audioflinger/Threads.cpp | 3 | ||||
-rw-r--r-- | services/audioflinger/TrackBase.h | 6 | ||||
-rw-r--r-- | 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<IAudioRecord> mAudioRecord; sp<IMemory> mCblkMemory; audio_track_cblk_t* mCblk; // re-load after mLock.unlock() + sp<IMemory> 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<IMemory>& cblk, + sp<IMemory>& 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<IMemory> iMem; // for cblk + sp<IMemory> bufferMem; sp<IAudioRecord> 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<IMemory> 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<audio_track_cblk_t*>(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<audio_track_cblk_t*>(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<AudioRecordClientProxy> proxy; sp<IMemory> iMem; + sp<IMemory> 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<IMemory>& cblk, + sp<IMemory>& 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<IAudioRecord>(reply.readStrongBinder()); + cblk = interface_cast<IMemory>(reply.readStrongBinder()); + if (cblk != 0 && cblk->pointer() == NULL) { + cblk.clear(); + } + buffers = interface_cast<IMemory>(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<IMemory> cblk; + sp<IMemory> buffers; status_t status; sp<IAudioRecord> 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<IAudioRecord> AudioFlinger::openRecord( IAudioFlinger::track_flags_t *flags, pid_t tid, int *sessionId, + sp<IMemory>& cblk, + sp<IMemory>& buffers, status_t *status) { sp<RecordThread::RecordTrack> recordTrack; @@ -1321,6 +1323,9 @@ sp<IAudioRecord> 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<IAudioRecord> 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<IMemory>& cblk, + sp<IMemory>& 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::RecordTrack> 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<IMemory>& 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<SyncEvent>& event); + sp<IMemory> getBuffers() const { return mBufferMemory; } + protected: TrackBase(const TrackBase&); TrackBase& operator = (const TrackBase&); @@ -112,6 +115,7 @@ protected: /*const*/ sp<Client> mClient; // see explanation at ~TrackBase() why not const sp<IMemory> mCblkMemory; audio_track_cblk_t* mCblk; + sp<IMemory> 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<IMemory>& 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<MemoryDealer> 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) |