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
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)