Add sideband streams to BufferQueue and related classes

Sideband streams are essentially a device-specific buffer queue that
bypasses the BufferQueue system. They can be used for situations with
hard real-time requirements like high-quality TV and video playback
with A/V sync. A handle to the stream is provided by the source HAL,
and attached to a BufferQueue. The sink HAL can read buffers via the
stream handle rather than acquiring individual buffers from the
BufferQueue.

Change-Id: Ib3f262eddfc520f4bbe3d9b91753ed7dd09d3a9b
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index af857fd..8584dc9 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -93,6 +93,10 @@
     return mProducer->disconnect(api);
 }
 
+status_t BufferQueue::setSidebandStream(const sp<NativeHandle>& stream) {
+    return mProducer->setSidebandStream(stream);
+}
+
 status_t BufferQueue::acquireBuffer(BufferItem* buffer, nsecs_t presentWhen) {
     return mConsumer->acquireBuffer(buffer, presentWhen);
 }
@@ -148,8 +152,19 @@
     return mConsumer->setTransformHint(hint);
 }
 
+sp<NativeHandle> BufferQueue::getSidebandStream() const {
+    return mConsumer->getSidebandStream();
+}
+
 void BufferQueue::dump(String8& result, const char* prefix) const {
     mConsumer->dump(result, prefix);
 }
 
+void BufferQueue::ProxyConsumerListener::onSidebandStreamChanged() {
+    sp<ConsumerListener> listener(mConsumerListener.promote());
+    if (listener != NULL) {
+        listener->onSidebandStreamChanged();
+    }
+}
+
 }; // namespace android
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index dc7aa15..e34f716 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -395,6 +395,10 @@
     return NO_ERROR;
 }
 
+sp<NativeHandle> BufferQueueConsumer::getSidebandStream() const {
+    return mCore->mSidebandStream;
+}
+
 void BufferQueueConsumer::dump(String8& result, const char* prefix) const {
     mCore->dump(result, prefix);
 }
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 0e9de88..0ff7b80 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -674,6 +674,7 @@
                     }
                     mCore->mConnectedProducerToken = NULL;
                     mCore->mConnectedApi = BufferQueueCore::NO_CONNECTED_API;
+                    mCore->mSidebandStream.clear();
                     mCore->mDequeueCondition.broadcast();
                     listener = mCore->mConsumerListener;
                 } else {
@@ -697,6 +698,12 @@
     return status;
 }
 
+status_t BufferQueueProducer::setSidebandStream(const sp<NativeHandle>& stream) {
+    Mutex::Autolock _l(mCore->mMutex);
+    mCore->mSidebandStream = stream;
+    return NO_ERROR;
+}
+
 void BufferQueueProducer::binderDied(const wp<android::IBinder>& /* who */) {
     // If we're here, it means that a producer we were connected to died.
     // We're guaranteed that we are still connected to it because we remove
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index c5900aa..b6adc54 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -130,6 +130,9 @@
     }
 }
 
+void ConsumerBase::onSidebandStreamChanged() {
+}
+
 void ConsumerBase::abandon() {
     CB_LOGV("abandon");
     Mutex::Autolock lock(mMutex);
diff --git a/libs/gui/IConsumerListener.cpp b/libs/gui/IConsumerListener.cpp
index 5304462..4ccf0ac 100644
--- a/libs/gui/IConsumerListener.cpp
+++ b/libs/gui/IConsumerListener.cpp
@@ -28,7 +28,8 @@
 
 enum {
     ON_FRAME_AVAILABLE = IBinder::FIRST_CALL_TRANSACTION,
-    ON_BUFFER_RELEASED
+    ON_BUFFER_RELEASED,
+    ON_SIDEBAND_STREAM_CHANGED,
 };
 
 class BpConsumerListener : public BpInterface<IConsumerListener>
@@ -49,6 +50,12 @@
         data.writeInterfaceToken(IConsumerListener::getInterfaceDescriptor());
         remote()->transact(ON_BUFFER_RELEASED, data, &reply, IBinder::FLAG_ONEWAY);
     }
+
+    virtual void onSidebandStreamChanged() {
+        Parcel data, reply;
+        data.writeInterfaceToken(IConsumerListener::getInterfaceDescriptor());
+        remote()->transact(ON_SIDEBAND_STREAM_CHANGED, data, &reply, IBinder::FLAG_ONEWAY);
+    }
 };
 
 IMPLEMENT_META_INTERFACE(ConsumerListener, "android.gui.IConsumerListener");
@@ -67,6 +74,10 @@
             CHECK_INTERFACE(IConsumerListener, data, reply);
             onBuffersReleased();
             return NO_ERROR;
+        case ON_SIDEBAND_STREAM_CHANGED:
+            CHECK_INTERFACE(IConsumerListener, data, reply);
+            onSidebandStreamChanged();
+            return NO_ERROR;
     }
     return BBinder::onTransact(code, data, reply, flags);
 }
diff --git a/libs/gui/IGraphicBufferConsumer.cpp b/libs/gui/IGraphicBufferConsumer.cpp
index 876c895..c97d15b 100644
--- a/libs/gui/IGraphicBufferConsumer.cpp
+++ b/libs/gui/IGraphicBufferConsumer.cpp
@@ -24,6 +24,7 @@
 #include <sys/types.h>
 
 #include <utils/Errors.h>
+#include <utils/NativeHandle.h>
 
 #include <binder/Parcel.h>
 #include <binder/IInterface.h>
@@ -195,6 +196,7 @@
     SET_DEFAULT_BUFFER_FORMAT,
     SET_CONSUMER_USAGE_BITS,
     SET_TRANSFORM_HINT,
+    GET_SIDEBAND_STREAM,
     DUMP,
 };
 
@@ -354,6 +356,20 @@
         return reply.readInt32();
     }
 
+    virtual sp<NativeHandle> getSidebandStream() const {
+        Parcel data, reply;
+        status_t err;
+        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
+        if ((err = remote()->transact(GET_SIDEBAND_STREAM, data, &reply)) != NO_ERROR) {
+            return NULL;
+        }
+        sp<NativeHandle> stream;
+        if (reply.readInt32()) {
+            stream = NativeHandle::create(reply.readNativeHandle());
+        }
+        return stream;
+    }
+
     virtual void dump(String8& result, const char* prefix) const {
         Parcel data, reply;
         data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 0f461e5..efbe878 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -18,9 +18,10 @@
 #include <sys/types.h>
 
 #include <utils/Errors.h>
+#include <utils/NativeHandle.h>
 #include <utils/RefBase.h>
-#include <utils/Vector.h>
 #include <utils/Timers.h>
+#include <utils/Vector.h>
 
 #include <binder/Parcel.h>
 #include <binder/IInterface.h>
@@ -39,6 +40,7 @@
     QUERY,
     CONNECT,
     DISCONNECT,
+    SET_SIDEBAND_STREAM,
 };
 
 class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer>
@@ -169,6 +171,22 @@
         result = reply.readInt32();
         return result;
     }
+
+    virtual status_t setSidebandStream(const sp<NativeHandle>& stream) {
+        Parcel data, reply;
+        status_t result;
+        data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
+        if (stream.get()) {
+            data.writeInt32(true);
+            data.writeNativeHandle(stream->handle());
+        } else {
+            data.writeInt32(false);
+        }
+        if ((result = remote()->transact(SET_SIDEBAND_STREAM, data, &reply)) == NO_ERROR) {
+            result = reply.readInt32();
+        }
+        return result;
+    }
 };
 
 IMPLEMENT_META_INTERFACE(GraphicBufferProducer, "android.gui.IGraphicBufferProducer");
@@ -263,6 +281,16 @@
             reply->writeInt32(res);
             return NO_ERROR;
         } break;
+        case SET_SIDEBAND_STREAM: {
+            CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
+            sp<NativeHandle> stream;
+            if (data.readInt32()) {
+                stream = NativeHandle::create(data.readNativeHandle());
+            }
+            status_t result = setSidebandStream(stream);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
     }
     return BBinder::onTransact(code, data, reply, flags);
 }