[Spice-devel] [RFC spice-server 1/1] streaming: Restart guest video streams on video-codec changes
Kevin Pouget
kpouget at redhat.com
Wed Jul 31 08:36:33 UTC 2019
This patch resets (stream_channel_reset) the guest video streams when
the the user changes the preferred video-codecs or when the host admin
updates the list of video-codecs allowed.
See also patch 4000846c0157a787b786a9bf7f36f0b6a73dfbf8 for the host
streaming counter part.
---
server/dcc.c | 4 +++-
server/display-channel.c | 2 +-
server/red-stream-device.c | 15 +++++++++++++++
server/red-stream-device.h | 1 +
server/reds.c | 11 +++++++++++
server/reds.h | 1 +
server/stream-channel.c | 34 ++++++++++++++++++++++++++++++----
server/video-stream.c | 8 ++++++++
server/video-stream.h | 1 +
9 files changed, 71 insertions(+), 6 deletions(-)
diff --git a/server/dcc.c b/server/dcc.c
index 21e8598e..2113d394 100644
--- a/server/dcc.c
+++ b/server/dcc.c
@@ -22,6 +22,7 @@
#include "display-channel.h"
#include "display-channel-private.h"
#include "red-client.h"
+#include "red-stream-device.h"
#include "main-channel-client.h"
#include <spice-server-enums.h>
#include "glib-compat.h"
@@ -1193,7 +1194,8 @@ static int dcc_handle_preferred_video_codec_type(DisplayChannelClient *dcc,
/* New client preference */
dcc_update_preferred_video_codecs(dcc);
- video_stream_detach_and_stop(DCC_TO_DC(dcc));
+
+ video_stream_codecs_changed(DCC_TO_DC(dcc));
return TRUE;
}
diff --git a/server/display-channel.c b/server/display-channel.c
index 75266598..65bc15ca 100644
--- a/server/display-channel.c
+++ b/server/display-channel.c
@@ -256,7 +256,7 @@ void display_channel_set_video_codecs(DisplayChannel *display, GArray *video_cod
display->priv->video_codecs = g_array_ref(video_codecs);
g_object_notify(G_OBJECT(display), "video-codecs");
- video_stream_detach_and_stop(display);
+ video_stream_codecs_changed(display);
}
GArray *display_channel_get_video_codecs(DisplayChannel *display)
diff --git a/server/red-stream-device.c b/server/red-stream-device.c
index 620e581e..1208a395 100644
--- a/server/red-stream-device.c
+++ b/server/red-stream-device.c
@@ -710,6 +710,21 @@ reset_channels(StreamDevice *dev)
}
}
+void
+stream_device_codecs_changed(RedCharDevice *char_dev)
+{
+ StreamDevice *dev = STREAM_DEVICE(char_dev);
+
+ StreamChannel *channel = dev->stream_channel;
+
+ if (channel == NULL) {
+ return;
+ }
+
+ /* interrupt the guest-side video streams*/
+ stream_channel_reset(channel);
+}
+
static void
char_device_set_state(RedCharDevice *char_dev, int state)
{
diff --git a/server/red-stream-device.h b/server/red-stream-device.h
index aa2b23a2..c48182e4 100644
--- a/server/red-stream-device.h
+++ b/server/red-stream-device.h
@@ -55,6 +55,7 @@ StreamDevice *stream_device_connect(RedsState *reds, SpiceCharDeviceInstance *si
* If the channel already exists the function does nothing.
*/
void stream_device_create_channel(StreamDevice *dev);
+void stream_device_codecs_changed(RedCharDevice *char_dev);
const StreamDeviceDisplayInfo *stream_device_get_device_display_info(StreamDevice *dev);
diff --git a/server/reds.c b/server/reds.c
index 78bbe5a0..d15e11b3 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -1880,6 +1880,17 @@ static void reds_late_initialization(RedsState *reds)
reds->late_initialization_done = true;
}
+void
+reds_codecs_changed(RedsState *reds) {
+ RedCharDevice *dev;
+
+ GLIST_FOREACH(reds->char_devices, RedCharDevice, dev) {
+ if (IS_STREAM_DEVICE(dev)) {
+ stream_device_codecs_changed(dev);
+ }
+ }
+}
+
static void
red_channel_capabilities_init_from_link_message(RedChannelCapabilities *caps,
const SpiceLinkMess *link_mess)
diff --git a/server/reds.h b/server/reds.h
index e3355f81..40feb330 100644
--- a/server/reds.h
+++ b/server/reds.h
@@ -92,6 +92,7 @@ int reds_on_migrate_dst_set_seamless(RedsState *reds, MainChannelClient *mcc, ui
void reds_on_client_semi_seamless_migrate_complete(RedsState *reds, RedClient *client);
void reds_on_client_seamless_migrate_complete(RedsState *reds, RedClient *client);
void reds_on_main_channel_migrate(RedsState *reds, MainChannelClient *mcc);
+void reds_codecs_changed(RedsState *reds);
void reds_set_client_mm_time_latency(RedsState *reds, RedClient *client, uint32_t latency);
uint32_t reds_get_streaming_video(const RedsState *reds);
diff --git a/server/stream-channel.c b/server/stream-channel.c
index 7953018e..35441ebf 100644
--- a/server/stream-channel.c
+++ b/server/stream-channel.c
@@ -369,17 +369,38 @@ stream_channel_get_supported_codecs(StreamChannel *channel, uint8_t *out_codecs)
}
FOREACH_CLIENT(channel, rcc) {
+ RedChannel *red_channel = red_channel_client_get_channel(rcc);
+ RedsState *reds = red_channel_get_server(red_channel);
+ GArray *preferred_codecs = reds_get_video_codecs(reds);
+
for (codec = 1; codec < SPICE_N_ELEMENTS(codec2cap); ++codec) {
- // if do not support codec delete from list
+ // skip the codec if it is already not supported
+ if (!supported[codec]) {
+ continue;
+ }
+
+ // delete the codec from list if it's not supported
if (!red_channel_client_test_remote_cap(rcc, codec2cap[codec])) {
supported[codec] = false;
+ continue;
+ }
+
+ // delete the codec from list if it's not in the preferred list
+ bool preferred_has_codec = false;
+ int i;
+
+ for (i = 0; i < preferred_codecs->len; i++) {
+ RedVideoCodec pref_codec = g_array_index(preferred_codecs, RedVideoCodec, i);
+
+ if (pref_codec.type == codec) {
+ preferred_has_codec = true;
+ break;
+ }
}
+ supported[codec] = preferred_has_codec;
}
}
- // 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]) {
@@ -387,6 +408,11 @@ stream_channel_get_supported_codecs(StreamChannel *channel, uint8_t *out_codecs)
}
}
+ if (num == 0) {
+ // surely mjpeg is supported
+ supported[SPICE_VIDEO_CODEC_TYPE_MJPEG] = true;
+ }
+
return num;
}
diff --git a/server/video-stream.c b/server/video-stream.c
index 6aa859a0..483c42f1 100644
--- a/server/video-stream.c
+++ b/server/video-stream.c
@@ -950,6 +950,14 @@ void video_stream_timeout(DisplayChannel *display)
}
}
+void video_stream_codecs_changed(DisplayChannel *display) {
+ /* interrupt the guest-side video streams*/
+ reds_codecs_changed(red_channel_get_server(RED_CHANNEL(display)));
+
+ /* interrupt the server-side video streams*/
+ video_stream_detach_and_stop(display);
+}
+
void video_stream_trace_add_drawable(DisplayChannel *display,
Drawable *item)
{
diff --git a/server/video-stream.h b/server/video-stream.h
index 46b076fd..fe74fc34 100644
--- a/server/video-stream.h
+++ b/server/video-stream.h
@@ -147,6 +147,7 @@ void video_stream_detach_and_stop(DisplayChannel *display);
void video_stream_trace_add_drawable(DisplayChannel *display, Drawable *item);
void video_stream_detach_behind(DisplayChannel *display, QRegion *region,
Drawable *drawable);
+void video_stream_codecs_changed(DisplayChannel *display);
void video_stream_agent_unref(DisplayChannel *display, VideoStreamAgent *agent);
void video_stream_agent_stop(VideoStreamAgent *agent);
--
2.21.0
More information about the Spice-devel
mailing list