[Spice-devel] [RFC PATCH spice-server v3 08/20] stream-device: Handle streaming data from device to channel
Frediano Ziglio
fziglio at redhat.com
Wed Aug 23 09:14:26 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 | 108 ++++++++++++++++++++++++++++++++++++++++++++++++
server/stream-channel.h | 8 ++++
server/stream-device.c | 4 +-
3 files changed, 118 insertions(+), 2 deletions(-)
diff --git a/server/stream-channel.c b/server/stream-channel.c
index c57f7e89..4ab378a8 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,8 @@ typedef struct StreamChannelClientClass StreamChannelClientClass;
* to get buffer handling */
struct StreamChannelClient {
CommonGraphicsChannelClient parent;
+
+ int stream_id;
};
struct StreamChannelClientClass {
@@ -58,6 +62,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 +77,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
@@ -81,6 +103,7 @@ stream_channel_client_class_init(StreamChannelClientClass *klass)
static void
stream_channel_client_init(StreamChannelClient *client)
{
+ client->stream_id = -1;
}
static void
@@ -122,6 +145,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: {
@@ -147,6 +171,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");
}
@@ -255,4 +305,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 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 = 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, uint32_t mm_time)
+{
+ 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 = 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 5691008c..6257f806 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);
+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 026f79c7..c1dd02d4 100644
--- a/server/stream-device.c
+++ b/server/stream-device.c
@@ -149,6 +149,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->channel, &fmt);
dev->hdr_pos = 0;
}
@@ -160,11 +161,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("readed %d bytes from device", n);
if (n <= 0) {
break;
}
+ stream_channel_send_data(dev->channel, buf, n, reds_get_mm_time());
dev->hdr.size -= n;
}
if (dev->hdr.size == 0) {
--
2.13.5
More information about the Spice-devel
mailing list