Start isolating control block accesses in a proxy

The proxy object will eventually be the only code that understands the
details of the control block.  This should make it easier to change the
control block in the future.

Initial set of control block fields that are isolated:
 - sample rate
 - send level
 - volume

Prepare for streaming/static separation by adding a union to the control
block for the new fields.

Fix bug in handling of max sample rate on a track.  It was only checking
at re-configuration, not at each mix.

Simplify OutputTrack::obtainBuffer.

Change-Id: I2249f9d04f73a911a922ad1d7f6197292c74cd92
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 1d87ff8..86a5579 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -97,7 +97,8 @@
     : mStatus(NO_INIT),
       mIsTimed(false),
       mPreviousPriority(ANDROID_PRIORITY_NORMAL),
-      mPreviousSchedulingGroup(SP_DEFAULT)
+      mPreviousSchedulingGroup(SP_DEFAULT),
+      mProxy(NULL)
 {
 }
 
@@ -115,7 +116,8 @@
     : mStatus(NO_INIT),
       mIsTimed(false),
       mPreviousPriority(ANDROID_PRIORITY_NORMAL),
-      mPreviousSchedulingGroup(SP_DEFAULT)
+      mPreviousSchedulingGroup(SP_DEFAULT),
+      mProxy(NULL)
 {
     mStatus = set(streamType, sampleRate, format, channelMask,
             frameCount, flags, cbf, user, notificationFrames,
@@ -136,7 +138,8 @@
     : mStatus(NO_INIT),
       mIsTimed(false),
       mPreviousPriority(ANDROID_PRIORITY_NORMAL),
-      mPreviousSchedulingGroup(SP_DEFAULT)
+      mPreviousSchedulingGroup(SP_DEFAULT),
+      mProxy(NULL)
 {
     if (sharedBuffer == 0) {
         ALOGE("sharedBuffer must be non-0");
@@ -166,6 +169,7 @@
         IPCThreadState::self()->flushCommands();
         AudioSystem::releaseAudioSessionId(mSessionId);
     }
+    delete mProxy;
 }
 
 status_t AudioTrack::set(
@@ -212,6 +216,7 @@
         }
         sampleRate = afSampleRate;
     }
+    mSampleRate = sampleRate;
 
     // these below should probably come from the audioFlinger too...
     if (format == AUDIO_FORMAT_DEFAULT) {
@@ -252,6 +257,14 @@
     uint32_t channelCount = popcount(channelMask);
     mChannelCount = channelCount;
 
+    if (audio_is_linear_pcm(format)) {
+        mFrameSize = channelCount * audio_bytes_per_sample(format);
+        mFrameSizeAF = channelCount * sizeof(int16_t);
+    } else {
+        mFrameSize = sizeof(uint8_t);
+        mFrameSizeAF = sizeof(uint8_t);
+    }
+
     audio_io_handle_t output = AudioSystem::getOutput(
                                     streamType,
                                     sampleRate, format, channelMask,
@@ -300,14 +313,6 @@
     mStreamType = streamType;
     mFormat = format;
 
-    if (audio_is_linear_pcm(format)) {
-        mFrameSize = channelCount * audio_bytes_per_sample(format);
-        mFrameSizeAF = channelCount * sizeof(int16_t);
-    } else {
-        mFrameSize = sizeof(uint8_t);
-        mFrameSizeAF = sizeof(uint8_t);
-    }
-
     mSharedBuffer = sharedBuffer;
     mActive = false;
     mUserData = user;
@@ -460,6 +465,11 @@
 
 status_t AudioTrack::setVolume(float left, float right)
 {
+    if (mStatus != NO_ERROR) {
+        return mStatus;
+    }
+    ALOG_ASSERT(mProxy != NULL);
+
     if (left < 0.0f || left > 1.0f || right < 0.0f || right > 1.0f) {
         return BAD_VALUE;
     }
@@ -468,7 +478,7 @@
     mVolume[LEFT] = left;
     mVolume[RIGHT] = right;
 
-    mCblk->setVolumeLR((uint32_t(uint16_t(right * 0x1000)) << 16) | uint16_t(left * 0x1000));
+    mProxy->setVolumeLR((uint32_t(uint16_t(right * 0x1000)) << 16) | uint16_t(left * 0x1000));
 
     return NO_ERROR;
 }
@@ -481,14 +491,19 @@
 status_t AudioTrack::setAuxEffectSendLevel(float level)
 {
     ALOGV("setAuxEffectSendLevel(%f)", level);
+
+    if (mStatus != NO_ERROR) {
+        return mStatus;
+    }
+    ALOG_ASSERT(mProxy != NULL);
+
     if (level < 0.0f || level > 1.0f) {
         return BAD_VALUE;
     }
     AutoMutex lock(mLock);
 
     mSendLevel = level;
-
-    mCblk->setSendLevel(level);
+    mProxy->setSendLevel(level);
 
     return NO_ERROR;
 }
@@ -517,7 +532,9 @@
     }
 
     AutoMutex lock(mLock);
-    mCblk->sampleRate = rate;
+    mSampleRate = rate;
+    mProxy->setSampleRate(rate);
+
     return NO_ERROR;
 }
 
@@ -528,7 +545,7 @@
     }
 
     AutoMutex lock(mLock);
-    return mCblk->sampleRate;
+    return mSampleRate;
 }
 
 status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount)
@@ -665,6 +682,11 @@
 
 status_t AudioTrack::reload()
 {
+    if (mStatus != NO_ERROR) {
+        return mStatus;
+    }
+    ALOG_ASSERT(mProxy != NULL);
+
     if (mSharedBuffer == 0 || mIsTimed) {
         return INVALID_OPERATION;
     }
@@ -677,8 +699,7 @@
 
     flush_l();
 
-    audio_track_cblk_t* cblk = mCblk;
-    cblk->stepUserOut(mFrameCount, mFrameCount);
+    (void) mProxy->stepUser(mFrameCount);
 
     return NO_ERROR;
 }
@@ -693,7 +714,7 @@
 audio_io_handle_t AudioTrack::getOutput_l()
 {
     return AudioSystem::getOutput(mStreamType,
-            mCblk->sampleRate, mFormat, mChannelMask, mFlags);
+            mSampleRate, mFormat, mChannelMask, mFlags);
 }
 
 status_t AudioTrack::attachAuxEffect(int effectId)
@@ -890,13 +911,8 @@
         mBuffers = (char*)cblk + sizeof(audio_track_cblk_t);
     } else {
         mBuffers = sharedBuffer->pointer();
-        // Force buffer full condition as data is already present in shared memory
-        cblk->stepUserOut(frameCount, frameCount);
     }
 
-    cblk->setVolumeLR((uint32_t(uint16_t(mVolume[RIGHT] * 0x1000)) << 16) |
-            uint16_t(mVolume[LEFT] * 0x1000));
-    cblk->setSendLevel(mSendLevel);
     mAudioTrack->attachAuxEffect(mAuxEffectId);
     cblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS;
     cblk->waitTimeMs = 0;
@@ -909,11 +925,26 @@
     if (frameCount > mReqFrameCount) {
         mReqFrameCount = frameCount;
     }
+
+    // update proxy
+    delete mProxy;
+    mProxy = new AudioTrackClientProxy(cblk, mBuffers, frameCount, mFrameSizeAF);
+    mProxy->setVolumeLR((uint32_t(uint16_t(mVolume[RIGHT] * 0x1000)) << 16) |
+            uint16_t(mVolume[LEFT] * 0x1000));
+    mProxy->setSendLevel(mSendLevel);
+    mProxy->setSampleRate(mSampleRate);
+    if (sharedBuffer != 0) {
+        // Force buffer full condition as data is already present in shared memory
+        mProxy->stepUser(frameCount);
+    }
+
     return NO_ERROR;
 }
 
 status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
 {
+    ALOG_ASSERT(mStatus == NO_ERROR && mProxy != NULL);
+
     AutoMutex lock(mLock);
     bool active;
     status_t result = NO_ERROR;
@@ -924,7 +955,7 @@
     audioBuffer->frameCount  = 0;
     audioBuffer->size = 0;
 
-    uint32_t framesAvail = cblk->framesAvailableOut(mFrameCount);
+    size_t framesAvail = mProxy->framesAvailable();
 
     cblk->lock.lock();
     if (cblk->flags & CBLK_INVALID) {
@@ -1000,7 +1031,7 @@
             }
             // read the server count again
         start_loop_here:
-            framesAvail = cblk->framesAvailableOut_l(mFrameCount);
+            framesAvail = mProxy->framesAvailable_l();
         }
         cblk->lock.unlock();
     }
@@ -1020,16 +1051,18 @@
 
     audioBuffer->frameCount = framesReq;
     audioBuffer->size = framesReq * mFrameSizeAF;
-    audioBuffer->raw = cblk->buffer(mBuffers, mFrameSizeAF, u);
+    audioBuffer->raw = mProxy->buffer(u);
     active = mActive;
     return active ? status_t(NO_ERROR) : status_t(STOPPED);
 }
 
 void AudioTrack::releaseBuffer(Buffer* audioBuffer)
 {
+    ALOG_ASSERT(mStatus == NO_ERROR && mProxy != NULL);
+
     AutoMutex lock(mLock);
     audio_track_cblk_t* cblk = mCblk;
-    cblk->stepUserOut(audioBuffer->frameCount, mFrameCount);
+    (void) mProxy->stepUser(audioBuffer->frameCount);
     if (audioBuffer->frameCount > 0) {
         // restart track if it was disabled by audioflinger due to previous underrun
         if (mActive && (cblk->flags & CBLK_DISABLED)) {
@@ -1199,7 +1232,7 @@
     // so all cblk references might still refer to old shared memory, but that should be benign
 
     // Manage underrun callback
-    if (active && (cblk->framesAvailableOut(mFrameCount) == mFrameCount)) {
+    if (active && (mProxy->framesAvailable() == mFrameCount)) {
         ALOGV("Underrun user: %x, server: %x, flags %04x", cblk->user, cblk->server, cblk->flags);
         if (!(android_atomic_or(CBLK_UNDERRUN, &cblk->flags) & CBLK_UNDERRUN)) {
             mCbf(EVENT_UNDERRUN, mUserData, 0);
@@ -1346,7 +1379,7 @@
     // following member variables: mAudioTrack, mCblkMemory and mCblk.
     // It will also delete the strong references on previous IAudioTrack and IMemory
     result = createTrack_l(mStreamType,
-                           cblk->sampleRate,
+                           mSampleRate,
                            mFormat,
                            mReqFrameCount,  // so that frame count never goes down
                            mFlags,
@@ -1365,12 +1398,12 @@
         // restore loop: this is not guaranteed to succeed if new frame count is not
         // compatible with loop length
         setLoop_l(cblk->loopStart, cblk->loopEnd, cblk->loopCount);
+        size_t frames = 0;
         if (!fromStart) {
             newCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
             // Make sure that a client relying on callback events indicating underrun or
             // the actual amount of audio frames played (e.g SoundPool) receives them.
             if (mSharedBuffer == 0) {
-                uint32_t frames = 0;
                 if (user > server) {
                     frames = ((user - server) > mFrameCount) ?
                             mFrameCount : (user - server);
@@ -1378,13 +1411,15 @@
                 }
                 // restart playback even if buffer is not completely filled.
                 android_atomic_or(CBLK_FORCEREADY, &newCblk->flags);
-                // stepUser() clears CBLK_UNDERRUN flag enabling underrun callbacks to
-                // the client
-                newCblk->stepUserOut(frames, mFrameCount);
             }
         }
         if (mSharedBuffer != 0) {
-            newCblk->stepUserOut(mFrameCount, mFrameCount);
+            frames = mFrameCount;
+        }
+        if (frames > 0) {
+            // stepUser() clears CBLK_UNDERRUN flag enabling underrun callbacks to
+            // the client
+            mProxy->stepUser(frames);
         }
         if (mActive) {
             result = mAudioTrack->start();
@@ -1416,7 +1451,6 @@
     char buffer[SIZE];
     String8 result;
 
-    audio_track_cblk_t* cblk = mCblk;
     result.append(" AudioTrack::dump\n");
     snprintf(buffer, 255, "  stream type(%d), left - right volume(%f, %f)\n", mStreamType,
             mVolume[0], mVolume[1]);
@@ -1424,8 +1458,7 @@
     snprintf(buffer, 255, "  format(%d), channel count(%d), frame count(%d)\n", mFormat,
             mChannelCount, mFrameCount);
     result.append(buffer);
-    snprintf(buffer, 255, "  sample rate(%u), status(%d)\n",
-            (cblk == 0) ? 0 : cblk->sampleRate, mStatus);
+    snprintf(buffer, 255, "  sample rate(%u), status(%d)\n", mSampleRate, mStatus);
     result.append(buffer);
     snprintf(buffer, 255, "  active(%d), latency (%d)\n", mActive, mLatency);
     result.append(buffer);