> > 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@xxxxxxxxxx> > > Signed-off-by: Christophe Fergeau <cfergeau@xxxxxxxxxx> IMO this patch is too artificial, I would merge to 10/10 Frediano > --- > 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; > +} _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/spice-devel