Blame SOURCES/0023-sound-Don-t-mute-recording-when-client-reconnects.patch

7bbc9c
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
7bbc9c
From: Christophe Fergeau <cfergeau@redhat.com>
7bbc9c
Date: Fri, 25 May 2018 11:12:40 +0200
7bbc9c
Subject: [spice-server] sound: Don't mute recording when client reconnects
7bbc9c
7bbc9c
When a new record channel is added, the code relies on a snd_send() call
7bbc9c
in record_channel_client_constructed() to send RECORD_START to the
7bbc9c
client. However, at this point, snd_send() is non-functional because
7bbc9c
the red_channel_client_pipe_add() call it makes is a no-op because
7bbc9c
prepare_pipe_add() makes a connection check through
7bbc9c
red_channel_client_is_connected() queueing the item. This connection
7bbc9c
check returns FALSE at ::constructed() time as the channel client will
7bbc9c
only become connected towards the end of
7bbc9c
red_channel_client_initable_init() which runs after the object
7bbc9c
instantiation is complete.
7bbc9c
7bbc9c
This commit solves this issue by making PlaybackChannelClient and
7bbc9c
RecordChannelClient implement GInitable, and move the code interacting
7bbc9c
with the client in their _initable_init() function, as at this point the
7bbc9c
objects will be able to send data.
7bbc9c
7bbc9c
This causes a bug where starting recording and then
7bbc9c
disconnecting/reconnecting the client does not successfully reenable
7bbc9c
recording. This is a regression introduced by commit d8dc09
7bbc9c
'sound: Convert SndChannelClient to RedChannelClient'
7bbc9c
7bbc9c
https://bugzilla.redhat.com/show_bug.cgi?id=1549132
7bbc9c
7bbc9c
Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
7bbc9c
Acked-by: Victor Toso <victortoso@redhat.com>
7bbc9c
---
7bbc9c
 server/sound.c | 120 ++++++++++++++++++++++++++++++++++---------------
7bbc9c
 1 file changed, 83 insertions(+), 37 deletions(-)
7bbc9c
7bbc9c
diff --git a/server/sound.c b/server/sound.c
7bbc9c
index 9073626..8c6cf8a 100644
7bbc9c
--- a/server/sound.c
7bbc9c
+++ b/server/sound.c
7bbc9c
@@ -103,6 +103,11 @@ typedef struct SndChannelClientClass {
7bbc9c
     RedChannelClientClass parent_class;
7bbc9c
 } SndChannelClientClass;
7bbc9c
 
7bbc9c
+static void playback_channel_client_initable_interface_init(GInitableIface *iface);
7bbc9c
+static void record_channel_client_initable_interface_init(GInitableIface *iface);
7bbc9c
+static GInitableIface *playback_channel_client_parent_initable_iface;
7bbc9c
+static GInitableIface *record_channel_client_parent_initable_iface;
7bbc9c
+
7bbc9c
 G_DEFINE_TYPE(SndChannelClient, snd_channel_client, RED_TYPE_CHANNEL_CLIENT)
7bbc9c
 
7bbc9c
 
7bbc9c
@@ -149,7 +154,9 @@ typedef struct PlaybackChannelClientClass {
7bbc9c
     SndChannelClientClass parent_class;
7bbc9c
 } PlaybackChannelClientClass;
7bbc9c
 
7bbc9c
-G_DEFINE_TYPE(PlaybackChannelClient, playback_channel_client, TYPE_SND_CHANNEL_CLIENT)
7bbc9c
+G_DEFINE_TYPE_WITH_CODE(PlaybackChannelClient, playback_channel_client, TYPE_SND_CHANNEL_CLIENT,
7bbc9c
+                        G_IMPLEMENT_INTERFACE(G_TYPE_INITABLE, playback_channel_client_initable_interface_init))
7bbc9c
+ 
7bbc9c
 
7bbc9c
 
7bbc9c
 typedef struct SpiceVolumeState {
7bbc9c
@@ -207,6 +214,7 @@ typedef struct RecordChannelClass {
7bbc9c
 } RecordChannelClass;
7bbc9c
 
7bbc9c
 G_DEFINE_TYPE(RecordChannel, record_channel, TYPE_SND_CHANNEL)
7bbc9c
+ 
7bbc9c
 
7bbc9c
 
7bbc9c
 #define TYPE_RECORD_CHANNEL_CLIENT record_channel_client_get_type()
7bbc9c
@@ -230,7 +238,8 @@ typedef struct RecordChannelClientClass {
7bbc9c
     SndChannelClientClass parent_class;
7bbc9c
 } RecordChannelClientClass;
7bbc9c
 
7bbc9c
-G_DEFINE_TYPE(RecordChannelClient, record_channel_client, TYPE_SND_CHANNEL_CLIENT)
7bbc9c
+G_DEFINE_TYPE_WITH_CODE(RecordChannelClient, record_channel_client, TYPE_SND_CHANNEL_CLIENT,
7bbc9c
+                        G_IMPLEMENT_INTERFACE(G_TYPE_INITABLE, record_channel_client_initable_interface_init))
7bbc9c
 
7bbc9c
 
7bbc9c
 /* A list of all Spice{Playback,Record}State objects */
7bbc9c
@@ -1044,7 +1053,6 @@ playback_channel_client_constructed(GObject *object)
7bbc9c
     RedChannelClient *rcc = RED_CHANNEL_CLIENT(playback_client);
7bbc9c
     RedChannel *red_channel = red_channel_client_get_channel(rcc);
7bbc9c
     SndChannel *channel = SND_CHANNEL(red_channel);
7bbc9c
-    RedClient *red_client = red_channel_client_get_client(rcc);
7bbc9c
     SndChannelClient *scc = SND_CHANNEL_CLIENT(playback_client);
7bbc9c
 
7bbc9c
     G_OBJECT_CLASS(playback_channel_client_parent_class)->constructed(object);
7bbc9c
@@ -1070,18 +1078,6 @@ playback_channel_client_constructed(GObject *object)
7bbc9c
 
7bbc9c
     spice_debug("playback client %p using mode %s", playback_client,
7bbc9c
                 spice_audio_data_mode_to_string(playback_client->mode));
7bbc9c
-
7bbc9c
-    if (!red_client_during_migrate_at_target(red_client)) {
7bbc9c
-        snd_set_command(scc, SND_PLAYBACK_MODE_MASK);
7bbc9c
-        if (channel->volume.volume_nchannels) {
7bbc9c
-            snd_set_command(scc, SND_VOLUME_MUTE_MASK);
7bbc9c
-        }
7bbc9c
-    }
7bbc9c
-
7bbc9c
-    if (channel->active) {
7bbc9c
-        playback_channel_client_start(scc);
7bbc9c
-    }
7bbc9c
-    snd_send(scc);
7bbc9c
 }
7bbc9c
 
7bbc9c
 static void snd_set_peer(RedChannel *red_channel, RedClient *client, RedsStream *stream,
7bbc9c
@@ -1250,27 +1246,6 @@ record_channel_client_finalize(GObject *object)
7bbc9c
     G_OBJECT_CLASS(record_channel_client_parent_class)->finalize(object);
7bbc9c
 }
7bbc9c
 
7bbc9c
-static void
7bbc9c
-record_channel_client_constructed(GObject *object)
7bbc9c
-{
7bbc9c
-    RecordChannelClient *record_client = RECORD_CHANNEL_CLIENT(object);
7bbc9c
-    RedChannel *red_channel = red_channel_client_get_channel(RED_CHANNEL_CLIENT(record_client));
7bbc9c
-    SndChannel *channel = SND_CHANNEL(red_channel);
7bbc9c
-    SndChannelClient *scc = SND_CHANNEL_CLIENT(record_client);
7bbc9c
-
7bbc9c
-    G_OBJECT_CLASS(record_channel_client_parent_class)->constructed(object);
7bbc9c
-
7bbc9c
-    if (channel->volume.volume_nchannels) {
7bbc9c
-        snd_set_command(scc, SND_VOLUME_MUTE_MASK);
7bbc9c
-    }
7bbc9c
-
7bbc9c
-    if (channel->active) {
7bbc9c
-        record_channel_client_start(scc);
7bbc9c
-    }
7bbc9c
-    snd_send(scc);
7bbc9c
-}
7bbc9c
-
7bbc9c
-
7bbc9c
 static void snd_set_record_peer(RedChannel *red_channel, RedClient *client, RedsStream *stream,
7bbc9c
                                 G_GNUC_UNUSED int migration,
7bbc9c
                                 RedChannelCapabilities *caps)
7bbc9c
@@ -1478,6 +1453,43 @@ snd_channel_client_init(SndChannelClient *self)
7bbc9c
 {
7bbc9c
 }
7bbc9c
 
7bbc9c
+static gboolean playback_channel_client_initable_init(GInitable *initable,
7bbc9c
+                                                      GCancellable *cancellable,
7bbc9c
+                                                      GError **error)
7bbc9c
+{
7bbc9c
+    gboolean success;
7bbc9c
+    RedClient *red_client = red_channel_client_get_client(RED_CHANNEL_CLIENT(initable));
7bbc9c
+    SndChannelClient *scc = SND_CHANNEL_CLIENT(initable);
7bbc9c
+    RedChannel *red_channel = red_channel_client_get_channel(RED_CHANNEL_CLIENT(initable));
7bbc9c
+    SndChannel *channel = SND_CHANNEL(red_channel);
7bbc9c
+
7bbc9c
+    success = playback_channel_client_parent_initable_iface->init(initable, cancellable, error);
7bbc9c
+    if (!success) {
7bbc9c
+        return FALSE;
7bbc9c
+    }
7bbc9c
+
7bbc9c
+    if (!red_client_during_migrate_at_target(red_client)) {
7bbc9c
+        snd_set_command(scc, SND_PLAYBACK_MODE_MASK);
7bbc9c
+        if (channel->volume.volume_nchannels) {
7bbc9c
+            snd_set_command(scc, SND_VOLUME_MUTE_MASK);
7bbc9c
+        }
7bbc9c
+    }
7bbc9c
+
7bbc9c
+    if (channel->active) {
7bbc9c
+        playback_channel_client_start(scc);
7bbc9c
+    }
7bbc9c
+    snd_send(SND_CHANNEL_CLIENT(initable));
7bbc9c
+
7bbc9c
+    return TRUE;
7bbc9c
+}
7bbc9c
+
7bbc9c
+static void playback_channel_client_initable_interface_init(GInitableIface *iface)
7bbc9c
+{
7bbc9c
+    playback_channel_client_parent_initable_iface = g_type_interface_peek_parent (iface);
7bbc9c
+
7bbc9c
+    iface->init = playback_channel_client_initable_init;
7bbc9c
+}
7bbc9c
+
7bbc9c
 static void
7bbc9c
 playback_channel_client_class_init(PlaybackChannelClientClass *klass)
7bbc9c
 {
7bbc9c
@@ -1505,11 +1517,45 @@ playback_channel_client_init(PlaybackChannelClient *playback)
7bbc9c
     snd_playback_alloc_frames(playback);
7bbc9c
 }
7bbc9c
 
7bbc9c
+static gboolean record_channel_client_initable_init(GInitable *initable,
7bbc9c
+                                                    GCancellable *cancellable,
7bbc9c
+                                                    GError **error)
7bbc9c
+{
7bbc9c
+    gboolean success;
7bbc9c
+    RecordChannelClient *record_client = RECORD_CHANNEL_CLIENT(initable);
7bbc9c
+    RedChannel *red_channel = red_channel_client_get_channel(RED_CHANNEL_CLIENT(record_client));
7bbc9c
+    SndChannel *channel = SND_CHANNEL(red_channel);
7bbc9c
+    SndChannelClient *scc = SND_CHANNEL_CLIENT(record_client);
7bbc9c
+
7bbc9c
+    success = record_channel_client_parent_initable_iface->init(initable, cancellable, error);
7bbc9c
+    if (!success) {
7bbc9c
+        return FALSE;
7bbc9c
+    }
7bbc9c
+
7bbc9c
+    if (channel->volume.volume_nchannels) {
7bbc9c
+        snd_set_command(scc, SND_VOLUME_MUTE_MASK);
7bbc9c
+    }
7bbc9c
+
7bbc9c
+    if (channel->active) {
7bbc9c
+        record_channel_client_start(scc);
7bbc9c
+    }
7bbc9c
+    snd_send(SND_CHANNEL_CLIENT(initable));
7bbc9c
+
7bbc9c
+    return TRUE;
7bbc9c
+}
7bbc9c
+
7bbc9c
+static void record_channel_client_initable_interface_init(GInitableIface *iface)
7bbc9c
+{
7bbc9c
+    record_channel_client_parent_initable_iface = g_type_interface_peek_parent (iface);
7bbc9c
+
7bbc9c
+    iface->init = record_channel_client_initable_init;
7bbc9c
+}
7bbc9c
+
7bbc9c
+
7bbc9c
 static void
7bbc9c
 record_channel_client_class_init(RecordChannelClientClass *klass)
7bbc9c
 {
7bbc9c
     GObjectClass *object_class = G_OBJECT_CLASS(klass);
7bbc9c
-    object_class->constructed = record_channel_client_constructed;
7bbc9c
     object_class->finalize = record_channel_client_finalize;
7bbc9c
 }
7bbc9c