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