Merge "IAudioFlinger::openRecord returns IMemory(s)"
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 @@
     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 @@
                                 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 @@
     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 @@
                                                        &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 @@
     // 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 @@
         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 @@
     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 @@
     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 @@
         // 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 @@
             // Keep the extra references
             proxy = mProxy;
             iMem = mCblkMemory;
+            bufferMem = mBufferMemory;
 
             // Non-blocking if track is stopped
             if (!mActive) {
@@ -986,7 +1002,7 @@
     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 @@
                                 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 @@
             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 @@
             }
             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 @@
             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 @@
         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 @@
     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 @@
         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 @@
                                 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 @@
                                 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 @@
         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 @@
                                 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 @@
             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 @@
     /*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 @@
             const sp<IMemory>& sharedBuffer,
             int sessionId,
             int clientUid,
-            bool isOut)
+            bool isOut,
+            bool useReadOnlyHeap)
     :   RefBase(),
         mThread(thread),
         mClient(client),
@@ -110,7 +111,7 @@
     // 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 @@
     // 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 @@
             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)