summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/media/AudioRecord.h4
-rw-r--r--include/media/IAudioFlinger.h2
-rw-r--r--media/libmedia/AudioRecord.cpp32
-rw-r--r--media/libmedia/IAudioFlinger.cpp34
-rw-r--r--services/audioflinger/AudioFlinger.cpp8
-rw-r--r--services/audioflinger/AudioFlinger.h2
-rw-r--r--services/audioflinger/RecordTracks.h3
-rw-r--r--services/audioflinger/Threads.cpp3
-rw-r--r--services/audioflinger/TrackBase.h6
-rw-r--r--services/audioflinger/Tracks.cpp37
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)