Blame SOURCES/0011-stream-device-Handle-streaming-data-from-device-to-c.patch

ad1357
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
ad1357
From: Frediano Ziglio <fziglio@redhat.com>
ad1357
Date: Sat, 21 Jan 2017 10:47:40 +0000
ad1357
Subject: [spice-server] stream-device: Handle streaming data from device to
ad1357
 channel
ad1357
ad1357
Handle stream data from device sending to the channel.
ad1357
The StreamChannel will forward the data to the clients using standard
ad1357
DisplayChannel messages, and will create and destroy streams as
ad1357
necessary.
ad1357
ad1357
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
ad1357
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
ad1357
---
ad1357
 server/stream-channel.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++++
ad1357
 server/stream-channel.h |   8 ++++
ad1357
 server/stream-device.c  |   4 +-
ad1357
 3 files changed, 113 insertions(+), 2 deletions(-)
ad1357
ad1357
diff --git a/server/stream-channel.c b/server/stream-channel.c
ad1357
index baf3d58a6..8931d8794 100644
ad1357
--- a/server/stream-channel.c
ad1357
+++ b/server/stream-channel.c
ad1357
@@ -20,11 +20,13 @@
ad1357
 #endif
ad1357
 
ad1357
 #include <common/generated_server_marshallers.h>
ad1357
+#include <spice/stream-device.h>
ad1357
 
ad1357
 #include "red-channel-client.h"
ad1357
 #include "stream-channel.h"
ad1357
 #include "reds.h"
ad1357
 #include "common-graphics-channel.h"
ad1357
+#include "display-limits.h"
ad1357
 
ad1357
 #define TYPE_STREAM_CHANNEL_CLIENT stream_channel_client_get_type()
ad1357
 
ad1357
@@ -46,6 +48,10 @@ typedef struct StreamChannelClientClass StreamChannelClientClass;
ad1357
  * to get buffer handling */
ad1357
 struct StreamChannelClient {
ad1357
     CommonGraphicsChannelClient parent;
ad1357
+
ad1357
+    /* current video stream id, <0 if not initialized or
ad1357
+     * we are not sending a stream */
ad1357
+    int stream_id;
ad1357
 };
ad1357
 
ad1357
 struct StreamChannelClientClass {
ad1357
@@ -58,6 +64,10 @@ G_DEFINE_TYPE(StreamChannelClient, stream_channel_client, TYPE_COMMON_GRAPHICS_C
ad1357
 
ad1357
 struct StreamChannel {
ad1357
     RedChannel parent;
ad1357
+
ad1357
+    /* current video stream id, <0 if not initialized or
ad1357
+     * we are not sending a stream */
ad1357
+    int stream_id;
ad1357
 };
ad1357
 
ad1357
 struct StreamChannelClass {
ad1357
@@ -69,8 +79,22 @@ G_DEFINE_TYPE(StreamChannel, stream_channel, RED_TYPE_CHANNEL)
ad1357
 enum {
ad1357
     RED_PIPE_ITEM_TYPE_SURFACE_CREATE = RED_PIPE_ITEM_TYPE_COMMON_LAST,
ad1357
     RED_PIPE_ITEM_TYPE_FILL_SURFACE,
ad1357
+    RED_PIPE_ITEM_TYPE_STREAM_CREATE,
ad1357
+    RED_PIPE_ITEM_TYPE_STREAM_DATA,
ad1357
+    RED_PIPE_ITEM_TYPE_STREAM_DESTROY,
ad1357
 };
ad1357
 
ad1357
+typedef struct StreamCreateItem {
ad1357
+    RedPipeItem base;
ad1357
+    SpiceMsgDisplayStreamCreate stream_create;
ad1357
+} StreamCreateItem;
ad1357
+
ad1357
+typedef struct StreamDataItem {
ad1357
+    RedPipeItem base;
ad1357
+    // NOTE: this must be the last field in the structure
ad1357
+    SpiceMsgDisplayStreamData data;
ad1357
+} StreamDataItem;
ad1357
+
ad1357
 #define PRIMARY_SURFACE_ID 0
ad1357
 
ad1357
 static void stream_channel_client_on_disconnect(RedChannelClient *rcc);
ad1357
@@ -86,6 +110,7 @@ stream_channel_client_class_init(StreamChannelClientClass *klass)
ad1357
 static void
ad1357
 stream_channel_client_init(StreamChannelClient *client)
ad1357
 {
ad1357
+    client->stream_id = -1;
ad1357
 }
ad1357
 
ad1357
 static void
ad1357
@@ -127,6 +152,7 @@ static void
ad1357
 stream_channel_send_item(RedChannelClient *rcc, RedPipeItem *pipe_item)
ad1357
 {
ad1357
     SpiceMarshaller *m = red_channel_client_get_marshaller(rcc);
ad1357
+    StreamChannelClient *client = STREAM_CHANNEL_CLIENT(rcc);
ad1357
 
ad1357
     switch (pipe_item->type) {
ad1357
     case RED_PIPE_ITEM_TYPE_SURFACE_CREATE: {
ad1357
@@ -152,6 +178,32 @@ stream_channel_send_item(RedChannelClient *rcc, RedPipeItem *pipe_item)
ad1357
         spice_marshall_Fill(m, &fill, &brush_pat_out, &mask_bitmap_out);
ad1357
         break;
ad1357
     }
ad1357
+    case RED_PIPE_ITEM_TYPE_STREAM_CREATE: {
ad1357
+        StreamCreateItem *item = SPICE_UPCAST(StreamCreateItem, pipe_item);
ad1357
+        client->stream_id = item->stream_create.id;
ad1357
+        red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_STREAM_CREATE);
ad1357
+        spice_marshall_msg_display_stream_create(m, &item->stream_create);
ad1357
+        break;
ad1357
+    }
ad1357
+    case RED_PIPE_ITEM_TYPE_STREAM_DATA: {
ad1357
+        StreamDataItem *item = SPICE_UPCAST(StreamDataItem, pipe_item);
ad1357
+        red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_STREAM_DATA);
ad1357
+        spice_marshall_msg_display_stream_data(m, &item->data);
ad1357
+        red_pipe_item_ref(pipe_item);
ad1357
+        spice_marshaller_add_by_ref_full(m, item->data.data, item->data.data_size,
ad1357
+                                         marshaller_unref_pipe_item, pipe_item);
ad1357
+        break;
ad1357
+    }
ad1357
+    case RED_PIPE_ITEM_TYPE_STREAM_DESTROY: {
ad1357
+        if (client->stream_id < 0) {
ad1357
+            return;
ad1357
+        }
ad1357
+        SpiceMsgDisplayStreamDestroy stream_destroy = { client->stream_id };
ad1357
+        red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_STREAM_DESTROY);
ad1357
+        spice_marshall_msg_display_stream_destroy(m, &stream_destroy);
ad1357
+        client->stream_id = -1;
ad1357
+        break;
ad1357
+    }
ad1357
     default:
ad1357
         spice_error("invalid pipe item type");
ad1357
     }
ad1357
@@ -259,4 +311,55 @@ stream_channel_class_init(StreamChannelClass *klass)
ad1357
 static void
ad1357
 stream_channel_init(StreamChannel *channel)
ad1357
 {
ad1357
+    channel->stream_id = -1;
ad1357
+}
ad1357
+
ad1357
+void
ad1357
+stream_channel_change_format(StreamChannel *channel, const StreamMsgFormat *fmt)
ad1357
+{
ad1357
+    RedChannel *red_channel = RED_CHANNEL(channel);
ad1357
+
ad1357
+    // send destroy old stream
ad1357
+    red_channel_pipes_add_type(red_channel, RED_PIPE_ITEM_TYPE_STREAM_DESTROY);
ad1357
+
ad1357
+    // TODO send new create surface if required
ad1357
+
ad1357
+    // allocate a new stream id
ad1357
+    channel->stream_id = (channel->stream_id + 1) % NUM_STREAMS;
ad1357
+
ad1357
+    // send create stream
ad1357
+    StreamCreateItem *item = g_new0(StreamCreateItem, 1);
ad1357
+    red_pipe_item_init(&item->base, RED_PIPE_ITEM_TYPE_STREAM_CREATE);
ad1357
+    item->stream_create.id = channel->stream_id;
ad1357
+    item->stream_create.flags = SPICE_STREAM_FLAGS_TOP_DOWN;
ad1357
+    item->stream_create.codec_type = fmt->codec;
ad1357
+    item->stream_create.stream_width = fmt->width;
ad1357
+    item->stream_create.stream_height = fmt->height;
ad1357
+    item->stream_create.src_width = fmt->width;
ad1357
+    item->stream_create.src_height = fmt->height;
ad1357
+    item->stream_create.dest = (SpiceRect) { 0, 0, fmt->width, fmt->height };
ad1357
+    item->stream_create.clip = (SpiceClip) { SPICE_CLIP_TYPE_NONE, NULL };
ad1357
+    red_channel_pipes_add(red_channel, &item->base);
ad1357
+}
ad1357
+
ad1357
+void
ad1357
+stream_channel_send_data(StreamChannel *channel, const void *data, size_t size, uint32_t mm_time)
ad1357
+{
ad1357
+    if (channel->stream_id < 0) {
ad1357
+        // this condition can happen if the guest didn't handle
ad1357
+        // the format stop that we send so think the stream is still
ad1357
+        // started
ad1357
+        return;
ad1357
+    }
ad1357
+
ad1357
+    RedChannel *red_channel = RED_CHANNEL(channel);
ad1357
+
ad1357
+    StreamDataItem *item = g_malloc(sizeof(*item) + size);
ad1357
+    red_pipe_item_init(&item->base, RED_PIPE_ITEM_TYPE_STREAM_DATA);
ad1357
+    item->data.base.id = channel->stream_id;
ad1357
+    item->data.base.multi_media_time = mm_time;
ad1357
+    item->data.data_size = size;
ad1357
+    // TODO try to optimize avoiding the copy
ad1357
+    memcpy(item->data.data, data, size);
ad1357
+    red_channel_pipes_add(red_channel, &item->base);
ad1357
 }
ad1357
diff --git a/server/stream-channel.h b/server/stream-channel.h
ad1357
index e50e17e9e..156a75d31 100644
ad1357
--- a/server/stream-channel.h
ad1357
+++ b/server/stream-channel.h
ad1357
@@ -48,6 +48,14 @@ GType stream_channel_get_type(void) G_GNUC_CONST;
ad1357
  */
ad1357
 StreamChannel* stream_channel_new(RedsState *server, uint32_t id);
ad1357
 
ad1357
+struct StreamMsgFormat;
ad1357
+
ad1357
+void stream_channel_change_format(StreamChannel *channel,
ad1357
+                                  const struct StreamMsgFormat *fmt);
ad1357
+void stream_channel_send_data(StreamChannel *channel,
ad1357
+                              const void *data, size_t size,
ad1357
+                              uint32_t mm_time);
ad1357
+
ad1357
 G_END_DECLS
ad1357
 
ad1357
 #endif /* STREAM_CHANNEL_H_ */
ad1357
diff --git a/server/stream-device.c b/server/stream-device.c
ad1357
index 0c9173ae0..6e78b1a99 100644
ad1357
--- a/server/stream-device.c
ad1357
+++ b/server/stream-device.c
ad1357
@@ -164,6 +164,7 @@ handle_msg_format(StreamDevice *dev, SpiceCharDeviceInstance *sin)
ad1357
     }
ad1357
     fmt.width = GUINT32_FROM_LE(fmt.width);
ad1357
     fmt.height = GUINT32_FROM_LE(fmt.height);
ad1357
+    stream_channel_change_format(dev->stream_channel, &fmt);
ad1357
 
ad1357
     return true;
ad1357
 }
ad1357
@@ -176,11 +177,10 @@ handle_msg_data(StreamDevice *dev, SpiceCharDeviceInstance *sin)
ad1357
     while (1) {
ad1357
         uint8_t buf[16 * 1024];
ad1357
         n = sif->read(sin, buf, sizeof(buf));
ad1357
-        /* TODO */
ad1357
-        spice_debug("read %d bytes from device", n);
ad1357
         if (n <= 0) {
ad1357
             break;
ad1357
         }
ad1357
+        stream_channel_send_data(dev->stream_channel, buf, n, reds_get_mm_time());
ad1357
         dev->hdr.size -= n;
ad1357
     }
ad1357