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@xxxxxxxxxx> --- 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 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/spice-devel