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