Refactored SurfaceMediaSource

SurfaceMediaSource takes advantage of BufferQueue to avoid
duplicated code.

Change-Id: I5e60b8eca21e6c3cf728d363cd8f3786125182d1
diff --git a/include/media/stagefright/SurfaceMediaSource.h b/include/media/stagefright/SurfaceMediaSource.h
index c0dc074..e25d444 100644
--- a/include/media/stagefright/SurfaceMediaSource.h
+++ b/include/media/stagefright/SurfaceMediaSource.h
@@ -18,6 +18,7 @@
 #define ANDROID_GUI_SURFACEMEDIASOURCE_H
 
 #include <gui/ISurfaceTexture.h>
+#include <gui/BufferQueue.h>
 
 #include <utils/threads.h>
 #include <utils/Vector.h>
@@ -31,16 +32,31 @@
 class String8;
 class GraphicBuffer;
 
-class SurfaceMediaSource : public BnSurfaceTexture, public MediaSource,
-                                            public MediaBufferObserver {
+// ASSUMPTIONS
+// 1. SurfaceMediaSource is initialized with width*height which
+// can never change.  However, deqeueue buffer does not currently
+// enforce this as in BufferQueue, dequeue can be used by SurfaceTexture
+// which can modify the default width and heght.  Also neither the width
+// nor height can be 0.
+// 2. setSynchronousMode is never used (basically no one should call
+// setSynchronousMode(false)
+// 3. setCrop, setTransform, setScalingMode should never be used
+// 4. queueBuffer returns a filled buffer to the SurfaceMediaSource. In addition, a
+// timestamp must be provided for the buffer. The timestamp is in
+// nanoseconds, and must be monotonically increasing. Its other semantics
+// (zero point, etc) are client-dependent and should be documented by the
+// client.
+// 5. Once disconnected, SurfaceMediaSource can be reused (can not
+// connect again)
+// 6. Stop is a hard stop, the last few frames held by the encoder
+// may be dropped.  It is possible to wait for the buffers to be
+// returned (but not implemented)
+
+class SurfaceMediaSource : public MediaSource,
+                                public MediaBufferObserver,
+                                protected BufferQueue::ConsumerListener {
 public:
-    enum { MIN_UNDEQUEUED_BUFFERS = 4 };
-    enum {
-        MIN_ASYNC_BUFFER_SLOTS = MIN_UNDEQUEUED_BUFFERS + 1,
-        MIN_SYNC_BUFFER_SLOTS  = MIN_UNDEQUEUED_BUFFERS
-    };
-    enum { NUM_BUFFER_SLOTS = 32 };
-    enum { NO_CONNECTED_API = 0 };
+    enum { MIN_UNDEQUEUED_BUFFERS = 4};
 
     struct FrameAvailableListener : public virtual RefBase {
         // onFrameAvailable() is called from queueBuffer() is the FIFO is
@@ -51,13 +67,13 @@
         virtual void onFrameAvailable() = 0;
     };
 
-    SurfaceMediaSource(uint32_t bufW, uint32_t bufH);
+    SurfaceMediaSource(uint32_t bufferWidth, uint32_t bufferHeight);
 
     virtual ~SurfaceMediaSource();
 
-
     // For the MediaSource interface for use by StageFrightRecorder:
     virtual status_t start(MetaData *params = NULL);
+
     virtual status_t stop() { return reset(); }
     virtual status_t read(
             MediaBuffer **buffer, const ReadOptions *options = NULL);
@@ -77,81 +93,6 @@
     virtual void signalBufferReturned(MediaBuffer* buffer);
     // end of MediaSource interface
 
-    uint32_t getBufferCount( ) const { return mBufferCount;}
-
-
-    // setBufferCount updates the number of available buffer slots.  After
-    // calling this all buffer slots are both unallocated and owned by the
-    // SurfaceMediaSource object (i.e. they are not owned by the client).
-    virtual status_t setBufferCount(int bufferCount);
-
-    virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf);
-
-    // dequeueBuffer gets the next buffer slot index for the client to use. If a
-    // buffer slot is available then that slot index is written to the location
-    // pointed to by the buf argument and a status of OK is returned.  If no
-    // slot is available then a status of -EBUSY is returned and buf is
-    // unmodified.
-    virtual status_t dequeueBuffer(int *buf, uint32_t w, uint32_t h,
-            uint32_t format, uint32_t usage);
-
-    // queueBuffer returns a filled buffer to the SurfaceMediaSource. In addition, a
-    // timestamp must be provided for the buffer. The timestamp is in
-    // nanoseconds, and must be monotonically increasing. Its other semantics
-    // (zero point, etc) are client-dependent and should be documented by the
-    // client.
-    virtual status_t queueBuffer(int buf, int64_t timestamp,
-            const Rect& crop, int scalingMode, uint32_t transform,
-            uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform);
-    virtual void cancelBuffer(int buf);
-
-    // onFrameReceivedLocked informs the buffer consumers (StageFrightRecorder)
-    // or listeners that a frame has been received
-    // The buffer is not made available for dequeueing immediately. We need to
-    // wait to hear from StageFrightRecorder to set the buffer FREE
-    // Make sure this is called when the mutex is locked
-    virtual status_t onFrameReceivedLocked();
-
-    virtual int query(int what, int* value);
-
-    // setSynchronousMode set whether dequeueBuffer is synchronous or
-    // asynchronous. In synchronous mode, dequeueBuffer blocks until
-    // a buffer is available, the currently bound buffer can be dequeued and
-    // queued buffers will be retired in order.
-    // The default mode is synchronous.
-    // TODO: Clarify the minute differences bet sycn /async
-    // modes (S.Encoder vis-a-vis SurfaceTexture)
-    virtual status_t setSynchronousMode(bool enabled);
-
-    // connect attempts to connect a client API to the SurfaceMediaSource.  This
-    // must be called before any other ISurfaceTexture methods are called except
-    // for getAllocator.
-    //
-    // This method will fail if the connect was previously called on the
-    // SurfaceMediaSource and no corresponding disconnect call was made.
-    virtual status_t connect(int api,
-            uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform);
-
-    // disconnect attempts to disconnect a client API from the SurfaceMediaSource.
-    // Calling this method will cause any subsequent calls to other
-    // ISurfaceTexture methods to fail except for getAllocator and connect.
-    // Successfully calling connect after this will allow the other methods to
-    // succeed again.
-    //
-    // This method will fail if the the SurfaceMediaSource is not currently
-    // connected to the specified client API.
-    virtual status_t disconnect(int api);
-
-    // getqueuedCount returns the number of queued frames waiting in the
-    // FIFO. In asynchronous mode, this always returns 0 or 1 since
-    // frames are not accumulating in the FIFO.
-    size_t getQueuedCount() const;
-
-    // setBufferCountServer set the buffer count. If the client has requested
-    // a buffer count using setBufferCount, the server-buffer count will
-    // take effect once the client sets the count back to zero.
-    status_t setBufferCountServer(int bufferCount);
-
     // getTimestamp retrieves the timestamp associated with the image
     // set by the most recent call to read()
     //
@@ -176,105 +117,42 @@
     // pass metadata through the buffers. Currently, it is force set to true
     bool isMetaDataStoredInVideoBuffers() const;
 
+    sp<BufferQueue> getBufferQueue() const { return mBufferQueue; }
+
 protected:
 
-    // freeAllBuffersLocked frees the resources (both GraphicBuffer and EGLImage) for
-    // all slots.
-    void freeAllBuffersLocked();
+    // Implementation of the BufferQueue::ConsumerListener interface.  These
+    // calls are used to notify the SurfaceTexture of asynchronous events in the
+    // BufferQueue.
+    virtual void onFrameAvailable();
+
+    // Used as a hook to BufferQueue::disconnect()
+    // This is called by the client side when it is done
+    // TODO: Currently, this also sets mStopped to true which
+    // is needed for unblocking the encoder which might be
+    // waiting to read more frames. So if on the client side,
+    // the same thread supplies the frames and also calls stop
+    // on the encoder, the client has to call disconnect before
+    // it calls stop.
+    // In the case of the camera,
+    // that need not be required since the thread supplying the
+    // frames is separate than the one calling stop.
+    virtual void onBuffersReleased();
+
     static bool isExternalFormat(uint32_t format);
 
 private:
+    // mBufferQueue is the exchange point between the producer and
+    // this consumer
+    sp<BufferQueue> mBufferQueue;
 
-    status_t setBufferCountServerLocked(int bufferCount);
+    // mBufferSlot caches GraphicBuffers from the buffer queue
+    sp<GraphicBuffer> mBufferSlot[BufferQueue::NUM_BUFFER_SLOTS];
 
-    enum { INVALID_BUFFER_SLOT = -1 };
 
-    struct BufferSlot {
-
-        BufferSlot()
-            : mBufferState(BufferSlot::FREE),
-              mRequestBufferCalled(false),
-              mTimestamp(0) {
-        }
-
-        // mGraphicBuffer points to the buffer allocated for this slot or is
-        // NULL if no buffer has been allocated.
-        sp<GraphicBuffer> mGraphicBuffer;
-
-        // BufferState represents the different states in which a buffer slot
-        // can be.
-        enum BufferState {
-            // FREE indicates that the buffer is not currently being used and
-            // will not be used in the future until it gets dequeued and
-            // subseqently queued by the client.
-            FREE = 0,
-
-            // DEQUEUED indicates that the buffer has been dequeued by the
-            // client, but has not yet been queued or canceled. The buffer is
-            // considered 'owned' by the client, and the server should not use
-            // it for anything.
-            //
-            // Note that when in synchronous-mode (mSynchronousMode == true),
-            // the buffer that's currently attached to the texture may be
-            // dequeued by the client.  That means that the current buffer can
-            // be in either the DEQUEUED or QUEUED state.  In asynchronous mode,
-            // however, the current buffer is always in the QUEUED state.
-            DEQUEUED = 1,
-
-            // QUEUED indicates that the buffer has been queued by the client,
-            // and has not since been made available for the client to dequeue.
-            // Attaching the buffer to the texture does NOT transition the
-            // buffer away from the QUEUED state. However, in Synchronous mode
-            // the current buffer may be dequeued by the client under some
-            // circumstances. See the note about the current buffer in the
-            // documentation for DEQUEUED.
-            QUEUED = 2,
-        };
-
-        // mBufferState is the current state of this buffer slot.
-        BufferState mBufferState;
-
-        // mRequestBufferCalled is used for validating that the client did
-        // call requestBuffer() when told to do so. Technically this is not
-        // needed but useful for debugging and catching client bugs.
-        bool mRequestBufferCalled;
-
-        // mTimestamp is the current timestamp for this buffer slot. This gets
-        // to set by queueBuffer each time this slot is queued.
-        int64_t mTimestamp;
-    };
-
-    // mSlots is the array of buffer slots that must be mirrored on the client
-    // side. This allows buffer ownership to be transferred between the client
-    // and server without sending a GraphicBuffer over binder. The entire array
-    // is initialized to NULL at construction time, and buffers are allocated
-    // for a slot when requestBuffer is called with that slot's index.
-    BufferSlot mSlots[NUM_BUFFER_SLOTS];
-
-    // mDefaultWidth holds the default width of allocated buffers. It is used
-    // in requestBuffers() if a width and height of zero is specified.
-    uint32_t mDefaultWidth;
-
-    // mDefaultHeight holds the default height of allocated buffers. It is used
-    // in requestBuffers() if a width and height of zero is specified.
-    uint32_t mDefaultHeight;
-
-    // mPixelFormat holds the pixel format of allocated buffers. It is used
-    // in requestBuffers() if a format of zero is specified.
-    uint32_t mPixelFormat;
-
-    // mBufferCount is the number of buffer slots that the client and server
-    // must maintain. It defaults to MIN_ASYNC_BUFFER_SLOTS and can be changed
-    // by calling setBufferCount or setBufferCountServer
-    int mBufferCount;
-
-    // mClientBufferCount is the number of buffer slots requested by the
-    // client. The default is zero, which means the client doesn't care how
-    // many buffers there are
-    int mClientBufferCount;
-
-    // mServerBufferCount buffer count requested by the server-side
-    int mServerBufferCount;
+    // The permenent width and height of SMS buffers
+    int mWidth;
+    int mHeight;
 
     // mCurrentSlot is the buffer slot index of the buffer that is currently
     // being used by buffer consumer
@@ -287,43 +165,21 @@
     // reset mCurrentTexture to INVALID_BUFFER_SLOT.
     int mCurrentSlot;
 
-
     // mCurrentBuf is the graphic buffer of the current slot to be used by
     // buffer consumer. It's possible that this buffer is not associated
     // with any buffer slot, so we must track it separately in order to
     // properly use IGraphicBufferAlloc::freeAllGraphicBuffersExcept.
     sp<GraphicBuffer> mCurrentBuf;
 
-
     // mCurrentTimestamp is the timestamp for the current texture. It
     // gets set to mLastQueuedTimestamp each time updateTexImage is called.
     int64_t mCurrentTimestamp;
 
-    // mGraphicBufferAlloc is the connection to SurfaceFlinger that is used to
-    // allocate new GraphicBuffer objects.
-    sp<IGraphicBufferAlloc> mGraphicBufferAlloc;
-
     // mFrameAvailableListener is the listener object that will be called when a
     // new frame becomes available. If it is not NULL it will be called from
     // queueBuffer.
     sp<FrameAvailableListener> mFrameAvailableListener;
 
-    // mSynchronousMode whether we're in synchronous mode or not
-    bool mSynchronousMode;
-
-    // mConnectedApi indicates the API that is currently connected to this
-    // SurfaceTexture.  It defaults to NO_CONNECTED_API (= 0), and gets updated
-    // by the connect and disconnect methods.
-    int mConnectedApi;
-
-    // mDequeueCondition condition used for dequeueBuffer in synchronous mode
-    mutable Condition mDequeueCondition;
-
-
-    // mQueue is a FIFO of queued buffers used in synchronous mode
-    typedef Vector<int> Fifo;
-    Fifo mQueue;
-
     // mMutex is the mutex used to prevent concurrent access to the member
     // variables of SurfaceMediaSource objects. It must be locked whenever the
     // member variables are accessed.
@@ -353,7 +209,6 @@
     // mFrameAvailableCondition condition used to indicate whether there
     // is a frame available for dequeuing
     Condition mFrameAvailableCondition;
-    Condition mFrameCompleteCondition;
 
     status_t reset();
 
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index ca79657..2c5644f 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -90,7 +90,7 @@
 // while encoding GL Frames
 sp<ISurfaceTexture> StagefrightRecorder::querySurfaceMediaSource() const {
     ALOGV("Get SurfaceMediaSource");
-    return mSurfaceMediaSource;
+    return mSurfaceMediaSource->getBufferQueue();
 }
 
 status_t StagefrightRecorder::setAudioSource(audio_source_t as) {
diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp
index 1345cd9..efc71a8 100644
--- a/media/libstagefright/SurfaceMediaSource.cpp
+++ b/media/libstagefright/SurfaceMediaSource.cpp
@@ -35,27 +35,42 @@
 
 namespace android {
 
-SurfaceMediaSource::SurfaceMediaSource(uint32_t bufW, uint32_t bufH) :
-                mDefaultWidth(bufW),
-                mDefaultHeight(bufH),
-                mPixelFormat(0),
-                mBufferCount(MIN_ASYNC_BUFFER_SLOTS),
-                mClientBufferCount(0),
-                mServerBufferCount(MIN_ASYNC_BUFFER_SLOTS),
-                mCurrentSlot(INVALID_BUFFER_SLOT),
-                mCurrentTimestamp(0),
-                mSynchronousMode(true),
-                mConnectedApi(NO_CONNECTED_API),
-                mFrameRate(30),
-                mStopped(false),
-                mNumFramesReceived(0),
-                mNumFramesEncoded(0),
-                mFirstFrameTimestamp(0) {
+SurfaceMediaSource::SurfaceMediaSource(uint32_t bufferWidth, uint32_t bufferHeight) :
+    mWidth(bufferWidth),
+    mHeight(bufferHeight),
+    mCurrentSlot(BufferQueue::INVALID_BUFFER_SLOT),
+    mCurrentTimestamp(0),
+    mFrameRate(30),
+    mStopped(false),
+    mNumFramesReceived(0),
+    mNumFramesEncoded(0),
+    mFirstFrameTimestamp(0)
+{
     ALOGV("SurfaceMediaSource::SurfaceMediaSource");
+
+    if (bufferWidth == 0 || bufferHeight == 0) {
+        ALOGE("Invalid dimensions %dx%d", bufferWidth, bufferHeight);
+    }
+
+    mBufferQueue = new BufferQueue(true, MIN_UNDEQUEUED_BUFFERS);
+    mBufferQueue->setDefaultBufferSize(bufferWidth, bufferHeight);
+    mBufferQueue->setSynchronousMode(true);
+
     sp<ISurfaceComposer> composer(ComposerService::getComposerService());
-    mGraphicBufferAlloc = composer->createGraphicBufferAlloc();
-    if (mGraphicBufferAlloc == 0) {
-        ALOGE("createGraphicBufferAlloc() failed in SurfaceMediaSource()");
+
+    // Note that we can't create an sp<...>(this) in a ctor that will not keep a
+    // reference once the ctor ends, as that would cause the refcount of 'this'
+    // dropping to 0 at the end of the ctor.  Since all we need is a wp<...>
+    // that's what we create.
+    wp<BufferQueue::ConsumerListener> listener;
+    sp<BufferQueue::ConsumerListener> proxy;
+    listener = static_cast<BufferQueue::ConsumerListener*>(this);
+    proxy = new BufferQueue::ProxyConsumerListener(listener);
+
+    status_t err = mBufferQueue->consumerConnect(proxy);
+    if (err != NO_ERROR) {
+        ALOGE("SurfaceMediaSource: error connecting to BufferQueue: %s (%d)",
+                strerror(-err), err);
     }
 }
 
@@ -66,523 +81,12 @@
     }
 }
 
-size_t SurfaceMediaSource::getQueuedCount() const {
-    Mutex::Autolock lock(mMutex);
-    return mQueue.size();
-}
-
-status_t SurfaceMediaSource::setBufferCountServerLocked(int bufferCount) {
-    if (bufferCount > NUM_BUFFER_SLOTS)
-        return BAD_VALUE;
-
-    // special-case, nothing to do
-    if (bufferCount == mBufferCount)
-        return OK;
-
-    if (!mClientBufferCount &&
-        bufferCount >= mBufferCount) {
-        // easy, we just have more buffers
-        mBufferCount = bufferCount;
-        mServerBufferCount = bufferCount;
-        mDequeueCondition.signal();
-    } else {
-        // we're here because we're either
-        // - reducing the number of available buffers
-        // - or there is a client-buffer-count in effect
-
-        // less than 2 buffers is never allowed
-        if (bufferCount < 2)
-            return BAD_VALUE;
-
-        // when there is non client-buffer-count in effect, the client is not
-        // allowed to dequeue more than one buffer at a time,
-        // so the next time they dequeue a buffer, we know that they don't
-        // own one. the actual resizing will happen during the next
-        // dequeueBuffer.
-
-        mServerBufferCount = bufferCount;
-    }
-    return OK;
-}
-
-// Called from the consumer side
-status_t SurfaceMediaSource::setBufferCountServer(int bufferCount) {
-    Mutex::Autolock lock(mMutex);
-    return setBufferCountServerLocked(bufferCount);
-}
-
-status_t SurfaceMediaSource::setBufferCount(int bufferCount) {
-    ALOGV("SurfaceMediaSource::setBufferCount");
-    if (bufferCount > NUM_BUFFER_SLOTS) {
-        ALOGE("setBufferCount: bufferCount is larger than the number of buffer slots");
-        return BAD_VALUE;
-    }
-
-    Mutex::Autolock lock(mMutex);
-    // Error out if the user has dequeued buffers
-    for (int i = 0 ; i < mBufferCount ; i++) {
-        if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) {
-            ALOGE("setBufferCount: client owns some buffers");
-            return INVALID_OPERATION;
-        }
-    }
-
-    if (bufferCount == 0) {
-        const int minBufferSlots = mSynchronousMode ?
-                MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
-        mClientBufferCount = 0;
-        bufferCount = (mServerBufferCount >= minBufferSlots) ?
-                mServerBufferCount : minBufferSlots;
-        return setBufferCountServerLocked(bufferCount);
-    }
-
-    // We don't allow the client to set a buffer-count less than
-    // MIN_ASYNC_BUFFER_SLOTS (3), there is no reason for it.
-    if (bufferCount < MIN_ASYNC_BUFFER_SLOTS) {
-        return BAD_VALUE;
-    }
-
-    // here we're guaranteed that the client doesn't have dequeued buffers
-    // and will release all of its buffer references.
-    mBufferCount = bufferCount;
-    mClientBufferCount = bufferCount;
-    mCurrentSlot = INVALID_BUFFER_SLOT;
-    mQueue.clear();
-    mDequeueCondition.signal();
-    freeAllBuffersLocked();
-    return OK;
-}
-
-status_t SurfaceMediaSource::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
-    ALOGV("SurfaceMediaSource::requestBuffer");
-    Mutex::Autolock lock(mMutex);
-    if (slot < 0 || mBufferCount <= slot) {
-        ALOGE("requestBuffer: slot index out of range [0, %d]: %d",
-                mBufferCount, slot);
-        return BAD_VALUE;
-    }
-    mSlots[slot].mRequestBufferCalled = true;
-    *buf = mSlots[slot].mGraphicBuffer;
-    return NO_ERROR;
-}
-
-status_t SurfaceMediaSource::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
-                                            uint32_t format, uint32_t usage) {
-    ALOGV("dequeueBuffer");
-    Mutex::Autolock lock(mMutex);
-
-    // Check for the buffer size- the client should just use the
-    // default width and height, and not try to set those.
-    // This is needed since
-    // the getFormat() returns mDefaultWidth/ Height for the OMX. It is
-    // queried by OMX in the beginning and not every time a frame comes.
-    // Not sure if there is  a way to update the
-    // frame size while recording. So as of now, the client side
-    // sets the default values via the constructor, and the encoder is
-    // setup to encode frames of that size
-    // The design might need to change in the future.
-    // TODO: Currently just uses mDefaultWidth/Height. In the future
-    // we might declare mHeight and mWidth and check against those here.
-    if ((w != 0) || (h != 0)) {
-        if ((w != mDefaultWidth) || (h != mDefaultHeight)) {
-            ALOGE("dequeuebuffer: invalid buffer size! Req: %dx%d, Found: %dx%d",
-                    mDefaultWidth, mDefaultHeight, w, h);
-            return BAD_VALUE;
-        }
-    }
-
-    status_t returnFlags(OK);
-    int found, foundSync;
-    int dequeuedCount = 0;
-    bool tryAgain = true;
-    while (tryAgain) {
-        // We need to wait for the FIFO to drain if the number of buffer
-        // needs to change.
-        //
-        // The condition "number of buffer needs to change" is true if
-        // - the client doesn't care about how many buffers there are
-        // - AND the actual number of buffer is different from what was
-        //   set in the last setBufferCountServer()
-        //                         - OR -
-        //   setBufferCountServer() was set to a value incompatible with
-        //   the synchronization mode (for instance because the sync mode
-        //   changed since)
-        //
-        // As long as this condition is true AND the FIFO is not empty, we
-        // wait on mDequeueCondition.
-
-        int minBufferCountNeeded = mSynchronousMode ?
-                MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
-
-        if (!mClientBufferCount &&
-                ((mServerBufferCount != mBufferCount) ||
-                        (mServerBufferCount < minBufferCountNeeded))) {
-            // wait for the FIFO to drain
-            while (!mQueue.isEmpty()) {
-                ALOGV("Waiting for the FIFO to drain");
-                mDequeueCondition.wait(mMutex);
-            }
-            if (mStopped) {
-                return NO_INIT;
-            }
-            // need to check again since the mode could have changed
-            // while we were waiting
-            minBufferCountNeeded = mSynchronousMode ?
-                    MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
-        }
-
-        if (!mClientBufferCount &&
-                ((mServerBufferCount != mBufferCount) ||
-                        (mServerBufferCount < minBufferCountNeeded))) {
-            // here we're guaranteed that mQueue is empty
-            freeAllBuffersLocked();
-            mBufferCount = mServerBufferCount;
-            if (mBufferCount < minBufferCountNeeded)
-                mBufferCount = minBufferCountNeeded;
-            mCurrentSlot = INVALID_BUFFER_SLOT;
-            returnFlags |= ISurfaceTexture::RELEASE_ALL_BUFFERS;
-        }
-
-        // look for a free buffer to give to the client
-        found = INVALID_BUFFER_SLOT;
-        foundSync = INVALID_BUFFER_SLOT;
-        dequeuedCount = 0;
-        for (int i = 0; i < mBufferCount; i++) {
-            const int state = mSlots[i].mBufferState;
-            if (state == BufferSlot::DEQUEUED) {
-                dequeuedCount++;
-                continue; // won't be continuing if could
-                // dequeue a non 'FREE' current slot like
-                // that in SurfaceTexture
-            }
-            // In case of Encoding, we do not deque the mCurrentSlot buffer
-            //  since we follow synchronous mode (unlike possibly in
-            //  SurfaceTexture that could be using the asynch mode
-            //  or has some mechanism in GL to be able to wait till the
-            //  currentslot is done using the data)
-            // Here, we have to wait for the MPEG4Writer(or equiv)
-            // to tell us when it's done using the current buffer
-            if (state == BufferSlot::FREE) {
-                foundSync = i;
-                // Unlike that in SurfaceTexture,
-                // We don't need to worry if it is the
-                // currentslot or not as it is in state FREE
-                found = i;
-                break;
-            }
-        }
-
-        // clients are not allowed to dequeue more than one buffer
-        // if they didn't set a buffer count.
-        if (!mClientBufferCount && dequeuedCount) {
-            return -EINVAL;
-        }
-
-        // See whether a buffer has been queued since the last setBufferCount so
-        // we know whether to perform the MIN_UNDEQUEUED_BUFFERS check below.
-        bool bufferHasBeenQueued = mCurrentSlot != INVALID_BUFFER_SLOT;
-        if (bufferHasBeenQueued) {
-            // make sure the client is not trying to dequeue more buffers
-            // than allowed.
-            const int avail = mBufferCount - (dequeuedCount+1);
-            if (avail < (MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode))) {
-                ALOGE("dequeueBuffer: MIN_UNDEQUEUED_BUFFERS=%d exceeded (dequeued=%d)",
-                        MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode),
-                        dequeuedCount);
-                return -EBUSY;
-            }
-        }
-
-        // we're in synchronous mode and didn't find a buffer, we need to wait
-        // for for some buffers to be consumed
-        tryAgain = mSynchronousMode && (foundSync == INVALID_BUFFER_SLOT);
-        if (tryAgain) {
-            ALOGV("Waiting..In synchronous mode and no buffer to dequeue");
-            mDequeueCondition.wait(mMutex);
-        }
-        if (mStopped) {
-            return NO_INIT;
-        }
-    }
-
-    if (mSynchronousMode && found == INVALID_BUFFER_SLOT) {
-        // foundSync guaranteed to be != INVALID_BUFFER_SLOT
-        found = foundSync;
-    }
-
-    if (found == INVALID_BUFFER_SLOT) {
-        return -EBUSY;
-    }
-
-    const int bufIndex = found;
-    *outBuf = found;
-
-    const bool useDefaultSize = !w && !h;
-    if (useDefaultSize) {
-        // use the default size
-        w = mDefaultWidth;
-        h = mDefaultHeight;
-    }
-
-    const bool updateFormat = (format != 0);
-    if (!updateFormat) {
-        // keep the current (or default) format
-        format = mPixelFormat;
-    }
-
-    // buffer is now in DEQUEUED (but can also be current at the same time,
-    // if we're in synchronous mode)
-    mSlots[bufIndex].mBufferState = BufferSlot::DEQUEUED;
-
-    const sp<GraphicBuffer>& buffer(mSlots[bufIndex].mGraphicBuffer);
-    if ((buffer == NULL) ||
-        (uint32_t(buffer->width)  != w) ||
-        (uint32_t(buffer->height) != h) ||
-        (uint32_t(buffer->format) != format) ||
-        ((uint32_t(buffer->usage) & usage) != usage)) {
-            // XXX: This will be changed to USAGE_HW_VIDEO_ENCODER once driver
-            // issues with that flag get fixed.
-            usage |= GraphicBuffer::USAGE_HW_TEXTURE;
-            status_t error;
-            sp<GraphicBuffer> graphicBuffer(
-                    mGraphicBufferAlloc->createGraphicBuffer(
-                                    w, h, format, usage, &error));
-            if (graphicBuffer == 0) {
-                ALOGE("dequeueBuffer: SurfaceComposer::createGraphicBuffer failed");
-                return error;
-            }
-            if (updateFormat) {
-                mPixelFormat = format;
-            }
-            mSlots[bufIndex].mGraphicBuffer = graphicBuffer;
-            mSlots[bufIndex].mRequestBufferCalled = false;
-            returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION;
-    }
-    return returnFlags;
-}
-
-// TODO: clean this up
-status_t SurfaceMediaSource::setSynchronousMode(bool enabled) {
-    Mutex::Autolock lock(mMutex);
-    if (mStopped) {
-        ALOGE("setSynchronousMode: SurfaceMediaSource has been stopped!");
-        return NO_INIT;
-    }
-
-    if (!enabled) {
-        // Async mode is not allowed
-        ALOGE("SurfaceMediaSource can be used only synchronous mode!");
-        return INVALID_OPERATION;
-    }
-
-    if (mSynchronousMode != enabled) {
-        // - if we're going to asynchronous mode, the queue is guaranteed to be
-        // empty here
-        // - if the client set the number of buffers, we're guaranteed that
-        // we have at least 3 (because we don't allow less)
-        mSynchronousMode = enabled;
-        mDequeueCondition.signal();
-    }
-    return OK;
-}
-
-status_t SurfaceMediaSource::connect(int api,
-        uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
-    ALOGV("SurfaceMediaSource::connect");
-    Mutex::Autolock lock(mMutex);
-
-    if (mStopped) {
-        ALOGE("Connect: SurfaceMediaSource has been stopped!");
-        return NO_INIT;
-    }
-
-    status_t err = NO_ERROR;
-    switch (api) {
-        case NATIVE_WINDOW_API_EGL:
-        case NATIVE_WINDOW_API_CPU:
-        case NATIVE_WINDOW_API_MEDIA:
-        case NATIVE_WINDOW_API_CAMERA:
-            if (mConnectedApi != NO_CONNECTED_API) {
-                err = -EINVAL;
-            } else {
-                mConnectedApi = api;
-                *outWidth = mDefaultWidth;
-                *outHeight = mDefaultHeight;
-                *outTransform = 0;
-            }
-            break;
-        default:
-            err = -EINVAL;
-            break;
-    }
-    return err;
-}
-
-// This is called by the client side when it is done
-// TODO: Currently, this also sets mStopped to true which
-// is needed for unblocking the encoder which might be
-// waiting to read more frames. So if on the client side,
-// the same thread supplies the frames and also calls stop
-// on the encoder, the client has to call disconnect before
-// it calls stop.
-// In the case of the camera,
-// that need not be required since the thread supplying the
-// frames is separate than the one calling stop.
-status_t SurfaceMediaSource::disconnect(int api) {
-    ALOGV("SurfaceMediaSource::disconnect");
-    Mutex::Autolock lock(mMutex);
-
-    if (mStopped) {
-        ALOGE("disconnect: SurfaceMediaSoource is already stopped!");
-        return NO_INIT;
-    }
-
-    status_t err = NO_ERROR;
-    switch (api) {
-        case NATIVE_WINDOW_API_EGL:
-        case NATIVE_WINDOW_API_CPU:
-        case NATIVE_WINDOW_API_MEDIA:
-        case NATIVE_WINDOW_API_CAMERA:
-            if (mConnectedApi == api) {
-                mConnectedApi = NO_CONNECTED_API;
-                mStopped = true;
-                mDequeueCondition.signal();
-                mFrameAvailableCondition.signal();
-            } else {
-                err = -EINVAL;
-            }
-            break;
-        default:
-            err = -EINVAL;
-            break;
-    }
-    return err;
-}
-
-status_t SurfaceMediaSource::queueBuffer(int bufIndex, int64_t timestamp,
-        const Rect& crop, int scalingMode, uint32_t transform,
-        uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
-    ALOGV("queueBuffer");
-
-    Mutex::Autolock lock(mMutex);
-    *outWidth = mDefaultWidth;
-    *outHeight = mDefaultHeight;
-    *outTransform = 0;
-
-    if (bufIndex < 0 || bufIndex >= mBufferCount) {
-        ALOGE("queueBuffer: slot index out of range [0, %d]: %d",
-                mBufferCount, bufIndex);
-        return -EINVAL;
-    } else if (mSlots[bufIndex].mBufferState != BufferSlot::DEQUEUED) {
-        ALOGE("queueBuffer: slot %d is not owned by the client (state=%d)",
-                bufIndex, mSlots[bufIndex].mBufferState);
-        return -EINVAL;
-    } else if (!mSlots[bufIndex].mRequestBufferCalled) {
-        ALOGE("queueBuffer: slot %d was enqueued without requesting a "
-                "buffer", bufIndex);
-        return -EINVAL;
-    }
-
-    if (mNumFramesReceived == 0) {
-        mFirstFrameTimestamp = timestamp;
-        // Initial delay
-        if (mStartTimeNs > 0) {
-            if (timestamp < mStartTimeNs) {
-                // This frame predates start of record, discard
-                mSlots[bufIndex].mBufferState = BufferSlot::FREE;
-                mDequeueCondition.signal();
-                return OK;
-            }
-            mStartTimeNs = timestamp - mStartTimeNs;
-        }
-    }
-    timestamp = mStartTimeNs + (timestamp - mFirstFrameTimestamp);
-
-    mNumFramesReceived++;
-    if (mSynchronousMode) {
-        // in synchronous mode we queue all buffers in a FIFO
-        mQueue.push_back(bufIndex);
-        ALOGV("Client queued buf# %d @slot: %d, Q size = %d, handle = %p, timestamp = %lld",
-            mNumFramesReceived, bufIndex, mQueue.size(),
-            mSlots[bufIndex].mGraphicBuffer->handle, timestamp);
-    } else {
-        // in asynchronous mode we only keep the most recent buffer
-        if (mQueue.empty()) {
-            mQueue.push_back(bufIndex);
-        } else {
-            Fifo::iterator front(mQueue.begin());
-            // buffer currently queued is freed
-            mSlots[*front].mBufferState = BufferSlot::FREE;
-            // and we record the new buffer index in the queued list
-            *front = bufIndex;
-        }
-    }
-
-    mSlots[bufIndex].mBufferState = BufferSlot::QUEUED;
-    mSlots[bufIndex].mTimestamp = timestamp;
-    // TODO: (Confirm) Don't want to signal dequeue here.
-    // May be just in asynchronous mode?
-    // mDequeueCondition.signal();
-
-    // Once the queuing is done, we need to let the listener
-    // and signal the buffer consumer (encoder) know that a
-    // buffer is available
-    onFrameReceivedLocked();
-
-
-    return OK;
-}
-
-
-// onFrameReceivedLocked informs the buffer consumers (StageFrightRecorder)
-// or listeners that a frame has been received
-// It is supposed to be called only from queuebuffer.
-// The buffer is NOT made available for dequeueing immediately. We need to
-// wait to hear from StageFrightRecorder to set the buffer FREE
-// Make sure this is called when the mutex is locked
-status_t SurfaceMediaSource::onFrameReceivedLocked() {
-    ALOGV("On Frame Received locked");
-    // Signal the encoder that a new frame has arrived
-    mFrameAvailableCondition.signal();
-
-    // call back the listener
-    // TODO: The listener may not be needed in SurfaceMediaSource at all.
-    // This can be made a SurfaceTexture specific thing
-    sp<FrameAvailableListener> listener;
-    if (mSynchronousMode || mQueue.empty()) {
-        listener = mFrameAvailableListener;
-    }
-
-    if (listener != 0) {
-        listener->onFrameAvailable();
-    }
-    return OK;
-}
-
-
-void SurfaceMediaSource::cancelBuffer(int bufIndex) {
-    ALOGV("SurfaceMediaSource::cancelBuffer");
-    Mutex::Autolock lock(mMutex);
-    if (bufIndex < 0 || bufIndex >= mBufferCount) {
-        ALOGE("cancelBuffer: slot index out of range [0, %d]: %d",
-                mBufferCount, bufIndex);
-        return;
-    } else if (mSlots[bufIndex].mBufferState != BufferSlot::DEQUEUED) {
-        ALOGE("cancelBuffer: slot %d is not owned by the client (state=%d)",
-                bufIndex, mSlots[bufIndex].mBufferState);
-        return;
-    }
-    mSlots[bufIndex].mBufferState = BufferSlot::FREE;
-    mDequeueCondition.signal();
-}
-
 nsecs_t SurfaceMediaSource::getTimestamp() {
     ALOGV("SurfaceMediaSource::getTimestamp");
     Mutex::Autolock lock(mMutex);
     return mCurrentTimestamp;
 }
 
-
 void SurfaceMediaSource::setFrameAvailableListener(
         const sp<FrameAvailableListener>& listener) {
     ALOGV("SurfaceMediaSource::setFrameAvailableListener");
@@ -590,49 +94,11 @@
     mFrameAvailableListener = listener;
 }
 
-void SurfaceMediaSource::freeAllBuffersLocked() {
-    ALOGV("freeAllBuffersLocked");
-    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
-        mSlots[i].mGraphicBuffer = 0;
-        mSlots[i].mBufferState = BufferSlot::FREE;
-    }
-}
-
 sp<GraphicBuffer> SurfaceMediaSource::getCurrentBuffer() const {
     Mutex::Autolock lock(mMutex);
     return mCurrentBuf;
 }
 
-int SurfaceMediaSource::query(int what, int* outValue)
-{
-    ALOGV("query");
-    Mutex::Autolock lock(mMutex);
-    int value;
-    switch (what) {
-    case NATIVE_WINDOW_WIDTH:
-        value = mDefaultWidth;
-        if (!mDefaultWidth && !mDefaultHeight && mCurrentBuf != 0)
-            value = mCurrentBuf->width;
-        break;
-    case NATIVE_WINDOW_HEIGHT:
-        value = mDefaultHeight;
-        if (!mDefaultWidth && !mDefaultHeight && mCurrentBuf != 0)
-            value = mCurrentBuf->height;
-        break;
-    case NATIVE_WINDOW_FORMAT:
-        value = mPixelFormat;
-        break;
-    case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
-        value = mSynchronousMode ?
-                (MIN_UNDEQUEUED_BUFFERS-1) : MIN_UNDEQUEUED_BUFFERS;
-        break;
-    default:
-        return BAD_VALUE;
-    }
-    outValue[0] = value;
-    return NO_ERROR;
-}
-
 void SurfaceMediaSource::dump(String8& result) const
 {
     char buffer[1024];
@@ -642,46 +108,10 @@
 void SurfaceMediaSource::dump(String8& result, const char* prefix,
         char* buffer, size_t SIZE) const
 {
-    Mutex::Autolock _l(mMutex);
-    snprintf(buffer, SIZE,
-            "%smBufferCount=%d, mSynchronousMode=%d, default-size=[%dx%d], "
-            "mPixelFormat=%d, \n",
-            prefix, mBufferCount, mSynchronousMode, mDefaultWidth, mDefaultHeight,
-            mPixelFormat);
-    result.append(buffer);
-
-    String8 fifo;
-    int fifoSize = 0;
-    Fifo::const_iterator i(mQueue.begin());
-    while (i != mQueue.end()) {
-        snprintf(buffer, SIZE, "%02d ", *i++);
-        fifoSize++;
-        fifo.append(buffer);
-    }
+    Mutex::Autolock lock(mMutex);
 
     result.append(buffer);
-
-    struct {
-        const char * operator()(int state) const {
-            switch (state) {
-                case BufferSlot::DEQUEUED: return "DEQUEUED";
-                case BufferSlot::QUEUED: return "QUEUED";
-                case BufferSlot::FREE: return "FREE";
-                default: return "Unknown";
-            }
-        }
-    } stateName;
-
-    for (int i = 0; i < mBufferCount; i++) {
-        const BufferSlot& slot(mSlots[i]);
-        snprintf(buffer, SIZE,
-                "%s%s[%02d] state=%-8s, "
-                "timestamp=%lld\n",
-                prefix, (i==mCurrentSlot)?">":" ", i, stateName(slot.mBufferState),
-                slot.mTimestamp
-        );
-        result.append(buffer);
-    }
+    mBufferQueue->dump(result);
 }
 
 status_t SurfaceMediaSource::setFrameRate(int32_t fps)
@@ -726,10 +156,9 @@
     Mutex::Autolock lock(mMutex);
     // TODO: Add waiting on mFrameCompletedCondition here?
     mStopped = true;
+
     mFrameAvailableCondition.signal();
-    mDequeueCondition.signal();
-    mQueue.clear();
-    freeAllBuffersLocked();
+    mBufferQueue->consumerDisconnect();
 
     return OK;
 }
@@ -737,17 +166,18 @@
 sp<MetaData> SurfaceMediaSource::getFormat()
 {
     ALOGV("getFormat");
-    Mutex::Autolock autoLock(mMutex);
+
+    Mutex::Autolock lock(mMutex);
     sp<MetaData> meta = new MetaData;
 
-    meta->setInt32(kKeyWidth, mDefaultWidth);
-    meta->setInt32(kKeyHeight, mDefaultHeight);
+    meta->setInt32(kKeyWidth, mWidth);
+    meta->setInt32(kKeyHeight, mHeight);
     // The encoder format is set as an opaque colorformat
     // The encoder will later find out the actual colorformat
     // from the GL Frames itself.
     meta->setInt32(kKeyColorFormat, OMX_COLOR_FormatAndroidOpaque);
-    meta->setInt32(kKeyStride, mDefaultWidth);
-    meta->setInt32(kKeySliceHeight, mDefaultHeight);
+    meta->setInt32(kKeyStride, mWidth);
+    meta->setInt32(kKeySliceHeight, mHeight);
     meta->setInt32(kKeyFrameRate, mFrameRate);
     meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
     return meta;
@@ -756,16 +186,54 @@
 status_t SurfaceMediaSource::read( MediaBuffer **buffer,
                                     const ReadOptions *options)
 {
-    Mutex::Autolock autoLock(mMutex) ;
+    ALOGV("read");
+    Mutex::Autolock lock(mMutex);
 
-    ALOGV("Read. Size of queued buffer: %d", mQueue.size());
     *buffer = NULL;
 
+    // Update the current buffer info
+    // TODO: mCurrentSlot can be made a bufferstate since there
+    // can be more than one "current" slots.
+
+    BufferQueue::BufferItem item;
     // If the recording has started and the queue is empty, then just
     // wait here till the frames come in from the client side
-    while (!mStopped && mQueue.empty()) {
-        ALOGV("NO FRAMES! Recorder waiting for FrameAvailableCondition");
-        mFrameAvailableCondition.wait(mMutex);
+    while (!mStopped) {
+
+        status_t err = mBufferQueue->acquireBuffer(&item);
+        if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
+            // wait for a buffer to be queued
+            mFrameAvailableCondition.wait(mMutex);
+        } else if (err == OK) {
+
+            // First time seeing the buffer?  Added it to the SMS slot
+            if (item.mGraphicBuffer != NULL) {
+                mBufferSlot[item.mBuf] = item.mGraphicBuffer;
+            }
+
+            // check for the timing of this buffer
+            if (mNumFramesReceived == 0) {
+                mFirstFrameTimestamp = item.mTimestamp;
+                // Initial delay
+                if (mStartTimeNs > 0) {
+                    if (item.mTimestamp < mStartTimeNs) {
+                        // This frame predates start of record, discard
+                        mBufferQueue->releaseBuffer(item.mBuf, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
+                        continue;
+                    }
+                    mStartTimeNs = item.mTimestamp - mStartTimeNs;
+                }
+            }
+            item.mTimestamp = mStartTimeNs + (item.mTimestamp - mFirstFrameTimestamp);
+
+            mNumFramesReceived++;
+
+            break;
+        } else {
+            ALOGE("read: acquire failed with error code %d", err);
+            return ERROR_END_OF_STREAM;
+        }
+
     }
 
     // If the loop was exited as a result of stopping the recording,
@@ -775,15 +243,15 @@
         return ERROR_END_OF_STREAM;
     }
 
-    // Update the current buffer info
-    // TODO: mCurrentSlot can be made a bufferstate since there
-    // can be more than one "current" slots.
-    Fifo::iterator front(mQueue.begin());
-    mCurrentSlot = *front;
-    mQueue.erase(front);
-    mCurrentBuf = mSlots[mCurrentSlot].mGraphicBuffer;
+    mCurrentSlot = item.mBuf;
+
+    // First time seeing the buffer?  Added it to the SMS slot
+    if (item.mGraphicBuffer != NULL) {
+        mBufferSlot[mCurrentSlot] = item.mGraphicBuffer;
+    }
+    mCurrentBuf = mBufferSlot[mCurrentSlot];
     int64_t prevTimeStamp = mCurrentTimestamp;
-    mCurrentTimestamp = mSlots[mCurrentSlot].mTimestamp;
+    mCurrentTimestamp = item.mTimestamp;
 
     mNumFramesEncoded++;
     // Pass the data to the MediaBuffer. Pass in only the metadata
@@ -796,6 +264,7 @@
             mNumFramesEncoded, mCurrentTimestamp / 1000,
             mCurrentTimestamp / 1000 - prevTimeStamp / 1000);
 
+
     return OK;
 }
 
@@ -833,25 +302,27 @@
     ALOGV("signalBufferReturned");
 
     bool foundBuffer = false;
-    Mutex::Autolock autoLock(mMutex);
+
+    Mutex::Autolock lock(mMutex);
 
     if (mStopped) {
         ALOGV("signalBufferReturned: mStopped = true! Nothing to do!");
         return;
     }
 
-    for (int id = 0; id < NUM_BUFFER_SLOTS; id++) {
-        if (mSlots[id].mGraphicBuffer == NULL) {
+    for (int id = 0; id < BufferQueue::NUM_BUFFER_SLOTS; id++) {
+        if (mBufferSlot[id] == NULL) {
             continue;
         }
         if (checkBufferMatchesSlot(id, buffer)) {
             ALOGV("Slot %d returned, matches handle = %p", id,
-                    mSlots[id].mGraphicBuffer->handle);
-            mSlots[id].mBufferState = BufferSlot::FREE;
+                    mBufferSlot[id]->handle);
+
+            mBufferQueue->releaseBuffer(id, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
+
             buffer->setObserver(0);
             buffer->release();
-            mDequeueCondition.signal();
-            mFrameCompleteCondition.signal();
+
             foundBuffer = true;
             break;
         }
@@ -868,7 +339,40 @@
     // copy the byte stream into our handle
     buffer_handle_t bufferHandle ;
     memcpy( &bufferHandle, (char *)(buffer->data()) + 4, sizeof(buffer_handle_t));
-    return mSlots[slot].mGraphicBuffer->handle  ==  bufferHandle;
+    return mBufferSlot[slot]->handle  ==  bufferHandle;
+}
+
+// Part of the BufferQueue::ConsumerListener
+void SurfaceMediaSource::onFrameAvailable() {
+    ALOGV("onFrameAvailable");
+
+    sp<FrameAvailableListener> listener;
+    { // scope for the lock
+        Mutex::Autolock lock(mMutex);
+        mFrameAvailableCondition.broadcast();
+        listener = mFrameAvailableListener;
+    }
+
+    if (listener != NULL) {
+        ALOGV("actually calling onFrameAvailable");
+        listener->onFrameAvailable();
+    }
+}
+
+// SurfaceMediaSource hijacks this event to assume
+// the prodcuer is disconnecting from the BufferQueue
+// and that it should stop the recording
+void SurfaceMediaSource::onBuffersReleased() {
+    ALOGV("onBuffersReleased");
+
+    Mutex::Autolock lock(mMutex);
+
+    mFrameAvailableCondition.signal();
+    mStopped = true;
+
+    for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
+       mBufferSlot[i] = 0;
+    }
 }
 
 } // end of namespace android
diff --git a/media/libstagefright/tests/SurfaceMediaSource_test.cpp b/media/libstagefright/tests/SurfaceMediaSource_test.cpp
index fe77cf7..10713fe 100644
--- a/media/libstagefright/tests/SurfaceMediaSource_test.cpp
+++ b/media/libstagefright/tests/SurfaceMediaSource_test.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-// #define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
 #define LOG_TAG "SurfaceMediaSource_test"
 
 #include <gtest/gtest.h>
@@ -107,8 +107,8 @@
                     window.get(), NULL);
         } else {
             ALOGV("No actual display. Choosing EGLSurface based on SurfaceMediaSource");
-            sp<ISurfaceTexture> sms = new SurfaceMediaSource(
-                    getSurfaceWidth(), getSurfaceHeight());
+            sp<ISurfaceTexture> sms = (new SurfaceMediaSource(
+                    getSurfaceWidth(), getSurfaceHeight()))->getBufferQueue();
             sp<SurfaceTextureClient> stc = new SurfaceTextureClient(sms);
             sp<ANativeWindow> window = stc;
 
@@ -359,9 +359,9 @@
     virtual void SetUp() {
         android::ProcessState::self()->startThreadPool();
         mSMS = new SurfaceMediaSource(mYuvTexWidth, mYuvTexHeight);
-        mSMS->setSynchronousMode(true);
+
         // Manual cast is required to avoid constructor ambiguity
-        mSTC = new SurfaceTextureClient(static_cast<sp<ISurfaceTexture> >( mSMS));
+        mSTC = new SurfaceTextureClient(static_cast<sp<ISurfaceTexture> >( mSMS->getBufferQueue()));
         mANW = mSTC;
     }
 
@@ -396,7 +396,7 @@
         ALOGV("SMS-GLTest::SetUp()");
         android::ProcessState::self()->startThreadPool();
         mSMS = new SurfaceMediaSource(mYuvTexWidth, mYuvTexHeight);
-        mSTC = new SurfaceTextureClient(static_cast<sp<ISurfaceTexture> >( mSMS));
+        mSTC = new SurfaceTextureClient(static_cast<sp<ISurfaceTexture> >( mSMS->getBufferQueue()));
         mANW = mSTC;
 
         // Doing the setup related to the GL Side
@@ -675,7 +675,7 @@
 
 // Delayed pass of multiple buffers from the native_window the SurfaceMediaSource
 // Dummy Encoder
-TEST_F(SurfaceMediaSourceTest,  DISABLED_DummyLagEncodingFromCpuFilledYV12BufferNpotMultiBufferPass) {
+TEST_F(SurfaceMediaSourceTest,  DummyLagEncodingFromCpuFilledYV12BufferNpotMultiBufferPass) {
     ALOGV("Test # %d", testId++);
     ALOGV("Testing MultiBufferPass, Dummy Recorder Lagging **************");
 
@@ -686,8 +686,10 @@
     writer.start();
 
     int32_t nFramesCount = 1;
-    const int FRAMES_LAG = mSMS->getBufferCount() - 1;
+    const int FRAMES_LAG = SurfaceMediaSource::MIN_UNDEQUEUED_BUFFERS;
+
     while (nFramesCount <= 300) {
+        ALOGV("Frame: %d", nFramesCount);
         oneBufferPass(mYuvTexWidth, mYuvTexHeight);
         // Forcing the writer to lag behind a few frames
         if (nFramesCount > FRAMES_LAG) {
@@ -700,7 +702,7 @@
 
 // pass multiple buffers from the native_window the SurfaceMediaSource
 // A dummy writer (MULTITHREADED) is used to simulate actual MPEG4Writer
-TEST_F(SurfaceMediaSourceTest, DISABLED_DummyThreadedEncodingFromCpuFilledYV12BufferNpotMultiBufferPass) {
+TEST_F(SurfaceMediaSourceTest, DummyThreadedEncodingFromCpuFilledYV12BufferNpotMultiBufferPass) {
     ALOGV("Test # %d", testId++);
     ALOGV("Testing MultiBufferPass, Dummy Recorder Multi-Threaded **********");
     ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(),
@@ -711,6 +713,7 @@
 
     int32_t nFramesCount = 0;
     while (nFramesCount <= 300) {
+        ALOGV("Frame: %d", nFramesCount);
         oneBufferPass(mYuvTexWidth, mYuvTexHeight);
 
         nFramesCount++;
@@ -774,7 +777,7 @@
     ALOGV("Verify creating a surface w/ right config + dummy writer*********");
 
     mSMS = new SurfaceMediaSource(mYuvTexWidth, mYuvTexHeight);
-    mSTC = new SurfaceTextureClient(static_cast<sp<ISurfaceTexture> >( mSMS));
+    mSTC = new SurfaceTextureClient(static_cast<sp<ISurfaceTexture> >( mSMS->getBufferQueue()));
     mANW = mSTC;
 
     DummyRecorder writer(mSMS);