[RFC,spice-server,3/3] streaming: Restart guest video streams on video-codec changes

Submitted by Kevin Pouget on Aug. 6, 2019, 3:34 p.m.

Details

Message ID 20190806153453.20616-4-kpouget@redhat.com
State New
Headers show
Series "Series without cover letter" ( rev: 3 2 1 ) in Spice

Not browsing as part of any series.

Commit Message

Kevin Pouget Aug. 6, 2019, 3:34 p.m.
This patch resets the host and guest video streams when the client
changes the preferred video-codecs or when the host admin updates the
list of video-codecs allowed.

TODO: restart only the streams of the client that changed codecs

Signed-off-by: Kevin Pouget <kpouget@redhat.com>
---
 server/main-dispatcher.c   | 31 ++++++++++++++++++++++++++++++-
 server/main-dispatcher.h   |  1 +
 server/red-stream-device.c |  6 +++---
 server/red-stream-device.h |  2 +-
 server/reds.c              | 11 +++++++++++
 server/reds.h              |  2 +-
 server/stream-channel.c    |  6 ++++++
 7 files changed, 53 insertions(+), 6 deletions(-)

Patch hide | download patch | download mbox

diff --git a/server/main-dispatcher.c b/server/main-dispatcher.c
index 2ca68a4d..04f5ac88 100644
--- a/server/main-dispatcher.c
+++ b/server/main-dispatcher.c
@@ -126,7 +126,7 @@  enum {
     MAIN_DISPATCHER_MIGRATE_SEAMLESS_DST_COMPLETE,
     MAIN_DISPATCHER_SET_MM_TIME_LATENCY,
     MAIN_DISPATCHER_CLIENT_DISCONNECT,
-
+    MAIN_DISPATCHER_RESET_STREAM_CHANNELS,
     MAIN_DISPATCHER_NUM_MESSAGES
 };
 
@@ -148,6 +148,11 @@  typedef struct MainDispatcherClientDisconnectMessage {
     RedClient *client;
 } MainDispatcherClientDisconnectMessage;
 
+
+typedef struct MainDispatcherResetStreamChannelMessage {
+    RedClient *client;
+} MainDispatcherResetStreamChannelMessage;
+
 /* channel_event - calls core->channel_event, must be done in main thread */
 static void main_dispatcher_handle_channel_event(void *opaque,
                                                  void *payload)
@@ -203,6 +208,17 @@  static void main_dispatcher_handle_client_disconnect(void *opaque,
     g_object_unref(msg->client);
 }
 
+static void main_dispatcher_handle_reset_stream_channel(void *opaque,
+                                                        void *payload)
+{
+    RedsState *reds = opaque;
+    MainDispatcherResetStreamChannelMessage __attribute__((unused)) *msg = payload;
+
+    /* TODO: reset only the char device linked to msg.client */
+
+    reds_reset_all_stream_char_devices(reds);
+}
+
 void main_dispatcher_seamless_migrate_dst_complete(MainDispatcher *self,
                                                    RedClient *client)
 {
@@ -247,6 +263,16 @@  void main_dispatcher_client_disconnect(MainDispatcher *self, RedClient *client)
     }
 }
 
+void main_dispatcher_reset_stream_channels(MainDispatcher *self, RedClient *client)
+{
+    MainDispatcherResetStreamChannelMessage msg;
+
+    msg.client = client;
+
+    dispatcher_send_message(DISPATCHER(self), MAIN_DISPATCHER_RESET_STREAM_CHANNELS,
+                            &msg);
+}
+
 /*
  * FIXME:
  * Reds routines shouldn't be exposed. Instead reds.c should register the callbacks,
@@ -282,6 +308,9 @@  void main_dispatcher_constructed(GObject *object)
     dispatcher_register_handler(DISPATCHER(self), MAIN_DISPATCHER_CLIENT_DISCONNECT,
                                 main_dispatcher_handle_client_disconnect,
                                 sizeof(MainDispatcherClientDisconnectMessage), false);
+    dispatcher_register_handler(DISPATCHER(self), MAIN_DISPATCHER_RESET_STREAM_CHANNELS,
+                                main_dispatcher_handle_reset_stream_channel,
+                                sizeof(MainDispatcherResetStreamChannelMessage), false);
 }
 
 static void main_dispatcher_finalize(GObject *object)
diff --git a/server/main-dispatcher.h b/server/main-dispatcher.h
index e1244f83..6d5f50a0 100644
--- a/server/main-dispatcher.h
+++ b/server/main-dispatcher.h
@@ -58,6 +58,7 @@  void main_dispatcher_set_mm_time_latency(MainDispatcher *self, RedClient *client
  * that triggered the client destruction.
  */
 void main_dispatcher_client_disconnect(MainDispatcher *self, RedClient *client);
+void main_dispatcher_reset_stream_channels(MainDispatcher *self, RedClient *client);
 
 MainDispatcher* main_dispatcher_new(RedsState *reds);
 
diff --git a/server/red-stream-device.c b/server/red-stream-device.c
index 620e581e..c551de69 100644
--- a/server/red-stream-device.c
+++ b/server/red-stream-device.c
@@ -702,8 +702,8 @@  stream_device_create_channel(StreamDevice *dev)
     stream_channel_register_queue_stat_cb(stream_channel, stream_device_stream_queue_stat, dev);
 }
 
-static void
-reset_channels(StreamDevice *dev)
+void
+stream_device_reset_channels(StreamDevice *dev)
 {
     if (dev->stream_channel) {
         stream_channel_reset(dev->stream_channel);
@@ -763,7 +763,7 @@  stream_device_port_event(RedCharDevice *char_dev, uint8_t event)
     dev->has_error = false;
     dev->flow_stopped = false;
     red_char_device_reset(char_dev);
-    reset_channels(dev);
+    stream_device_reset_channels(dev);
 
     // enable the device again. We re-enable it on close as otherwise we don't want to get a
     // failure when  we try to re-open the device as would happen if we keep it disabled
diff --git a/server/red-stream-device.h b/server/red-stream-device.h
index aa2b23a2..0f080228 100644
--- a/server/red-stream-device.h
+++ b/server/red-stream-device.h
@@ -55,7 +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_reset_channels(StreamDevice *dev);
 const StreamDeviceDisplayInfo *stream_device_get_device_display_info(StreamDevice *dev);
 
 /**
diff --git a/server/reds.c b/server/reds.c
index a3795ab9..9aae838d 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -3301,6 +3301,17 @@  static void reds_on_char_device_destroy(RedsState *reds,
     reds->char_devices = g_list_remove(reds->char_devices, dev);
 }
 
+void reds_reset_all_stream_char_devices(RedsState *reds)
+{
+    RedCharDevice *dev;
+
+    GLIST_FOREACH(reds->char_devices, RedCharDevice, dev) {
+        if (IS_STREAM_DEVICE(dev)) {
+            stream_device_reset_channels(STREAM_DEVICE(dev));
+        }
+    }
+}
+
 static int spice_server_char_device_add_interface(SpiceServer *reds,
                                            SpiceBaseInstance *sin)
 {
diff --git a/server/reds.h b/server/reds.h
index e3355f81..ec106394 100644
--- a/server/reds.h
+++ b/server/reds.h
@@ -53,7 +53,7 @@  bool reds_config_get_playback_compression(RedsState *reds); // used by playback
 
 void reds_send_device_display_info(RedsState *reds);
 void reds_handle_agent_mouse_event(RedsState *reds, const VDAgentMouseState *mouse_state); // used by inputs_channel
-
+void reds_reset_all_stream_char_devices(RedsState *reds);
 GArray* reds_get_renderers(RedsState *reds);
 char *reds_get_video_codec_fullname(RedVideoCodec *codec);
 
diff --git a/server/stream-channel.c b/server/stream-channel.c
index e0e41895..99ce7c9a 100644
--- a/server/stream-channel.c
+++ b/server/stream-channel.c
@@ -465,6 +465,12 @@  stream_channel_handle_preferred_video_codec_type(RedChannelClient *rcc,
     g_clear_pointer(&scc->client_preferred_video_codecs, g_array_unref);
     scc->client_preferred_video_codecs = video_stream_parse_preferred_codecs(msg);
 
+    /* Reset video streams */
+    RedClient *client = red_channel_client_get_client(rcc);
+    RedsState *reds = red_client_get_server(client);
+
+    main_dispatcher_reset_stream_channels(reds_get_main_dispatcher(reds), client);
+
     return TRUE;
 }