[Spice-devel] [RFC PATCH 10/16] stream-device: Handle streaming data from device to channel

Frediano Ziglio fziglio at redhat.com
Wed Jan 25 12:42:33 UTC 2017


Handle stream data from device sending to the channel.
Channel will forward to clients as proper DisplayChannel
messaging creating and destroying the channel stream as
needed.

Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
---
 server/stream-channel.c | 105 +++++++++++++++++++++++++++++++++++++++++-
 server/stream-channel.h |   6 ++-
 server/stream-device.c  |   4 +-
 3 files changed, 113 insertions(+), 2 deletions(-)

diff --git a/server/stream-channel.c b/server/stream-channel.c
index 79beb4d..be119f8 100644
--- a/server/stream-channel.c
+++ b/server/stream-channel.c
@@ -20,6 +20,7 @@
 #endif
 
 #include <common/generated_server_marshallers.h>
+#include <spice/stream-device.h>
 
 #include "red-channel-client.h"
 #include "stream-channel.h"
@@ -44,6 +45,8 @@ typedef struct StreamChannelClientClass StreamChannelClientClass;
 
 struct StreamChannelClient {
     RedChannelClient parent;
+
+    int stream_id;
 };
 
 struct StreamChannelClientClass {
@@ -56,6 +59,8 @@ G_DEFINE_TYPE(StreamChannelClient, stream_channel_client, RED_TYPE_CHANNEL_CLIEN
 
 struct StreamChannel {
     CommonGraphicsChannel parent;
+
+    int stream_id;
 };
 
 struct StreamChannelClass {
@@ -67,8 +72,22 @@ G_DEFINE_TYPE(StreamChannel, stream_channel, TYPE_COMMON_GRAPHICS_CHANNEL)
 enum {
     RED_PIPE_ITEM_TYPE_SURFACE_CREATE = RED_PIPE_ITEM_TYPE_COMMON_LAST,
     RED_PIPE_ITEM_TYPE_FILL_SURFACE,
+    RED_PIPE_ITEM_TYPE_STREAM_CREATE,
+    RED_PIPE_ITEM_TYPE_STREAM_DATA,
+    RED_PIPE_ITEM_TYPE_STREAM_DESTROY,
 };
 
+typedef struct StreamCreateItem {
+    RedPipeItem base;
+    SpiceMsgDisplayStreamCreate stream_create;
+} StreamCreateItem;
+
+typedef struct StreamDataItem {
+    RedPipeItem base;
+    // NOTE: this must be the last field in the structure
+    SpiceMsgDisplayStreamData data;
+} StreamDataItem;
+
 static void
 stream_channel_client_class_init(StreamChannelClientClass *klass)
 {
@@ -77,6 +96,7 @@ stream_channel_client_class_init(StreamChannelClientClass *klass)
 static void
 stream_channel_client_init(StreamChannelClient *client)
 {
+    client->stream_id = -1;
 }
 
 static void
@@ -139,6 +159,7 @@ static void
 stream_channel_send_item(RedChannelClient *rcc, RedPipeItem *pipe_item)
 {
     SpiceMarshaller *m = red_channel_client_get_marshaller(rcc);
+    StreamChannelClient *client = STREAM_CHANNEL_CLIENT(rcc);
 
     switch (pipe_item->type) {
     case RED_PIPE_ITEM_TYPE_SURFACE_CREATE: {
@@ -160,6 +181,32 @@ stream_channel_send_item(RedChannelClient *rcc, RedPipeItem *pipe_item)
         spice_marshall_Fill(m, &fill, &brush_pat_out, &mask_bitmap_out);
         break;
     }
+    case RED_PIPE_ITEM_TYPE_STREAM_CREATE: {
+        StreamCreateItem *item = SPICE_UPCAST(StreamCreateItem, pipe_item);
+        client->stream_id = item->stream_create.id;
+        red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_STREAM_CREATE);
+        spice_marshall_msg_display_stream_create(m, &item->stream_create);
+        break;
+    }
+    case RED_PIPE_ITEM_TYPE_STREAM_DATA: {
+        StreamDataItem *item = SPICE_UPCAST(StreamDataItem, pipe_item);
+        red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_STREAM_DATA);
+        spice_marshall_msg_display_stream_data(m, &item->data);
+        red_pipe_item_ref(pipe_item);
+        spice_marshaller_add_by_ref_full(m, item->data.data, item->data.data_size,
+                                         marshaller_unref_pipe_item, pipe_item);
+        break;
+    }
+    case RED_PIPE_ITEM_TYPE_STREAM_DESTROY: {
+        if (client->stream_id < 0) {
+            return;
+        }
+        SpiceMsgDisplayStreamDestroy stream_destroy = { client->stream_id };
+        red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_STREAM_DESTROY);
+        spice_marshall_msg_display_stream_destroy(m, &stream_destroy);
+        client->stream_id = -1;
+        break;
+    }
     default:
         spice_error("invalid pipe item type");
     }
@@ -273,4 +320,62 @@ stream_channel_class_init(StreamChannelClass *klass)
 static void
 stream_channel_init(StreamChannel *channel)
 {
+    channel->stream_id = -1;
+}
+
+static RedPipeItem *
+pipe_item_new_ref(G_GNUC_UNUSED RedChannelClient *rcc, void *data, G_GNUC_UNUSED int num)
+{
+    RedPipeItem *item = data;
+    red_pipe_item_ref(item);
+    return item;
+}
+
+void
+stream_channel_change_format(StreamChannel *channel, const struct StreamMsgStreamFormat *fmt)
+{
+    RedChannel *red_channel = RED_CHANNEL(channel);
+
+    // send destroy old stream
+    red_channel_pipes_add_type(red_channel, RED_PIPE_ITEM_TYPE_STREAM_DESTROY);
+
+    // TODO send new create surface if required
+
+    // allocate a new stream id
+    channel->stream_id = (channel->stream_id + 1) % 40;
+
+    // send create stream
+    StreamCreateItem *item = spice_new0(StreamCreateItem, 1);
+    red_pipe_item_init(&item->base, RED_PIPE_ITEM_TYPE_STREAM_CREATE);
+    item->stream_create.id = channel->stream_id;
+    item->stream_create.flags = SPICE_STREAM_FLAGS_TOP_DOWN;
+    item->stream_create.codec_type = fmt->codec;
+    item->stream_create.stream_width = fmt->width;
+    item->stream_create.stream_height = fmt->height;
+    item->stream_create.src_width = fmt->width;
+    item->stream_create.src_height = fmt->height;
+    item->stream_create.dest = (SpiceRect) { 0, 0, fmt->width, fmt->height };
+    item->stream_create.clip = (SpiceClip) { SPICE_CLIP_TYPE_NONE, NULL };
+    red_channel_pipes_new_add(red_channel, pipe_item_new_ref, item);
+    red_pipe_item_unref(&item->base);
+}
+
+void
+stream_channel_send_data(StreamChannel *channel, const void *data, size_t size)
+{
+    if (channel->stream_id < 0) {
+        return;
+    }
+
+    RedChannel *red_channel = RED_CHANNEL(channel);
+
+    StreamDataItem *item = spice_malloc(sizeof(*item) + size);
+    red_pipe_item_init(&item->base, RED_PIPE_ITEM_TYPE_STREAM_DATA);
+    item->data.base.id = channel->stream_id;
+    item->data.base.multi_media_time = reds_get_mm_time();
+    item->data.data_size = size;
+    // TODO try to optimize avoiding the copy
+    memcpy(item->data.data, data, size);
+    red_channel_pipes_new_add(red_channel, pipe_item_new_ref, item);
+    red_pipe_item_unref(&item->base);
 }
diff --git a/server/stream-channel.h b/server/stream-channel.h
index 7390383..bb66ac6 100644
--- a/server/stream-channel.h
+++ b/server/stream-channel.h
@@ -47,6 +47,12 @@ GType stream_channel_get_type(void) G_GNUC_CONST;
  */
 StreamChannel* stream_channel_new(RedsState *server);
 
+struct StreamMsgStreamFormat;
+
+void stream_channel_change_format(StreamChannel *channel,
+                                  const struct StreamMsgStreamFormat *fmt);
+void stream_channel_send_data(StreamChannel *channel, const void *data, size_t size);
+
 G_END_DECLS
 
 #endif /* STREAM_CHANNEL_H_ */
diff --git a/server/stream-device.c b/server/stream-device.c
index 35ba3f0..da71880 100644
--- a/server/stream-device.c
+++ b/server/stream-device.c
@@ -122,6 +122,7 @@ handle_msg_format(StreamDevice *dev, SpiceCharDeviceInstance *sin)
     spice_assert(n == sizeof(fmt));
     fmt.width = GUINT32_FROM_LE(fmt.width);
     fmt.height = GUINT32_FROM_LE(fmt.height);
+    stream_channel_change_format(dev->channel, &fmt);
     dev->hdr_pos = 0;
 }
 
@@ -133,11 +134,10 @@ handle_msg_data(StreamDevice *dev, SpiceCharDeviceInstance *sin)
     do {
         uint8_t buf[16 * 1024];
         n = sif->read(sin, buf, sizeof(buf));
-        /* FIXME */
-        printf("readed %d bytes from device\n", n);
         if (n <= 0) {
             break;
         }
+        stream_channel_send_data(dev->channel, buf, n);
         dev->hdr.size -= n;
     } while (n > 0);
     if (dev->hdr.size == 0) {
-- 
git-series 0.9.1


More information about the Spice-devel mailing list