[Spice-devel] [RFC PATCH spice-server v3 08/20] stream-device: Handle streaming data from device to channel

Frediano Ziglio fziglio at redhat.com
Fri Aug 25 09:32:50 UTC 2017


> 
> On Wed, 2017-08-23 at 10:14 +0100, Frediano Ziglio wrote:
> > 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.
> 
> This last sentence is a bit unclear. Perhaps
> 
> "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 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;
> > +}
> 
> How about a name like:
> 
> shared_pipe_item_ref()
> pipe_item_new_shared()
> 
> ?
> 

I liked the suggestion to add a function to RedChannel.
Too many red_channel_add_whatever :-)

> 
> > +
> > +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) {
> 
> print a warning here? Seems like sending stream data without creating a
> stream is potentially a signal that something went wrong.
> 

I put a comment now.
This is not really an error, can happen if we send a stop but
the guest didn't handle it or was still sending data.

> > +        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) {
> 
> 
> Acked-by: Jonathon Jongsma <jjongsma at redhat.com>
> 
> 
Frediano


More information about the Spice-devel mailing list