mirror of
https://gitlab.uni-freiburg.de/opensourcevdi/spice
synced 2026-01-04 00:06:29 +00:00
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>
This commit is contained in:
parent
09ddeff804
commit
60104d818c
@ -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);
|
||||
}
|
||||
|
||||
@ -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_ */
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user