[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