You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
231 lines
8.1 KiB
231 lines
8.1 KiB
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 |
|
From: Frediano Ziglio <fziglio@redhat.com> |
|
Date: Sat, 21 Jan 2017 10:47:40 +0000 |
|
Subject: [spice-server] stream-device: Handle streaming data from device to |
|
channel |
|
|
|
Handle stream data from device sending to the channel. |
|
The StreamChannel will forward the data to the clients using standard |
|
DisplayChannel messages, and will create and destroy streams as |
|
necessary. |
|
|
|
Signed-off-by: Frediano Ziglio <fziglio@redhat.com> |
|
Acked-by: Jonathon Jongsma <jjongsma@redhat.com> |
|
--- |
|
server/stream-channel.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++++ |
|
server/stream-channel.h | 8 ++++ |
|
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 baf3d58a6..8931d8794 100644 |
|
--- a/server/stream-channel.c |
|
+++ b/server/stream-channel.c |
|
@@ -20,11 +20,13 @@ |
|
#endif |
|
|
|
#include <common/generated_server_marshallers.h> |
|
+#include <spice/stream-device.h> |
|
|
|
#include "red-channel-client.h" |
|
#include "stream-channel.h" |
|
#include "reds.h" |
|
#include "common-graphics-channel.h" |
|
+#include "display-limits.h" |
|
|
|
#define TYPE_STREAM_CHANNEL_CLIENT stream_channel_client_get_type() |
|
|
|
@@ -46,6 +48,10 @@ typedef struct StreamChannelClientClass StreamChannelClientClass; |
|
* to get buffer handling */ |
|
struct StreamChannelClient { |
|
CommonGraphicsChannelClient parent; |
|
+ |
|
+ /* current video stream id, <0 if not initialized or |
|
+ * we are not sending a stream */ |
|
+ int stream_id; |
|
}; |
|
|
|
struct StreamChannelClientClass { |
|
@@ -58,6 +64,10 @@ G_DEFINE_TYPE(StreamChannelClient, stream_channel_client, TYPE_COMMON_GRAPHICS_C |
|
|
|
struct StreamChannel { |
|
RedChannel parent; |
|
+ |
|
+ /* current video stream id, <0 if not initialized or |
|
+ * we are not sending a stream */ |
|
+ int stream_id; |
|
}; |
|
|
|
struct StreamChannelClass { |
|
@@ -69,8 +79,22 @@ G_DEFINE_TYPE(StreamChannel, stream_channel, RED_TYPE_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; |
|
+ |
|
#define PRIMARY_SURFACE_ID 0 |
|
|
|
static void stream_channel_client_on_disconnect(RedChannelClient *rcc); |
|
@@ -86,6 +110,7 @@ stream_channel_client_class_init(StreamChannelClientClass *klass) |
|
static void |
|
stream_channel_client_init(StreamChannelClient *client) |
|
{ |
|
+ client->stream_id = -1; |
|
} |
|
|
|
static void |
|
@@ -127,6 +152,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: { |
|
@@ -152,6 +178,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"); |
|
} |
|
@@ -259,4 +311,55 @@ stream_channel_class_init(StreamChannelClass *klass) |
|
static void |
|
stream_channel_init(StreamChannel *channel) |
|
{ |
|
+ channel->stream_id = -1; |
|
+} |
|
+ |
|
+void |
|
+stream_channel_change_format(StreamChannel *channel, const StreamMsgFormat *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) % NUM_STREAMS; |
|
+ |
|
+ // send create stream |
|
+ StreamCreateItem *item = g_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_add(red_channel, &item->base); |
|
+} |
|
+ |
|
+void |
|
+stream_channel_send_data(StreamChannel *channel, const void *data, size_t size, uint32_t mm_time) |
|
+{ |
|
+ if (channel->stream_id < 0) { |
|
+ // this condition can happen if the guest didn't handle |
|
+ // the format stop that we send so think the stream is still |
|
+ // started |
|
+ return; |
|
+ } |
|
+ |
|
+ RedChannel *red_channel = RED_CHANNEL(channel); |
|
+ |
|
+ StreamDataItem *item = g_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 = mm_time; |
|
+ item->data.data_size = size; |
|
+ // TODO try to optimize avoiding the copy |
|
+ memcpy(item->data.data, data, size); |
|
+ red_channel_pipes_add(red_channel, &item->base); |
|
} |
|
diff --git a/server/stream-channel.h b/server/stream-channel.h |
|
index e50e17e9e..156a75d31 100644 |
|
--- a/server/stream-channel.h |
|
+++ b/server/stream-channel.h |
|
@@ -48,6 +48,14 @@ GType stream_channel_get_type(void) G_GNUC_CONST; |
|
*/ |
|
StreamChannel* stream_channel_new(RedsState *server, uint32_t id); |
|
|
|
+struct StreamMsgFormat; |
|
+ |
|
+void stream_channel_change_format(StreamChannel *channel, |
|
+ const struct StreamMsgFormat *fmt); |
|
+void stream_channel_send_data(StreamChannel *channel, |
|
+ const void *data, size_t size, |
|
+ uint32_t mm_time); |
|
+ |
|
G_END_DECLS |
|
|
|
#endif /* STREAM_CHANNEL_H_ */ |
|
diff --git a/server/stream-device.c b/server/stream-device.c |
|
index 0c9173ae0..6e78b1a99 100644 |
|
--- a/server/stream-device.c |
|
+++ b/server/stream-device.c |
|
@@ -164,6 +164,7 @@ handle_msg_format(StreamDevice *dev, SpiceCharDeviceInstance *sin) |
|
} |
|
fmt.width = GUINT32_FROM_LE(fmt.width); |
|
fmt.height = GUINT32_FROM_LE(fmt.height); |
|
+ stream_channel_change_format(dev->stream_channel, &fmt); |
|
|
|
return true; |
|
} |
|
@@ -176,11 +177,10 @@ handle_msg_data(StreamDevice *dev, SpiceCharDeviceInstance *sin) |
|
while (1) { |
|
uint8_t buf[16 * 1024]; |
|
n = sif->read(sin, buf, sizeof(buf)); |
|
- /* TODO */ |
|
- spice_debug("read %d bytes from device", n); |
|
if (n <= 0) { |
|
break; |
|
} |
|
+ stream_channel_send_data(dev->stream_channel, buf, n, reds_get_mm_time()); |
|
dev->hdr.size -= n; |
|
} |
|
|
|
|