[Spice-devel] [spice-server v3 07/10] sound: Use RedChannelClient to receive/send data
Frediano Ziglio
fziglio at redhat.com
Thu Jan 26 12:34:05 UTC 2017
>
> You can see that SndChannelClient has much less field
> as the code to read/write from/to client is reused from
> RedChannelClient instead of creating a fake RedChannelClient
> just to make the system happy.
>
> One of the different between the old sound code and all other
> RedChannelClient objects was that the sound channel don't use
> a queue while RedChannelClient use RedPipeItem object. This was
> the main reason why RedChannelClient was not used. To implement
> the old behaviour a "persistent_pipe_item" is used. This RedPipeItem
> will be queued to RedChannelClient (only one!) so signal code we
> have data to send. The {playback,record}_channel_send_item will
> then send the messages to the client using RedChannelClient functions.
> For this reason snd_reset_send_data is replaced by a call to
> red_channel_client_init_send_data and snd_begin_send_message is
> replaced by red_channel_client_begin_send_message.
>
> Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
> Signed-off-by: Christophe Fergeau <cfergeau at redhat.com>
> ---
> server/sound.c | 659
> +++++++++++++++++++++------------------------------------
> 1 file changed, 245 insertions(+), 414 deletions(-)
>
> diff --git a/server/sound.c b/server/sound.c
> index f27a53d..2bb5688 100644
> --- a/server/sound.c
> +++ b/server/sound.c
> @@ -82,8 +82,6 @@ typedef struct AudioFrameContainer AudioFrameContainer;
> typedef struct SpicePlaybackState PlaybackChannel;
> typedef struct SpiceRecordState RecordChannel;
>
> -typedef void (*snd_channel_send_messages_proc)(void *in_channel);
> -typedef int (*snd_channel_handle_message_proc)(SndChannelClient *client,
> size_t size, uint32_t type, void *message);
> typedef void (*snd_channel_on_message_done_proc)(SndChannelClient *client);
> typedef void (*snd_channel_cleanup_channel_proc)(SndChannelClient *client);
>
....
> @@ -994,6 +672,13 @@ static SndChannelClient *__new_channel(SndChannel
> *channel, int size, uint32_t c
> 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;
> }
> @@ -1005,6 +690,135 @@ error2:
> 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.
> + * This is used to have a simple item in RedChannelClient queue but to send
> + * multiple messages in a row if possible.
> + * During realtime sound transmission you usually don't want to queue too
> + * much data or having retransmission preferring instead loosing some
> + * samples.
> + */
> +
I would remove this extra empty line
> +static void snd_persistent_pipe_item_free(struct RedPipeItem *item)
> +{
> + SndChannelClient *client = SPICE_CONTAINEROF(item, SndChannelClient,
> persistent_pipe_item);
> +
> + red_pipe_item_init_full(item, RED_PIPE_ITEM_PERSISTENT,
> + snd_persistent_pipe_item_free);
> +
> + if (client->on_message_done) {
> + client->on_message_done(client);
> + }
> +}
> +
> +static void snd_send(SndChannelClient * client)
> +{
> + RedChannelClient *rcc = client->channel_client;
> +
> + if (!client || !red_channel_client_pipe_is_empty(rcc) ||
> !client->command) {
the !client check here is useless after its use
> + return;
> + }
> + // just append a dummy item and push!
> + red_pipe_item_init_full(&client->persistent_pipe_item,
> RED_PIPE_ITEM_PERSISTENT,
> + snd_persistent_pipe_item_free);
> + red_channel_client_pipe_add_push(rcc, &client->persistent_pipe_item);
> +}
> +
> +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);
> +
> + client->command &= SND_PLAYBACK_MODE_MASK|SND_PLAYBACK_PCM_MASK|
> + SND_CTRL_MASK|SND_VOLUME_MUTE_MASK|
> + SND_MIGRATE_MASK|SND_PLAYBACK_LATENCY_MASK;
> + while (client->command) {
> + if (client->command & SND_PLAYBACK_MODE_MASK) {
> + client->command &= ~SND_PLAYBACK_MODE_MASK;
> + if (playback_send_mode(playback_client)) {
> + break;
> + }
> + }
> + if (client->command & SND_PLAYBACK_PCM_MASK) {
> + spice_assert(!playback_client->in_progress &&
> playback_client->pending_frame);
> + playback_client->in_progress = playback_client->pending_frame;
> + playback_client->pending_frame = NULL;
> + client->command &= ~SND_PLAYBACK_PCM_MASK;
> + if (snd_playback_send_write(playback_client)) {
> + break;
> + }
> + spice_printerr("snd_send_playback_write failed");
> + }
> + if (client->command & SND_CTRL_MASK) {
> + client->command &= ~SND_CTRL_MASK;
> + if (snd_playback_send_ctl(playback_client)) {
> + break;
> + }
> + }
> + if (client->command & SND_VOLUME_MASK) {
> + client->command &= ~SND_VOLUME_MASK;
> + if (snd_playback_send_volume(playback_client)) {
> + break;
> + }
> + }
> + if (client->command & SND_MUTE_MASK) {
> + client->command &= ~SND_MUTE_MASK;
> + if (snd_playback_send_mute(playback_client)) {
> + break;
> + }
> + }
> + if (client->command & SND_MIGRATE_MASK) {
> + client->command &= ~SND_MIGRATE_MASK;
> + if (snd_playback_send_migrate(playback_client)) {
> + break;
> + }
> + }
> + if (client->command & SND_PLAYBACK_LATENCY_MASK) {
> + client->command &= ~SND_PLAYBACK_LATENCY_MASK;
> + if (snd_playback_send_latency(playback_client)) {
> + break;
> + }
> + }
> + }
> + snd_send(client);
> +}
> +
....
Beside that
Acked-by: Frediano Ziglio <fziglio at redhat.com>
Frediano
More information about the Spice-devel
mailing list