|
|
ad1357 |
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
|
ad1357 |
From: Frediano Ziglio <fziglio@redhat.com>
|
|
|
ad1357 |
Date: Sat, 21 Jan 2017 19:03:19 +0000
|
|
|
ad1357 |
Subject: [spice-server] stream-channel: Support client
|
|
|
ad1357 |
connection/disconnection
|
|
|
ad1357 |
|
|
|
ad1357 |
When a new client is connected we must restart the stream so new
|
|
|
ad1357 |
clients can receive correct data without having to wait for the
|
|
|
ad1357 |
next full screen (which on idle screen could take ages).
|
|
|
ad1357 |
On disconnection we should tell the guest to stop streaming
|
|
|
ad1357 |
not wasting resources to stream not needed data.
|
|
|
ad1357 |
|
|
|
ad1357 |
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
|
|
|
ad1357 |
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
|
|
|
ad1357 |
---
|
|
|
ad1357 |
server/stream-channel.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
ad1357 |
1 file changed, 81 insertions(+)
|
|
|
ad1357 |
|
|
|
ad1357 |
diff --git a/server/stream-channel.c b/server/stream-channel.c
|
|
|
ad1357 |
index be6f7c7d1..2ad9ebae3 100644
|
|
|
ad1357 |
--- a/server/stream-channel.c
|
|
|
ad1357 |
+++ b/server/stream-channel.c
|
|
|
ad1357 |
@@ -121,8 +121,32 @@ stream_channel_client_init(StreamChannelClient *client)
|
|
|
ad1357 |
}
|
|
|
ad1357 |
|
|
|
ad1357 |
static void
|
|
|
ad1357 |
+request_new_stream(StreamChannel *channel, StreamMsgStartStop *start)
|
|
|
ad1357 |
+{
|
|
|
ad1357 |
+ if (channel->start_cb) {
|
|
|
ad1357 |
+ channel->start_cb(channel->start_opaque, start, channel);
|
|
|
ad1357 |
+ }
|
|
|
ad1357 |
+}
|
|
|
ad1357 |
+
|
|
|
ad1357 |
+static void
|
|
|
ad1357 |
stream_channel_client_on_disconnect(RedChannelClient *rcc)
|
|
|
ad1357 |
{
|
|
|
ad1357 |
+ RedChannel *red_channel = red_channel_client_get_channel(rcc);
|
|
|
ad1357 |
+
|
|
|
ad1357 |
+ // if there are still some client connected keep streaming
|
|
|
ad1357 |
+ // TODO, maybe would be worth sending new codecs if they are better
|
|
|
ad1357 |
+ if (red_channel_is_connected(red_channel)) {
|
|
|
ad1357 |
+ return;
|
|
|
ad1357 |
+ }
|
|
|
ad1357 |
+
|
|
|
ad1357 |
+ StreamChannel *channel = STREAM_CHANNEL(red_channel);
|
|
|
ad1357 |
+ channel->stream_id = -1;
|
|
|
ad1357 |
+ channel->width = 0;
|
|
|
ad1357 |
+ channel->height = 0;
|
|
|
ad1357 |
+
|
|
|
ad1357 |
+ // send stream stop to device
|
|
|
ad1357 |
+ StreamMsgStartStop stop = { 0, };
|
|
|
ad1357 |
+ request_new_stream(channel, &stop);
|
|
|
ad1357 |
}
|
|
|
ad1357 |
|
|
|
ad1357 |
static StreamChannelClient*
|
|
|
ad1357 |
@@ -258,18 +282,75 @@ stream_channel_new(RedsState *server, uint32_t id)
|
|
|
ad1357 |
NULL);
|
|
|
ad1357 |
}
|
|
|
ad1357 |
|
|
|
ad1357 |
+#define MAX_SUPPORTED_CODECS SPICE_VIDEO_CODEC_TYPE_ENUM_END
|
|
|
ad1357 |
+
|
|
|
ad1357 |
+// find common codecs supported by all clients
|
|
|
ad1357 |
+static uint8_t
|
|
|
ad1357 |
+stream_channel_get_supported_codecs(StreamChannel *channel, uint8_t *out_codecs)
|
|
|
ad1357 |
+{
|
|
|
ad1357 |
+ RedChannelClient *rcc;
|
|
|
ad1357 |
+ int codec;
|
|
|
ad1357 |
+
|
|
|
ad1357 |
+ static const uint16_t codec2cap[] = {
|
|
|
ad1357 |
+ 0, // invalid
|
|
|
ad1357 |
+ SPICE_DISPLAY_CAP_CODEC_MJPEG,
|
|
|
ad1357 |
+ SPICE_DISPLAY_CAP_CODEC_VP8,
|
|
|
ad1357 |
+ SPICE_DISPLAY_CAP_CODEC_H264,
|
|
|
ad1357 |
+ SPICE_DISPLAY_CAP_CODEC_VP9,
|
|
|
ad1357 |
+ };
|
|
|
ad1357 |
+
|
|
|
ad1357 |
+ bool supported[SPICE_N_ELEMENTS(codec2cap)];
|
|
|
ad1357 |
+
|
|
|
ad1357 |
+ for (codec = 0; codec < SPICE_N_ELEMENTS(codec2cap); ++codec) {
|
|
|
ad1357 |
+ supported[codec] = true;
|
|
|
ad1357 |
+ }
|
|
|
ad1357 |
+
|
|
|
ad1357 |
+ FOREACH_CLIENT(channel, rcc) {
|
|
|
ad1357 |
+ for (codec = 1; codec < SPICE_N_ELEMENTS(codec2cap); ++codec) {
|
|
|
ad1357 |
+ // if do not support codec delete from list
|
|
|
ad1357 |
+ if (!red_channel_client_test_remote_cap(rcc, codec2cap[codec])) {
|
|
|
ad1357 |
+ supported[codec] = false;
|
|
|
ad1357 |
+ }
|
|
|
ad1357 |
+ }
|
|
|
ad1357 |
+ }
|
|
|
ad1357 |
+
|
|
|
ad1357 |
+ // surely mjpeg is supported
|
|
|
ad1357 |
+ supported[SPICE_VIDEO_CODEC_TYPE_MJPEG] = true;
|
|
|
ad1357 |
+
|
|
|
ad1357 |
+ int num = 0;
|
|
|
ad1357 |
+ for (codec = 1; codec < SPICE_N_ELEMENTS(codec2cap); ++codec) {
|
|
|
ad1357 |
+ if (supported[codec]) {
|
|
|
ad1357 |
+ out_codecs[num++] = codec;
|
|
|
ad1357 |
+ }
|
|
|
ad1357 |
+ }
|
|
|
ad1357 |
+
|
|
|
ad1357 |
+ return num;
|
|
|
ad1357 |
+}
|
|
|
ad1357 |
+
|
|
|
ad1357 |
static void
|
|
|
ad1357 |
stream_channel_connect(RedChannel *red_channel, RedClient *red_client, RedsStream *stream,
|
|
|
ad1357 |
int migration, RedChannelCapabilities *caps)
|
|
|
ad1357 |
{
|
|
|
ad1357 |
StreamChannel *channel = STREAM_CHANNEL(red_channel);
|
|
|
ad1357 |
StreamChannelClient *client;
|
|
|
ad1357 |
+ struct {
|
|
|
ad1357 |
+ StreamMsgStartStop base;
|
|
|
ad1357 |
+ uint8_t codecs_buffer[MAX_SUPPORTED_CODECS];
|
|
|
ad1357 |
+ } start_msg;
|
|
|
ad1357 |
+ StreamMsgStartStop *const start = &start_msg.base;
|
|
|
ad1357 |
|
|
|
ad1357 |
spice_return_if_fail(stream != NULL);
|
|
|
ad1357 |
|
|
|
ad1357 |
client = stream_channel_client_new(channel, red_client, stream, migration, caps);
|
|
|
ad1357 |
spice_return_if_fail(client != NULL);
|
|
|
ad1357 |
|
|
|
ad1357 |
+ // request new stream
|
|
|
ad1357 |
+ start->num_codecs = stream_channel_get_supported_codecs(channel, start->codecs);
|
|
|
ad1357 |
+ // send in any case, even if list is not changed
|
|
|
ad1357 |
+ // notify device about changes
|
|
|
ad1357 |
+ request_new_stream(channel, start);
|
|
|
ad1357 |
+
|
|
|
ad1357 |
+
|
|
|
ad1357 |
// TODO set capabilities like SPICE_DISPLAY_CAP_MONITORS_CONFIG
|
|
|
ad1357 |
// see guest_set_client_capabilities
|
|
|
ad1357 |
RedChannelClient *rcc = RED_CHANNEL_CLIENT(client);
|