OSDN Git Service

Start isolating control block accesses in a proxy
authorGlenn Kasten <gkasten@google.com>
Tue, 4 Dec 2012 20:22:46 +0000 (12:22 -0800)
committerGlenn Kasten <gkasten@google.com>
Wed, 12 Dec 2012 20:21:59 +0000 (12:21 -0800)
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

12 files changed:
include/media/AudioRecord.h
include/media/AudioTrack.h
include/private/media/AudioTrackShared.h
media/libmedia/AudioRecord.cpp
media/libmedia/AudioTrack.cpp
media/libmedia/AudioTrackShared.cpp
services/audioflinger/AudioFlinger.h
services/audioflinger/PlaybackTracks.h
services/audioflinger/RecordTracks.h
services/audioflinger/Threads.cpp
services/audioflinger/TrackBase.h
services/audioflinger/Tracks.cpp

index ae444c3..38c6548 100644 (file)
@@ -29,6 +29,7 @@
 namespace android {
 
 class audio_track_cblk_t;
+class AudioRecordClientProxy;
 
 // ----------------------------------------------------------------------------
 
@@ -374,6 +375,7 @@ private:
     uint32_t                mUpdatePeriod;      // in ms
 
     // constant after constructor or set()
+    uint32_t                mSampleRate;
     size_t                  mFrameCount;
     audio_format_t          mFormat;
     uint8_t                 mChannelCount;
@@ -393,6 +395,7 @@ private:
 
     int                     mPreviousPriority;          // before start()
     SchedPolicy             mPreviousSchedulingGroup;
+    AudioRecordClientProxy* mProxy;
 };
 
 }; // namespace android
index 6f85527..9d07ed5 100644 (file)
@@ -36,6 +36,7 @@ namespace android {
 // ----------------------------------------------------------------------------
 
 class audio_track_cblk_t;
+class AudioTrackClientProxy;
 
 // ----------------------------------------------------------------------------
 
@@ -538,6 +539,7 @@ protected:
 
     float                   mVolume[2];
     float                   mSendLevel;
+    uint32_t                mSampleRate;
     size_t                  mFrameCount;            // corresponds to current IAudioTrack
     size_t                  mReqFrameCount;         // frame count to request the next time a new
                                                     // IAudioTrack is needed
@@ -596,6 +598,7 @@ protected:
     bool                    mIsTimed;
     int                     mPreviousPriority;          // before start()
     SchedPolicy             mPreviousSchedulingGroup;
+    AudioTrackClientProxy*  mProxy;
 };
 
 class TimedAudioTrack : public AudioTrack
index 48b6b21..41e20f8 100644 (file)
@@ -21,6 +21,7 @@
 #include <sys/types.h>
 
 #include <utils/threads.h>
+#include <utils/Log.h>
 
 namespace android {
 
@@ -38,9 +39,26 @@ namespace android {
 #define CBLK_INVALID    0x04 // track buffer invalidated by AudioFlinger, need to re-create
 #define CBLK_DISABLED   0x08 // track disabled by AudioFlinger due to underrun, need to re-start
 
+struct AudioTrackSharedStreaming {
+    // similar to NBAIO MonoPipe
+    volatile int32_t mFront;
+    volatile int32_t mRear;
+};
+
+// future
+struct AudioTrackSharedStatic {
+    int mReserved;
+};
+
+// ----------------------------------------------------------------------------
+
 // Important: do not add any virtual methods, including ~
 struct audio_track_cblk_t
 {
+                friend class Proxy;
+                friend class AudioTrackClientProxy;
+                friend class AudioRecordClientProxy;
+                friend class ServerProxy;
 
     // The data members are grouped so that members accessed frequently and in the same context
     // are in the same line of data cache.
@@ -72,12 +90,13 @@ struct audio_track_cblk_t
                 // For AudioTrack only, not used by AudioRecord.
 private:
                 uint32_t    mVolumeLR;
-public:
 
-                uint32_t    sampleRate;
+                uint32_t    mSampleRate;    // AudioTrack only: client's requested sample rate in Hz
+                                            // or 0 == default. Write-only client, read-only server.
 
                 uint8_t     mPad2;           // unused
 
+public:
                 // read-only for client, server writes once at initialization and is then read-only
                 uint8_t     mName;           // normal tracks: track name, fast tracks: track index
 
@@ -94,65 +113,184 @@ public:
 
                 // Cache line boundary (32 bytes)
 
+#if 0
+                union {
+                    AudioTrackSharedStreaming   mStreaming;
+                    AudioTrackSharedStatic      mStatic;
+                    int                         mAlign[8];
+                } u;
+
+                // Cache line boundary (32 bytes)
+#endif
+
                 // Since the control block is always located in shared memory, this constructor
                 // is only used for placement new().  It is never used for regular new() or stack.
                             audio_track_cblk_t();
 
-                // called by client only, where client includes regular
-                // AudioTrack and AudioFlinger::PlaybackThread::OutputTrack
-                uint32_t    stepUserIn(size_t stepCount, size_t frameCount) { return stepUser(stepCount, frameCount, false); }
-                uint32_t    stepUserOut(size_t stepCount, size_t frameCount) { return stepUser(stepCount, frameCount, true); }
-
-                bool        stepServer(size_t stepCount, size_t frameCount, bool isOut);
-
+private:
                 // if there is a shared buffer, "buffers" is the value of pointer() for the shared
                 // buffer, otherwise "buffers" points immediately after the control block
-                void*       buffer(void *buffers, uint32_t frameSize, uint32_t offset) const;
-
-                uint32_t    framesAvailableIn(size_t frameCount)
-                                { return framesAvailable(frameCount, false); }
-                uint32_t    framesAvailableOut(size_t frameCount)
-                                { return framesAvailable(frameCount, true); }
-                uint32_t    framesAvailableIn_l(size_t frameCount)
-                                { return framesAvailable_l(frameCount, false); }
-                uint32_t    framesAvailableOut_l(size_t frameCount)
-                                { return framesAvailable_l(frameCount, true); }
-                uint32_t    framesReadyIn() { return framesReady(false); }
-                uint32_t    framesReadyOut() { return framesReady(true); }
+                void*       buffer(void *buffers, uint32_t frameSize, size_t offset) const;
 
                 bool        tryLock();
 
-                // No barriers on the following operations, so the ordering of loads/stores
-                // with respect to other parameters is UNPREDICTABLE. That's considered safe.
-
-                // for AudioTrack client only, caller must limit to 0.0 <= sendLevel <= 1.0
-                void        setSendLevel(float sendLevel) {
-                    mSendLevel = uint16_t(sendLevel * 0x1000);
-                }
-
-                // for AudioFlinger only; the return value must be validated by the caller
-                uint16_t    getSendLevel_U4_12() const {
-                    return mSendLevel;
-                }
-
-                // for AudioTrack client only, caller must limit to 0 <= volumeLR <= 0x10001000
-                void        setVolumeLR(uint32_t volumeLR) {
-                    mVolumeLR = volumeLR;
-                }
-
-                // for AudioFlinger only; the return value must be validated by the caller
-                uint32_t    getVolumeLR() const {
-                    return mVolumeLR;
-                }
-
-private:
                 // isOut == true means AudioTrack, isOut == false means AudioRecord
+                bool        stepServer(size_t stepCount, size_t frameCount, bool isOut);
                 uint32_t    stepUser(size_t stepCount, size_t frameCount, bool isOut);
                 uint32_t    framesAvailable(size_t frameCount, bool isOut);
                 uint32_t    framesAvailable_l(size_t frameCount, bool isOut);
                 uint32_t    framesReady(bool isOut);
 };
 
+// ----------------------------------------------------------------------------
+
+// Proxy for shared memory control block, to isolate callers from needing to know the details.
+// There is exactly one ClientProxy and one ServerProxy per shared memory control block.
+// The proxies are located in normal memory, and are not multi-thread safe within a given side.
+class Proxy {
+protected:
+    Proxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, size_t frameSize)
+        : mCblk(cblk), mBuffers(buffers), mFrameCount(frameCount), mFrameSize(frameSize) { }
+    virtual ~Proxy() { }
+
+public:
+    void*   buffer(size_t offset) const {
+        return mCblk->buffer(mBuffers, mFrameSize, offset);
+    }
+
+protected:
+    // These refer to shared memory, and are virtual addresses with respect to the current process.
+    // They may have different virtual addresses within the other process.
+    audio_track_cblk_t* const   mCblk;          // the control block
+    void* const                 mBuffers;       // starting address of buffers
+
+    const size_t                mFrameCount;    // not necessarily a power of 2
+    const size_t                mFrameSize;     // in bytes
+#if 0
+    const size_t                mFrameCountP2;  // mFrameCount rounded to power of 2, streaming mode
+#endif
+
+};
+
+// ----------------------------------------------------------------------------
+
+// Proxy seen by AudioTrack client and AudioRecord client
+class ClientProxy : public Proxy {
+protected:
+    ClientProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, size_t frameSize)
+        : Proxy(cblk, buffers, frameCount, frameSize) { }
+    virtual ~ClientProxy() { }
+};
+
+// ----------------------------------------------------------------------------
+
+// Proxy used by AudioTrack client, which also includes AudioFlinger::PlaybackThread::OutputTrack
+class AudioTrackClientProxy : public ClientProxy {
+public:
+    AudioTrackClientProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, size_t frameSize)
+        : ClientProxy(cblk, buffers, frameCount, frameSize) { }
+    virtual ~AudioTrackClientProxy() { }
+
+    // No barriers on the following operations, so the ordering of loads/stores
+    // with respect to other parameters is UNPREDICTABLE. That's considered safe.
+
+    // caller must limit to 0.0 <= sendLevel <= 1.0
+    void        setSendLevel(float sendLevel) {
+        mCblk->mSendLevel = uint16_t(sendLevel * 0x1000);
+    }
+
+    // caller must limit to 0 <= volumeLR <= 0x10001000
+    void        setVolumeLR(uint32_t volumeLR) {
+        mCblk->mVolumeLR = volumeLR;
+    }
+
+    void        setSampleRate(uint32_t sampleRate) {
+        mCblk->mSampleRate = sampleRate;
+    }
+
+    // called by:
+    //   PlaybackThread::OutputTrack::write
+    //   AudioTrack::createTrack_l
+    //   AudioTrack::releaseBuffer
+    //   AudioTrack::reload
+    //   AudioTrack::restoreTrack_l (2 places)
+    size_t      stepUser(size_t stepCount) {
+        return mCblk->stepUser(stepCount, mFrameCount, true /*isOut*/);
+    }
+
+    // called by AudioTrack::obtainBuffer and AudioTrack::processBuffer
+    size_t      framesAvailable() {
+        return mCblk->framesAvailable(mFrameCount, true /*isOut*/);
+    }
+
+    // called by AudioTrack::obtainBuffer and PlaybackThread::OutputTrack::obtainBuffer
+    // FIXME remove this API since it assumes a lock that should be invisible to caller
+    size_t      framesAvailable_l() {
+        return mCblk->framesAvailable_l(mFrameCount, true /*isOut*/);
+    }
+
+};
+
+// ----------------------------------------------------------------------------
+
+// Proxy used by AudioRecord client
+class AudioRecordClientProxy : public ClientProxy {
+public:
+    AudioRecordClientProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, size_t frameSize)
+        : ClientProxy(cblk, buffers, frameCount, frameSize) { }
+    ~AudioRecordClientProxy() { }
+
+    // called by AudioRecord::releaseBuffer
+    size_t      stepUser(size_t stepCount) {
+        return mCblk->stepUser(stepCount, mFrameCount, false /*isOut*/);
+    }
+
+    // called by AudioRecord::processBuffer
+    size_t      framesAvailable() {
+        return mCblk->framesAvailable(mFrameCount, false /*isOut*/);
+    }
+
+    // called by AudioRecord::obtainBuffer
+    size_t      framesReady() {
+        return mCblk->framesReady(false /*isOut*/);
+    }
+
+};
+
+// ----------------------------------------------------------------------------
+
+// Proxy used by AudioFlinger server
+class ServerProxy : public Proxy {
+public:
+    ServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, size_t frameSize, bool isOut)
+        : Proxy(cblk, buffers, frameCount, frameSize), mIsOut(isOut) { }
+    virtual ~ServerProxy() { }
+
+    // for AudioTrack and AudioRecord
+    bool        step(size_t stepCount) { return mCblk->stepServer(stepCount, mFrameCount, mIsOut); }
+
+    // return value of these methods must be validated by the caller
+    uint32_t    getSampleRate() const { return mCblk->mSampleRate; }
+    uint16_t    getSendLevel_U4_12() const { return mCblk->mSendLevel; }
+    uint32_t    getVolumeLR() const { return mCblk->mVolumeLR; }
+
+    // for AudioTrack only
+    size_t      framesReady() {
+        ALOG_ASSERT(mIsOut);
+        return mCblk->framesReady(true);
+    }
+
+    // for AudioRecord only, called by RecordThread::RecordTrack::getNextBuffer
+    // FIXME remove this API since it assumes a lock that should be invisible to caller
+    size_t      framesAvailableIn_l() {
+        ALOG_ASSERT(!mIsOut);
+        return mCblk->framesAvailable_l(mFrameCount, false);
+    }
+
+private:
+    const bool  mIsOut;     // true for AudioTrack, false for AudioRecord
+
+};
 
 // ----------------------------------------------------------------------------
 
index c2ef68c..8eb1656 100644 (file)
@@ -75,7 +75,8 @@ status_t AudioRecord::getMinFrameCount(
 
 AudioRecord::AudioRecord()
     : mStatus(NO_INIT), mSessionId(0),
-      mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT)
+      mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT),
+      mProxy(NULL)
 {
 }
 
@@ -90,7 +91,9 @@ AudioRecord::AudioRecord(
         int notificationFrames,
         int sessionId)
     : mStatus(NO_INIT), mSessionId(0),
-      mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT)
+      mPreviousPriority(ANDROID_PRIORITY_NORMAL),
+      mPreviousSchedulingGroup(SP_DEFAULT),
+      mProxy(NULL)
 {
     mStatus = set(inputSource, sampleRate, format, channelMask,
             frameCount, cbf, user, notificationFrames, sessionId);
@@ -112,6 +115,7 @@ AudioRecord::~AudioRecord()
         IPCThreadState::self()->flushCommands();
         AudioSystem::releaseAudioSessionId(mSessionId);
     }
+    delete mProxy;
 }
 
 status_t AudioRecord::set(
@@ -149,6 +153,8 @@ status_t AudioRecord::set(
     if (sampleRate == 0) {
         sampleRate = DEFAULT_SAMPLE_RATE;
     }
+    mSampleRate = sampleRate;
+
     // these below should probably come from the audioFlinger too...
     if (format == AUDIO_FORMAT_DEFAULT) {
         format = AUDIO_FORMAT_PCM_16_BIT;
@@ -166,6 +172,12 @@ status_t AudioRecord::set(
     uint32_t channelCount = popcount(channelMask);
     mChannelCount = channelCount;
 
+    if (audio_is_linear_pcm(mFormat)) {
+        mFrameSize = channelCount * audio_bytes_per_sample(format);
+    } else {
+        mFrameSize = sizeof(uint8_t);
+    }
+
     if (sessionId == 0 ) {
         mSessionId = AudioSystem::newAudioSessionId();
     } else {
@@ -218,12 +230,6 @@ status_t AudioRecord::set(
     // Update buffer size in case it has been limited by AudioFlinger during track creation
     mFrameCount = mCblk->frameCount_;
 
-    if (audio_is_linear_pcm(mFormat)) {
-        mFrameSize = channelCount * audio_bytes_per_sample(format);
-    } else {
-        mFrameSize = sizeof(uint8_t);
-    }
-
     mActive = false;
     mCbf = cbf;
     mNotificationFrames = notificationFrames;
@@ -360,7 +366,7 @@ bool AudioRecord::stopped() const
 
 uint32_t AudioRecord::getSampleRate() const
 {
-    return mCblk->sampleRate;
+    return mSampleRate;
 }
 
 status_t AudioRecord::setMarkerPosition(uint32_t marker)
@@ -473,11 +479,18 @@ status_t AudioRecord::openRecord_l(
     mBuffers = (char*)cblk + sizeof(audio_track_cblk_t);
     cblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
     cblk->waitTimeMs = 0;
+
+    // update proxy
+    delete mProxy;
+    mProxy = new AudioRecordClientProxy(cblk, mBuffers, frameCount, mFrameSize);
+
     return NO_ERROR;
 }
 
 status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
 {
+    ALOG_ASSERT(mStatus == NO_ERROR && mProxy != NULL);
+
     AutoMutex lock(mLock);
     bool active;
     status_t result = NO_ERROR;
@@ -488,7 +501,7 @@ status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
     audioBuffer->frameCount  = 0;
     audioBuffer->size        = 0;
 
-    uint32_t framesReady = cblk->framesReadyIn();
+    size_t framesReady = mProxy->framesReady();
 
     if (framesReady == 0) {
         cblk->lock.lock();
@@ -551,7 +564,7 @@ create_new_record:
             }
             // read the server count again
         start_loop_here:
-            framesReady = cblk->framesReadyIn();
+            framesReady = mProxy->framesReady();
         }
         cblk->lock.unlock();
     }
@@ -573,15 +586,17 @@ create_new_record:
 
     audioBuffer->frameCount  = framesReq;
     audioBuffer->size        = framesReq * mFrameSize;
-    audioBuffer->raw         = cblk->buffer(mBuffers, mFrameSize, u);
+    audioBuffer->raw         = mProxy->buffer(u);
     active = mActive;
     return active ? status_t(NO_ERROR) : status_t(STOPPED);
 }
 
 void AudioRecord::releaseBuffer(Buffer* audioBuffer)
 {
+    ALOG_ASSERT(mStatus == NO_ERROR && mProxy != NULL);
+
     AutoMutex lock(mLock);
-    mCblk->stepUserIn(audioBuffer->frameCount, mFrameCount);
+    (void) mProxy->stepUser(audioBuffer->frameCount);
 }
 
 audio_io_handle_t AudioRecord::getInput() const
@@ -594,7 +609,7 @@ audio_io_handle_t AudioRecord::getInput() const
 audio_io_handle_t AudioRecord::getInput_l()
 {
     mInput = AudioSystem::getInput(mInputSource,
-                                mCblk->sampleRate,
+                                mSampleRate,
                                 mFormat,
                                 mChannelMask,
                                 mSessionId);
@@ -745,7 +760,7 @@ bool AudioRecord::processAudioBuffer(const sp<AudioRecordThread>& thread)
 
 
     // Manage overrun callback
-    if (active && (cblk->framesAvailableIn(mFrameCount) == 0)) {
+    if (active && (mProxy->framesAvailable() == 0)) {
         // The value of active is stale, but we are almost sure to be active here because
         // otherwise we would have exited when obtainBuffer returned STOPPED earlier.
         ALOGV("Overrun user: %x, server: %x, flags %04x", cblk->user, cblk->server, cblk->flags);
@@ -781,7 +796,7 @@ status_t AudioRecord::restoreRecord_l(audio_track_cblk_t*& refCblk)
     // if the new IAudioRecord is created, openRecord_l() will modify the
     // following member variables: mAudioRecord, mCblkMemory and mCblk.
     // It will also delete the strong references on previous IAudioRecord and IMemory
-    result = openRecord_l(cblk->sampleRate, mFormat, mFrameCount, getInput_l());
+    result = openRecord_l(mSampleRate, mFormat, mFrameCount, getInput_l());
     if (result == NO_ERROR) {
         newCblk = mCblk;
         // callback thread or sync event hasn't changed
index 1d87ff8..86a5579 100644 (file)
@@ -97,7 +97,8 @@ AudioTrack::AudioTrack()
     : mStatus(NO_INIT),
       mIsTimed(false),
       mPreviousPriority(ANDROID_PRIORITY_NORMAL),
-      mPreviousSchedulingGroup(SP_DEFAULT)
+      mPreviousSchedulingGroup(SP_DEFAULT),
+      mProxy(NULL)
 {
 }
 
@@ -115,7 +116,8 @@ AudioTrack::AudioTrack(
     : 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 @@ AudioTrack::AudioTrack(
     : 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 @@ AudioTrack::~AudioTrack()
         IPCThreadState::self()->flushCommands();
         AudioSystem::releaseAudioSessionId(mSessionId);
     }
+    delete mProxy;
 }
 
 status_t AudioTrack::set(
@@ -212,6 +216,7 @@ status_t AudioTrack::set(
         }
         sampleRate = afSampleRate;
     }
+    mSampleRate = sampleRate;
 
     // these below should probably come from the audioFlinger too...
     if (format == AUDIO_FORMAT_DEFAULT) {
@@ -252,6 +257,14 @@ status_t AudioTrack::set(
     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 @@ status_t AudioTrack::set(
     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 @@ void AudioTrack::pause()
 
 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 @@ status_t AudioTrack::setVolume(float left, float right)
     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::setVolume(float volume)
 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 @@ status_t AudioTrack::setSampleRate(uint32_t rate)
     }
 
     AutoMutex lock(mLock);
-    mCblk->sampleRate = rate;
+    mSampleRate = rate;
+    mProxy->setSampleRate(rate);
+
     return NO_ERROR;
 }
 
@@ -528,7 +545,7 @@ uint32_t AudioTrack::getSampleRate() const
     }
 
     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::getPosition(uint32_t *position)
 
 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 @@ status_t AudioTrack::reload()
 
     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()
 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 @@ status_t AudioTrack::createTrack_l(
         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 @@ status_t AudioTrack::createTrack_l(
     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 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
     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 @@ create_new_track:
             }
             // read the server count again
         start_loop_here:
-            framesAvail = cblk->framesAvailableOut_l(mFrameCount);
+            framesAvail = mProxy->framesAvailable_l();
         }
         cblk->lock.unlock();
     }
@@ -1020,16 +1051,18 @@ create_new_track:
 
     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 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread)
     // 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 @@ status_t AudioTrack::restoreTrack_l(audio_track_cblk_t*& refCblk, bool fromStart
     // 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 @@ status_t AudioTrack::restoreTrack_l(audio_track_cblk_t*& refCblk, bool fromStart
         // 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 @@ status_t AudioTrack::restoreTrack_l(audio_track_cblk_t*& refCblk, bool fromStart
                 }
                 // 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 @@ status_t AudioTrack::dump(int fd, const Vector<String16>& args) const
     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 @@ status_t AudioTrack::dump(int fd, const Vector<String16>& args) const
     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);
index bee13c8..13d47c9 100644 (file)
@@ -26,7 +26,7 @@ audio_track_cblk_t::audio_track_cblk_t()
     : lock(Mutex::SHARED), cv(Condition::SHARED), user(0), server(0),
     userBase(0), serverBase(0), frameCount_(0),
     loopStart(UINT_MAX), loopEnd(UINT_MAX), loopCount(0), mVolumeLR(0x10001000),
-    mSendLevel(0), flags(0)
+    mSampleRate(0), mSendLevel(0), flags(0)
 {
 }
 
index 6d3f0a1..64a9871 100644 (file)
@@ -61,6 +61,7 @@ class AudioMixer;
 class AudioBuffer;
 class AudioResampler;
 class FastMixer;
+class ServerProxy;
 
 // ----------------------------------------------------------------------------
 
index aaa5333..adec938 100644 (file)
@@ -107,7 +107,6 @@ public:
     bool isInvalid() const { return mIsInvalid; }
     virtual bool isTimedTrack() const { return false; }
     bool isFastTrack() const { return (mFlags & IAudioFlinger::TRACK_FAST) != 0; }
-    virtual bool isOut() const;
 
 protected:
 
@@ -277,5 +276,5 @@ private:
     AudioBufferProvider::Buffer mOutBuffer;
     bool                        mActive;
     DuplicatingThread* const mSourceThread; // for waitTimeMs() in write()
-    void*                       mBuffers;   // starting address of buffers in plain memory
+    AudioTrackClientProxy*      mClientProxy;
 };  // end of OutputTrack
index fe681d7..6c0d1d3 100644 (file)
@@ -45,8 +45,6 @@ public:
     static  void        appendDumpHeader(String8& result);
             void        dump(char* buffer, size_t size);
 
-    virtual bool isOut() const;
-
 private:
     friend class AudioFlinger;  // for mState
 
index d2b2931..82acd3a 100644 (file)
@@ -2643,7 +2643,8 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac
                 // read original volumes with volume control
                 float typeVolume = mStreamTypes[track->streamType()].volume;
                 float v = masterVolume * typeVolume;
-                uint32_t vlr = cblk->getVolumeLR();
+                ServerProxy *proxy = track->mServerProxy;
+                uint32_t vlr = proxy->getVolumeLR();
                 vl = vlr & 0xFFFF;
                 vr = vlr >> 16;
                 // track volumes come from shared memory, so can't be trusted and must be clamped
@@ -2661,7 +2662,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac
                 // assuming master volume and stream type volume each go up to 1.0,
                 // vl and vr are now in 8.24 format
 
-                uint16_t sendLevel = cblk->getSendLevel_U4_12();
+                uint16_t sendLevel = proxy->getSendLevel_U4_12();
                 // send level comes from shared memory and so may be corrupt
                 if (sendLevel > MAX_GAIN_INT) {
                     ALOGV("Track send level out of range: %04X", sendLevel);
@@ -2713,11 +2714,19 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac
                 name,
                 AudioMixer::TRACK,
                 AudioMixer::CHANNEL_MASK, (void *)track->channelMask());
+            // limit track sample rate to 2 x output sample rate, which changes at re-configuration
+            uint32_t maxSampleRate = mSampleRate * 2;
+            uint32_t reqSampleRate = track->mServerProxy->getSampleRate();
+            if (reqSampleRate == 0) {
+                reqSampleRate = mSampleRate;
+            } else if (reqSampleRate > maxSampleRate) {
+                reqSampleRate = maxSampleRate;
+            }
             mAudioMixer->setParameter(
                 name,
                 AudioMixer::RESAMPLE,
                 AudioMixer::SAMPLE_RATE,
-                (void *)(cblk->sampleRate));
+                (void *)reqSampleRate);
             mAudioMixer->setParameter(
                 name,
                 AudioMixer::TRACK,
@@ -2990,10 +2999,6 @@ bool AudioFlinger::MixerThread::checkForNewParameters_l()
                         break;
                     }
                     mTracks[i]->mName = name;
-                    // limit track sample rate to 2 x new output sample rate
-                    if (mTracks[i]->mCblk->sampleRate > 2 * sampleRate()) {
-                        mTracks[i]->mCblk->sampleRate = 2 * sampleRate();
-                    }
                 }
                 sendIoConfigEvent_l(AudioSystem::OUTPUT_CONFIG_CHANGED);
             }
@@ -3142,7 +3147,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep
             } else {
                 float typeVolume = mStreamTypes[track->streamType()].volume;
                 float v = mMasterVolume * typeVolume;
-                uint32_t vlr = cblk->getVolumeLR();
+                uint32_t vlr = track->mServerProxy->getVolumeLR();
                 float v_clamped = v * (vlr & 0xFFFF);
                 if (v_clamped > MAX_GAIN) {
                     v_clamped = MAX_GAIN;
index 17de49b..e0bd97a 100644 (file)
@@ -44,7 +44,8 @@ public:
                                 audio_channel_mask_t channelMask,
                                 size_t frameCount,
                                 const sp<IMemory>& sharedBuffer,
-                                int sessionId);
+                                int sessionId,
+                                bool isOut);
     virtual             ~TrackBase();
 
     virtual status_t    start(AudioSystem::sync_event_t event,
@@ -108,7 +109,8 @@ protected:
     bool step();    // mStepCount is an implicit input
     void reset();
 
-    virtual bool isOut() const = 0; // true for Track and TimedTrack, false for RecordTrack,
+    bool isOut() const { return mIsOut; }
+                                    // true for Track and TimedTrack, false for RecordTrack,
                                     // this could be a track type if needed later
 
     const wp<ThreadBase> mThread;
@@ -116,6 +118,7 @@ protected:
     sp<IMemory>         mCblkMemory;
     audio_track_cblk_t* mCblk;
     void*               mBuffer;    // start of track buffer, typically in shared memory
+                                    // except for OutputTrack when it is in local memory
     void*               mBufferEnd; // &mBuffer[mFrameCount * frameSize], where frameSize
                                     //   is based on mChannelCount and 16-bit samples
     uint32_t            mStepCount; // saves AudioBufferProvider::Buffer::frameCount as of
@@ -136,4 +139,6 @@ protected:
     bool                mStepServerFailed;
     const int           mSessionId;
     Vector < sp<SyncEvent> >mSyncEvents;
+    const bool          mIsOut;
+    ServerProxy*        mServerProxy;
 };
index 9b611d2..c5f0ed7 100644 (file)
@@ -62,7 +62,8 @@ AudioFlinger::ThreadBase::TrackBase::TrackBase(
             audio_channel_mask_t channelMask,
             size_t frameCount,
             const sp<IMemory>& sharedBuffer,
-            int sessionId)
+            int sessionId,
+            bool isOut)
     :   RefBase(),
         mThread(thread),
         mClient(client),
@@ -79,7 +80,9 @@ AudioFlinger::ThreadBase::TrackBase::TrackBase(
                 mChannelCount * audio_bytes_per_sample(format) : sizeof(int8_t)),
         mFrameCount(frameCount),
         mStepServerFailed(false),
-        mSessionId(sessionId)
+        mSessionId(sessionId),
+        mIsOut(isOut),
+        mServerProxy(NULL)
 {
     // client == 0 implies sharedBuffer == 0
     ALOG_ASSERT(!(client == 0 && sharedBuffer != 0));
@@ -105,7 +108,8 @@ AudioFlinger::ThreadBase::TrackBase::TrackBase(
             return;
         }
     } else {
-        mCblk = (audio_track_cblk_t *)(new uint8_t[size]);
+        // this syntax avoids calling the audio_track_cblk_t constructor twice
+        mCblk = (audio_track_cblk_t *) new uint8_t[size];
         // assume mCblk != NULL
     }
 
@@ -114,7 +118,6 @@ AudioFlinger::ThreadBase::TrackBase::TrackBase(
         new(mCblk) audio_track_cblk_t();
         // clear all buffers
         mCblk->frameCount_ = frameCount;
-        mCblk->sampleRate = sampleRate;
 // uncomment the following lines to quickly test 32-bit wraparound
 //      mCblk->user = 0xffff0000;
 //      mCblk->server = 0xffff0000;
@@ -130,11 +133,14 @@ AudioFlinger::ThreadBase::TrackBase::TrackBase(
             mBuffer = sharedBuffer->pointer();
         }
         mBufferEnd = (uint8_t *)mBuffer + bufferSize;
+        mServerProxy = new ServerProxy(mCblk, mBuffer, frameCount, mFrameSize, isOut);
     }
 }
 
 AudioFlinger::ThreadBase::TrackBase::~TrackBase()
 {
+    // delete the proxy before deleting the shared memory it refers to, to avoid dangling reference
+    delete mServerProxy;
     if (mCblk != NULL) {
         if (mClient == 0) {
             delete mCblk;
@@ -166,10 +172,7 @@ void AudioFlinger::ThreadBase::TrackBase::releaseBuffer(AudioBufferProvider::Buf
 }
 
 bool AudioFlinger::ThreadBase::TrackBase::step() {
-    bool result;
-    audio_track_cblk_t* cblk = this->cblk();
-
-    result = cblk->stepServer(mStepCount, mFrameCount, isOut());
+    bool result = mServerProxy->step(mStepCount);
     if (!result) {
         ALOGV("stepServer failed acquiring cblk mutex");
         mStepServerFailed = true;
@@ -189,7 +192,7 @@ void AudioFlinger::ThreadBase::TrackBase::reset() {
 }
 
 uint32_t AudioFlinger::ThreadBase::TrackBase::sampleRate() const {
-    return mCblk->sampleRate;
+    return mServerProxy->getSampleRate();
 }
 
 void* AudioFlinger::ThreadBase::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const {
@@ -310,7 +313,7 @@ AudioFlinger::PlaybackThread::Track::Track(
             int sessionId,
             IAudioFlinger::track_flags_t flags)
     :   TrackBase(thread, client, sampleRate, format, channelMask, frameCount, sharedBuffer,
-            sessionId),
+            sessionId, true /*isOut*/),
     mFillingUpStatus(FS_INVALID),
     // mRetryCount initialized later when needed
     mSharedBuffer(sharedBuffer),
@@ -399,7 +402,7 @@ void AudioFlinger::PlaybackThread::Track::destroy()
 
 void AudioFlinger::PlaybackThread::Track::dump(char* buffer, size_t size)
 {
-    uint32_t vlr = mCblk->getVolumeLR();
+    uint32_t vlr = mServerProxy->getVolumeLR();
     if (isFastTrack()) {
         sprintf(buffer, "   F %2d", mFastIndex);
     } else {
@@ -468,7 +471,7 @@ void AudioFlinger::PlaybackThread::Track::dump(char* buffer, size_t size)
             mFrameCount,
             stateChar,
             mFillingUpStatus,
-            mCblk->sampleRate,
+            mServerProxy->getSampleRate(),
             20.0 * log10((vlr & 0xFFFF) / 4096.0),
             20.0 * log10((vlr >> 16) / 4096.0),
             mCblk->server,
@@ -503,7 +506,7 @@ status_t AudioFlinger::PlaybackThread::Track::getNextBuffer(
     }
 
     // FIXME Same as above
-    framesReady = cblk->framesReadyOut();
+    framesReady = mServerProxy->framesReady();
 
     if (CC_LIKELY(framesReady)) {
         uint32_t s = cblk->server;
@@ -538,7 +541,7 @@ getNextBuffer_exit:
 // the tryLock() could block for up to 1 ms, and a sequence of these could delay fast mixer.
 // FIXME Replace AudioTrackShared control block implementation by a non-blocking FIFO queue.
 size_t AudioFlinger::PlaybackThread::Track::framesReady() const {
-    return mCblk->framesReadyOut();
+    return mServerProxy->framesReady();
 }
 
 // Don't call for fast tracks; the framesReady() could result in priority inversion
@@ -795,7 +798,7 @@ uint32_t AudioFlinger::PlaybackThread::Track::getVolumeLR()
 {
     // called by FastMixer, so not allowed to take any locks, block, or do I/O including logs
     ALOG_ASSERT(isFastTrack() && (mCblk != NULL));
-    uint32_t vlr = mCblk->getVolumeLR();
+    uint32_t vlr = mServerProxy->getVolumeLR();
     uint32_t vl = vlr & 0xFFFF;
     uint32_t vr = vlr >> 16;
     // track volumes come from shared memory, so can't be trusted and must be clamped
@@ -830,11 +833,6 @@ status_t AudioFlinger::PlaybackThread::Track::setSyncEvent(const sp<SyncEvent>&
     return NO_ERROR;
 }
 
-bool AudioFlinger::PlaybackThread::Track::isOut() const
-{
-    return true;
-}
-
 void AudioFlinger::PlaybackThread::Track::invalidate()
 {
     // FIXME should use proxy
@@ -1369,17 +1367,19 @@ AudioFlinger::PlaybackThread::OutputTrack::OutputTrack(
             size_t frameCount)
     :   Track(playbackThread, NULL, AUDIO_STREAM_CNT, sampleRate, format, channelMask, frameCount,
                 NULL, 0, IAudioFlinger::TRACK_DEFAULT),
-    mActive(false), mSourceThread(sourceThread), mBuffers(NULL)
+    mActive(false), mSourceThread(sourceThread), mClientProxy(NULL)
 {
 
     if (mCblk != NULL) {
-        mBuffers = (char*)mCblk + sizeof(audio_track_cblk_t);
         mOutBuffer.frameCount = 0;
         playbackThread->mTracks.add(this);
-        ALOGV("OutputTrack constructor mCblk %p, mBuffer %p, mBuffers %p, " \
-                "mCblk->frameCount %d, mCblk->sampleRate %u, mChannelMask 0x%08x mBufferEnd %p",
-                mCblk, mBuffer, mBuffers,
-                mCblk->frameCount, mCblk->sampleRate, mChannelMask, mBufferEnd);
+        ALOGV("OutputTrack constructor mCblk %p, mBuffer %p, "
+                "mCblk->frameCount_ %u, mChannelMask 0x%08x mBufferEnd %p",
+                mCblk, mBuffer,
+                mCblk->frameCount_, mChannelMask, mBufferEnd);
+        // since client and server are in the same process,
+        // the buffer has the same virtual address on both sides
+        mClientProxy = new AudioTrackClientProxy(mCblk, mBuffer, mFrameCount, mFrameSize);
     } else {
         ALOGW("Error creating output track on thread %p", playbackThread);
     }
@@ -1388,6 +1388,8 @@ AudioFlinger::PlaybackThread::OutputTrack::OutputTrack(
 AudioFlinger::PlaybackThread::OutputTrack::~OutputTrack()
 {
     clearBufferQueue();
+    delete mClientProxy;
+    // superclass destructor will now delete the server proxy and shared memory both refer to
 }
 
 status_t AudioFlinger::PlaybackThread::OutputTrack::start(AudioSystem::sync_event_t event,
@@ -1475,7 +1477,7 @@ bool AudioFlinger::PlaybackThread::OutputTrack::write(int16_t* data, uint32_t fr
         uint32_t outFrames = pInBuffer->frameCount > mOutBuffer.frameCount ? mOutBuffer.frameCount :
                 pInBuffer->frameCount;
         memcpy(mOutBuffer.raw, pInBuffer->raw, outFrames * channelCount * sizeof(int16_t));
-        mCblk->stepUserOut(outFrames, mFrameCount);
+        mClientProxy->stepUser(outFrames);
         pInBuffer->frameCount -= outFrames;
         pInBuffer->i16 += outFrames * channelCount;
         mOutBuffer.frameCount -= outFrames;
@@ -1538,40 +1540,29 @@ bool AudioFlinger::PlaybackThread::OutputTrack::write(int16_t* data, uint32_t fr
 status_t AudioFlinger::PlaybackThread::OutputTrack::obtainBuffer(
         AudioBufferProvider::Buffer* buffer, uint32_t waitTimeMs)
 {
-    int active;
-    status_t result;
     audio_track_cblk_t* cblk = mCblk;
     uint32_t framesReq = buffer->frameCount;
 
     ALOGVV("OutputTrack::obtainBuffer user %d, server %d", cblk->user, cblk->server);
     buffer->frameCount  = 0;
 
-    uint32_t framesAvail = cblk->framesAvailableOut(mFrameCount);
-
-
-    if (framesAvail == 0) {
+    size_t framesAvail;
+    {
         Mutex::Autolock _l(cblk->lock);
-        goto start_loop_here;
-        while (framesAvail == 0) {
-            active = mActive;
-            if (CC_UNLIKELY(!active)) {
+
+        // read the server count again
+        while (!(framesAvail = mClientProxy->framesAvailable_l())) {
+            if (CC_UNLIKELY(!mActive)) {
                 ALOGV("Not active and NO_MORE_BUFFERS");
                 return NO_MORE_BUFFERS;
             }
-            result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs));
+            status_t result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs));
             if (result != NO_ERROR) {
                 return NO_MORE_BUFFERS;
             }
-            // read the server count again
-        start_loop_here:
-            framesAvail = cblk->framesAvailableOut_l(mFrameCount);
         }
     }
 
-//    if (framesAvail < framesReq) {
-//        return NO_MORE_BUFFERS;
-//    }
-
     if (framesReq > framesAvail) {
         framesReq = framesAvail;
     }
@@ -1584,7 +1575,7 @@ status_t AudioFlinger::PlaybackThread::OutputTrack::obtainBuffer(
     }
 
     buffer->frameCount  = framesReq;
-    buffer->raw         = cblk->buffer(mBuffers, mFrameSize, u);
+    buffer->raw         = mClientProxy->buffer(u);
     return NO_ERROR;
 }
 
@@ -1655,7 +1646,7 @@ AudioFlinger::RecordThread::RecordTrack::RecordTrack(
             size_t frameCount,
             int sessionId)
     :   TrackBase(thread, client, sampleRate, format,
-                  channelMask, frameCount, 0 /*sharedBuffer*/, sessionId),
+                  channelMask, frameCount, 0 /*sharedBuffer*/, sessionId, false /*isOut*/),
         mOverflow(false)
 {
     ALOGV("RecordTrack constructor, size %d", (int)mBufferEnd - (int)mBuffer);
@@ -1684,7 +1675,7 @@ status_t AudioFlinger::RecordThread::RecordTrack::getNextBuffer(AudioBufferProvi
     }
 
     // FIXME lock is not actually held, so overrun is possible
-    framesAvail = cblk->framesAvailableIn_l(mFrameCount);
+    framesAvail = mServerProxy->framesAvailableIn_l();
 
     if (CC_LIKELY(framesAvail)) {
         uint32_t s = cblk->server;
@@ -1761,27 +1752,21 @@ void AudioFlinger::RecordThread::RecordTrack::destroy()
 
 /*static*/ void AudioFlinger::RecordThread::RecordTrack::appendDumpHeader(String8& result)
 {
-    result.append("   Clien Fmt Chn mask   Session Step S SRate  Serv     User   FrameCount\n");
+    result.append("   Clien Fmt Chn mask   Session Step S Serv     User   FrameCount\n");
 }
 
 void AudioFlinger::RecordThread::RecordTrack::dump(char* buffer, size_t size)
 {
-    snprintf(buffer, size, "   %05d %03u 0x%08x %05d   %04u %01d %05u  %08x %08x %05d\n",
+    snprintf(buffer, size, "   %05d %03u 0x%08x %05d   %04u %01d %08x %08x %05d\n",
             (mClient == 0) ? getpid_cached : mClient->pid(),
             mFormat,
             mChannelMask,
             mSessionId,
             mStepCount,
             mState,
-            mCblk->sampleRate,
             mCblk->server,
             mCblk->user,
             mFrameCount);
 }
 
-bool AudioFlinger::RecordThread::RecordTrack::isOut() const
-{
-    return false;
-}
-
 }; // namespace android