[Spice-devel] [spice-server v2 09/10] sound: Turn {Playback, Record}ChannelClient into GObjects
Christophe Fergeau
cfergeau at redhat.com
Tue Jan 24 11:52:44 UTC 2017
This is in preparation for making them inherit from RedChannelClient.
Doing it in one go would result in a very huge commit, so this commit
starts by turning these into GObjects, while still using a
DummyChannelClient instance for sending the data.
Based on a patch from Frediano Ziglio <fziglio at redhat.com>
Signed-off-by: Christophe Fergeau <cfergeau at redhat.com>
---
server/sound.c | 326 +++++++++++++++++++++++++++++++++++++--------------------
1 file changed, 210 insertions(+), 116 deletions(-)
diff --git a/server/sound.c b/server/sound.c
index d0cfbf1..7738de4 100644
--- a/server/sound.c
+++ b/server/sound.c
@@ -83,14 +83,17 @@ typedef struct SpicePlaybackState PlaybackChannel;
typedef struct SpiceRecordState RecordChannel;
typedef void (*snd_channel_on_message_done_proc)(SndChannelClient *client);
-typedef void (*snd_channel_cleanup_channel_proc)(SndChannelClient *client);
-#define SND_CHANNEL_CLIENT(obj) (&(obj)->base)
+#define TYPE_SND_CHANNEL_CLIENT snd_channel_client_get_type()
+#define SND_CHANNEL_CLIENT(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_SND_CHANNEL_CLIENT, SndChannelClient))
+#define IS_SND_CHANNEL_CLIENT(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_SND_CHANNEL_CLIENT))
+GType snd_channel_client_get_type(void) G_GNUC_CONST;
/* Connects an audio client to a Spice client */
struct SndChannelClient {
- int refs;
-
+ GObject parent;
RedChannelClient *channel_client;
int active;
@@ -104,9 +107,14 @@ struct SndChannelClient {
RedPipeItem persistent_pipe_item;
snd_channel_on_message_done_proc on_message_done;
- snd_channel_cleanup_channel_proc cleanup;
};
+typedef struct SndChannelClientClass {
+ GObjectClass parent_class;
+} SndChannelClientClass;
+
+G_DEFINE_TYPE(SndChannelClient, snd_channel_client, G_TYPE_OBJECT)
+
enum {
RED_PIPE_ITEM_PERSISTENT = RED_PIPE_ITEM_TYPE_CHANNEL_BASE,
@@ -129,8 +137,13 @@ struct AudioFrameContainer
AudioFrame items[NUM_AUDIO_FRAMES];
};
+#define TYPE_PLAYBACK_CHANNEL_CLIENT playback_channel_client_get_type()
+#define PLAYBACK_CHANNEL_CLIENT(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_PLAYBACK_CHANNEL_CLIENT, PlaybackChannelClient))
+GType playback_channel_client_get_type(void) G_GNUC_CONST;
+
struct PlaybackChannelClient {
- SndChannelClient base;
+ SndChannelClient parent;
AudioFrameContainer *frames;
AudioFrame *free_frames;
@@ -142,6 +155,13 @@ struct PlaybackChannelClient {
uint8_t encode_buf[SND_CODEC_MAX_COMPRESSED_BYTES];
};
+typedef struct PlaybackChannelClientClass {
+ SndChannelClientClass parent_class;
+} PlaybackChannelClientClass;
+
+G_DEFINE_TYPE(PlaybackChannelClient, playback_channel_client, TYPE_SND_CHANNEL_CLIENT)
+
+
typedef struct SpiceVolumeState {
uint16_t *volume;
uint8_t volume_nchannels;
@@ -202,8 +222,13 @@ typedef struct RecordChannelClass {
G_DEFINE_TYPE(RecordChannel, record_channel, TYPE_SND_CHANNEL)
+#define TYPE_RECORD_CHANNEL_CLIENT record_channel_client_get_type()
+#define RECORD_CHANNEL_CLIENT(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_RECORD_CHANNEL_CLIENT, RecordChannelClient))
+GType record_channel_client_get_type(void) G_GNUC_CONST;
+
struct RecordChannelClient {
- SndChannelClient base;
+ SndChannelClient parent;
uint32_t samples[RECORD_SAMPLES_SIZE];
uint32_t write_pos;
uint32_t read_pos;
@@ -214,22 +239,41 @@ struct RecordChannelClient {
uint8_t decode_buf[SND_CODEC_MAX_FRAME_BYTES];
};
+typedef struct RecordChannelClientClass {
+ SndChannelClientClass parent_class;
+} RecordChannelClientClass;
+
+G_DEFINE_TYPE(RecordChannelClient, record_channel_client, TYPE_SND_CHANNEL_CLIENT)
+
+
/* A list of all Spice{Playback,Record}State objects */
static SndChannel *snd_channels;
static void snd_playback_start(SndChannel *channel);
static void snd_record_start(SndChannel *channel);
-static void snd_playback_alloc_frames(PlaybackChannelClient *playback);
static void snd_send(SndChannelClient * client);
-static SndChannelClient *snd_channel_unref(SndChannelClient *client)
+enum {
+ PROP0,
+ PROP_CHANNEL_CLIENT
+};
+
+static void
+snd_channel_client_set_property(GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
{
- if (!--client->refs) {
- spice_printerr("SndChannelClient=%p freed", client);
- free(client);
- return NULL;
+ SndChannelClient *self = SND_CHANNEL_CLIENT(object);
+
+ switch (property_id)
+ {
+ case PROP_CHANNEL_CLIENT:
+ self->channel_client = g_value_dup_object(value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
}
- return client;
}
static SndChannelClient *snd_channel_client_from_dummy(RedChannelClient *dummy)
@@ -238,6 +282,7 @@ static SndChannelClient *snd_channel_client_from_dummy(RedChannelClient *dummy)
g_assert(IS_DUMMY_CHANNEL_CLIENT(dummy));
sound_client = g_object_get_data(G_OBJECT(dummy), "sound-channel-client");
+ g_assert(IS_SND_CHANNEL_CLIENT(sound_client));
return sound_client;
}
@@ -263,10 +308,9 @@ static void snd_disconnect_channel(SndChannelClient *client)
spice_debug("SndChannelClient=%p rcc=%p type=%d",
client, client->channel_client, type);
channel = SND_CHANNEL(red_channel);
- client->cleanup(client);
red_channel_client_disconnect(channel->connection->channel_client);
channel->connection->channel_client = NULL;
- snd_channel_unref(client);
+ g_object_unref(client);
channel->connection = NULL;
}
@@ -290,10 +334,6 @@ static void snd_playback_on_message_done(SndChannelClient *client)
}
}
-static void snd_record_on_message_done(SndChannelClient *client)
-{
-}
-
static int snd_record_handle_write(RecordChannelClient *record_client, size_t size, void *message)
{
SpiceMsgcRecordPacket *packet;
@@ -355,7 +395,7 @@ static int
record_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, uint16_t type, void *message)
{
SndChannelClient *snd_client = snd_channel_client_from_dummy(rcc);
- RecordChannelClient *record_client = SPICE_CONTAINEROF(snd_client, RecordChannelClient, base);
+ RecordChannelClient *record_client = RECORD_CHANNEL_CLIENT(snd_client);
switch (type) {
case SPICE_MSGC_RECORD_DATA:
@@ -648,49 +688,6 @@ static int playback_send_mode(PlaybackChannelClient *playback_client)
return TRUE;
}
-static int snd_channel_config_socket(RedChannelClient *rcc);
-
-static SndChannelClient *__new_channel(SndChannel *channel, int size, uint32_t channel_id,
- RedClient *red_client,
- RedsStream *stream,
- snd_channel_on_message_done_proc on_message_done,
- snd_channel_cleanup_channel_proc cleanup,
- uint32_t *common_caps, int num_common_caps,
- uint32_t *caps, int num_caps)
-{
- SndChannelClient *client;
-
- spice_assert(size >= sizeof(*client));
- client = spice_malloc0(size);
- client->refs = 1;
- client->on_message_done = on_message_done;
- client->cleanup = cleanup;
-
- client->channel_client =
- dummy_channel_client_create(RED_CHANNEL(channel), red_client, stream,
- num_common_caps, common_caps, num_caps, caps);
- if (!client->channel_client) {
- goto error2;
- }
-
- /* SndChannelClient is not yet a RedChannelClient, but we still need to go from our
- * RedChannelClient implementation (DummyChannelClient) to the SndChannelClient instance
- * in various vfuncs
- */
- g_object_set_data(G_OBJECT(client->channel_client), "sound-channel-client", client);
-
- if (!snd_channel_config_socket(RED_CHANNEL_CLIENT(client->channel_client))) {
- goto error2;
- }
-
- return client;
-
-error2:
- free(client);
- reds_stream_free(stream);
- return NULL;
-}
-
/* This function is called when the "persistent" item is removed from the
* queue. Note that there is not free call as the item is allocated into
* SndChannelClient.
@@ -729,7 +726,7 @@ static void snd_send(SndChannelClient * client)
static void playback_channel_send_item(RedChannelClient *rcc, G_GNUC_UNUSED RedPipeItem *item)
{
SndChannelClient *client = snd_channel_client_from_dummy(rcc);
- PlaybackChannelClient *playback_client = SPICE_CONTAINEROF(client, PlaybackChannelClient, base);
+ PlaybackChannelClient *playback_client = PLAYBACK_CHANNEL_CLIENT(client);
client->command &= SND_PLAYBACK_MODE_MASK|SND_PLAYBACK_PCM_MASK|
SND_CTRL_MASK|SND_VOLUME_MUTE_MASK|
@@ -788,7 +785,7 @@ static void playback_channel_send_item(RedChannelClient *rcc, G_GNUC_UNUSED RedP
static void record_channel_send_item(RedChannelClient *rcc, G_GNUC_UNUSED RedPipeItem *item)
{
SndChannelClient *client = snd_channel_client_from_dummy(rcc);
- RecordChannelClient *record_client = SPICE_CONTAINEROF(client, RecordChannelClient, base);
+ RecordChannelClient *record_client = RECORD_CHANNEL_CLIENT(client);
client->command &= SND_CTRL_MASK|SND_VOLUME_MUTE_MASK|SND_MIGRATE_MASK;
while (client->command) {
@@ -985,7 +982,7 @@ SPICE_GNUC_VISIBLE void spice_server_playback_stop(SpicePlaybackInstance *sin)
sin->st->channel.active = 0;
if (!client)
return;
- PlaybackChannelClient *playback_client = SPICE_CONTAINEROF(client, PlaybackChannelClient, base);
+ PlaybackChannelClient *playback_client = PLAYBACK_CHANNEL_CLIENT(client);
spice_assert(client->active);
reds_enable_mm_time(snd_channel_get_server(client));
client->active = FALSE;
@@ -1015,7 +1012,7 @@ SPICE_GNUC_VISIBLE void spice_server_playback_get_buffer(SpicePlaybackInstance *
if (!client) {
return;
}
- PlaybackChannelClient *playback_client = SPICE_CONTAINEROF(client, PlaybackChannelClient, base);
+ PlaybackChannelClient *playback_client = PLAYBACK_CHANNEL_CLIENT(client);
if (!playback_client->free_frames) {
return;
}
@@ -1118,10 +1115,12 @@ static void on_new_playback_channel_client(SndChannel *channel, SndChannelClient
}
}
-static void snd_playback_cleanup(SndChannelClient *client)
+static void
+playback_channel_client_finalize(GObject *object)
{
- PlaybackChannelClient *playback_client = SPICE_CONTAINEROF(client, PlaybackChannelClient, base);
int i;
+ PlaybackChannelClient *playback_client = PLAYBACK_CHANNEL_CLIENT(object);
+ SndChannelClient *client = SND_CHANNEL_CLIENT(playback_client);
// free frames, unref them
for (i = 0; i < NUM_AUDIO_FRAMES; ++i) {
@@ -1136,41 +1135,42 @@ static void snd_playback_cleanup(SndChannelClient *client)
}
snd_codec_destroy(&playback_client->codec);
+
+ G_OBJECT_CLASS(playback_channel_client_parent_class)->finalize(object);
}
-static void snd_set_playback_peer(RedChannel *red_channel, RedClient *client, RedsStream *stream,
- G_GNUC_UNUSED int migration,
- int num_common_caps, uint32_t *common_caps,
- int num_caps, uint32_t *caps)
+static void
+playback_channel_client_constructed(GObject *object)
{
+ PlaybackChannelClient *playback_client = PLAYBACK_CHANNEL_CLIENT(object);
+ SndChannelClient *client = SND_CHANNEL_CLIENT(playback_client);
+ RedChannel *red_channel = red_channel_client_get_channel(client->channel_client);
+ RedClient *red_client = red_channel_client_get_client(client->channel_client);
SndChannel *channel = SND_CHANNEL(red_channel);
- PlaybackChannelClient *playback_client;
- snd_disconnect_channel(channel->connection);
+ G_OBJECT_CLASS(playback_channel_client_parent_class)->constructed(object);
- if (!(playback_client = (PlaybackChannelClient *)__new_channel(channel,
- sizeof(*playback_client),
- SPICE_CHANNEL_PLAYBACK,
- client,
- stream,
- snd_playback_on_message_done,
- snd_playback_cleanup,
- common_caps, num_common_caps,
- caps, num_caps))) {
- return;
+ if (!snd_channel_config_socket(RED_CHANNEL_CLIENT(client->channel_client))) {
+ g_warning("failed to set sound channel socket parameters");
}
- snd_playback_alloc_frames(playback_client);
+ /* SndChannelClient is not yet a RedChannelClient, but we still need to go from our
+ * RedChannelClient implementation (DummyChannelClient) to the SndChannelClient instance
+ * in various vfuncs
+ */
+ g_object_set_data(G_OBJECT(client->channel_client), "sound-channel-client", client);
- int client_can_celt = red_channel_client_test_remote_cap(playback_client->base.channel_client,
+ SND_CHANNEL_CLIENT(playback_client)->on_message_done = snd_playback_on_message_done;
+
+ RedChannelClient *rcc = client->channel_client;
+ int client_can_celt = red_channel_client_test_remote_cap(rcc,
SPICE_PLAYBACK_CAP_CELT_0_5_1);
- int client_can_opus = red_channel_client_test_remote_cap(playback_client->base.channel_client,
+ int client_can_opus = red_channel_client_test_remote_cap(rcc,
SPICE_PLAYBACK_CAP_OPUS);
int playback_compression =
reds_config_get_playback_compression(red_channel_get_server(red_channel));
int desired_mode = snd_desired_audio_mode(playback_compression, channel->frequency,
client_can_celt, client_can_opus);
- playback_client->mode = SPICE_AUDIO_DATA_MODE_RAW;
if (desired_mode != SPICE_AUDIO_DATA_MODE_RAW) {
if (snd_codec_create(&playback_client->codec, desired_mode, channel->frequency,
SND_CODEC_ENCODE) == SND_CODEC_OK) {
@@ -1180,7 +1180,7 @@ static void snd_set_playback_peer(RedChannel *red_channel, RedClient *client, Re
}
}
- if (!red_client_during_migrate_at_target(client)) {
+ if (!red_client_during_migrate_at_target(red_client)) {
on_new_playback_channel_client(channel, SND_CHANNEL_CLIENT(playback_client));
}
@@ -1190,6 +1190,28 @@ static void snd_set_playback_peer(RedChannel *red_channel, RedClient *client, Re
snd_send(channel->connection);
}
+static void snd_set_playback_peer(RedChannel *red_channel, RedClient *client, RedsStream *stream,
+ G_GNUC_UNUSED int migration,
+ int num_common_caps, uint32_t *common_caps,
+ int num_caps, uint32_t *caps)
+{
+ SndChannel *channel = SND_CHANNEL(red_channel);
+ PlaybackChannelClient *playback_client;
+
+ snd_disconnect_channel(channel->connection);
+
+ RedChannelClient *rcc =
+ dummy_channel_client_create(red_channel, client, stream,
+ num_common_caps, common_caps,
+ num_caps, caps);
+ playback_client = g_object_new(TYPE_PLAYBACK_CHANNEL_CLIENT, "channel-client", rcc, NULL);
+ g_object_unref(rcc);
+ g_warn_if_fail(playback_client != NULL);
+ /* FIXME: stream used to be destroyed (reds_stream_free) on failure to create the initable,
+ * is it still the case
+ */
+}
+
static void snd_record_migrate_channel_client(RedChannelClient *rcc)
{
SndChannel *channel;
@@ -1244,7 +1266,7 @@ static void snd_record_start(SndChannel *channel)
channel->active = 1;
if (!client)
return;
- RecordChannelClient *record_client = SPICE_CONTAINEROF(client, RecordChannelClient, base);
+ RecordChannelClient *record_client = RECORD_CHANNEL_CLIENT(client);
spice_assert(!client->active);
record_client->read_pos = record_client->write_pos = 0; //todo: improve by
//stream generation
@@ -1289,7 +1311,7 @@ SPICE_GNUC_VISIBLE uint32_t spice_server_record_get_samples(SpiceRecordInstance
if (!client)
return 0;
- RecordChannelClient *record_client = SPICE_CONTAINEROF(client, RecordChannelClient, base);
+ RecordChannelClient *record_client = RECORD_CHANNEL_CLIENT(client);
spice_assert(client->active);
if (record_client->write_pos < RECORD_SAMPLES_SIZE / 2) {
@@ -1363,10 +1385,41 @@ static void on_new_record_channel_client(SndChannel *channel, SndChannelClient *
}
}
-static void snd_record_cleanup(SndChannelClient *client)
+static void
+record_channel_client_finalize(GObject *object)
{
- RecordChannelClient *record_client = SPICE_CONTAINEROF(client, RecordChannelClient, base);
+ RecordChannelClient *record_client = RECORD_CHANNEL_CLIENT(object);
+
snd_codec_destroy(&record_client->codec);
+
+ G_OBJECT_CLASS(record_channel_client_parent_class)->finalize(object);
+}
+
+static void
+record_channel_client_constructed(GObject *object)
+{
+ RecordChannelClient *record_client = RECORD_CHANNEL_CLIENT(object);
+ SndChannelClient *client = SND_CHANNEL_CLIENT(record_client);
+ RedChannel *red_channel = red_channel_client_get_channel(client->channel_client);
+ SndChannel *channel = SND_CHANNEL(red_channel);
+
+ G_OBJECT_CLASS(record_channel_client_parent_class)->constructed(object);
+
+ if (!snd_channel_config_socket(RED_CHANNEL_CLIENT(client->channel_client))) {
+ g_warning("failed to set sound channel socket parameters");
+ }
+
+ /* SndChannelClient is not yet a RedChannelClient, but we still need to go from our
+ * RedChannelClient implementation (DummyChannelClient) to the SndChannelClient instance
+ * in various vfuncs
+ */
+ g_object_set_data(G_OBJECT(client->channel_client), "sound-channel-client", client);
+
+ on_new_record_channel_client(channel, SND_CHANNEL_CLIENT(record_client));
+ if (channel->active) {
+ snd_record_start(channel);
+ }
+ snd_send(channel->connection);
}
static void snd_set_record_peer(RedChannel *red_channel, RedClient *client, RedsStream *stream,
@@ -1379,27 +1432,16 @@ static void snd_set_record_peer(RedChannel *red_channel, RedClient *client, Reds
snd_disconnect_channel(channel->connection);
- if (!(record_client = (RecordChannelClient *)__new_channel(channel,
- sizeof(*record_client),
- SPICE_CHANNEL_RECORD,
- client,
- stream,
- snd_record_on_message_done,
- snd_record_cleanup,
- common_caps, num_common_caps,
- caps, num_caps))) {
- return;
- }
-
- record_client->mode = SPICE_AUDIO_DATA_MODE_RAW;
-
- on_new_record_channel_client(channel, SND_CHANNEL_CLIENT(record_client));
- if (channel->active) {
- snd_record_start(channel);
- }
- snd_send(channel->connection);
+ RedChannelClient *rcc =
+ dummy_channel_client_create(red_channel, client, stream,
+ num_common_caps, common_caps,
+ num_caps, caps);
+ record_client = g_object_new(TYPE_RECORD_CHANNEL_CLIENT, "channel-client", rcc, NULL);
+ g_object_unref(rcc);
+ g_warn_if_fail(record_client != NULL);
}
+
static void snd_playback_migrate_channel_client(RedChannelClient *rcc)
{
SndChannel *channel;
@@ -1588,9 +1630,10 @@ void snd_set_playback_compression(int on)
g_object_get(RED_CHANNEL(now), "channel-type", &type, NULL);
if (type == SPICE_CHANNEL_PLAYBACK && now->connection) {
PlaybackChannelClient* playback = (PlaybackChannelClient*)now->connection;
- int client_can_celt = red_channel_client_test_remote_cap(playback->base.channel_client,
+ RedChannelClient *rcc = SND_CHANNEL_CLIENT(playback)->channel_client;
+ int client_can_celt = red_channel_client_test_remote_cap(rcc,
SPICE_PLAYBACK_CAP_CELT_0_5_1);
- int client_can_opus = red_channel_client_test_remote_cap(playback->base.channel_client,
+ int client_can_opus = red_channel_client_test_remote_cap(rcc,
SPICE_PLAYBACK_CAP_OPUS);
int desired_mode = snd_desired_audio_mode(on, now->frequency,
client_can_opus, client_can_celt);
@@ -1602,6 +1645,36 @@ void snd_set_playback_compression(int on)
}
}
+static void
+snd_channel_client_class_init(SndChannelClientClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ GParamSpec *spec;
+
+ object_class->set_property = snd_channel_client_set_property;
+
+ spec = g_param_spec_object("channel-client", "channel-client",
+ "Associated dummy RedChannelClient",
+ RED_TYPE_CHANNEL_CLIENT,
+ G_PARAM_STATIC_STRINGS
+ | G_PARAM_WRITABLE
+ | G_PARAM_CONSTRUCT_ONLY);
+ g_object_class_install_property(object_class, PROP_CHANNEL_CLIENT, spec);
+}
+
+static void
+snd_channel_client_init(SndChannelClient *self)
+{
+}
+
+static void
+playback_channel_client_class_init(PlaybackChannelClientClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ object_class->constructed = playback_channel_client_constructed;
+ object_class->finalize = playback_channel_client_finalize;
+}
+
static void snd_playback_alloc_frames(PlaybackChannelClient *playback)
{
int i;
@@ -1613,3 +1686,24 @@ static void snd_playback_alloc_frames(PlaybackChannelClient *playback)
snd_playback_free_frame(playback, &playback->frames->items[i]);
}
}
+
+static void
+playback_channel_client_init(PlaybackChannelClient *playback)
+{
+ playback->mode = SPICE_AUDIO_DATA_MODE_RAW;
+ snd_playback_alloc_frames(playback);
+}
+
+static void
+record_channel_client_class_init(RecordChannelClientClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ object_class->constructed = record_channel_client_constructed;
+ object_class->finalize = record_channel_client_finalize;
+}
+
+static void
+record_channel_client_init(RecordChannelClient *record)
+{
+ record->mode = SPICE_AUDIO_DATA_MODE_RAW;
+}
--
2.9.3
More information about the Spice-devel
mailing list