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 <fzig...@redhat.com> Signed-off-by: Christophe Fergeau <cferg...@redhat.com> --- server/sound.c | 325 +++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 210 insertions(+), 115 deletions(-) diff --git a/server/sound.c b/server/sound.c index b629377..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,48 +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); - 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. @@ -728,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| @@ -787,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) { @@ -984,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; @@ -1014,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; } @@ -1117,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) { @@ -1135,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) { @@ -1179,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)); } @@ -1189,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; @@ -1243,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 @@ -1288,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) { @@ -1362,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, @@ -1378,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; @@ -1587,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); @@ -1601,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; @@ -1612,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 _______________________________________________ Spice-devel mailing list Spice-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/spice-devel