|
|
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 |
|