[Spice-devel] [PATCH 3/4] sndworker: add AudioVolume/AudioMute messages
Alon Levy
alevy at redhat.com
Wed Jun 22 03:04:26 PDT 2011
On Wed, Jun 22, 2011 at 11:51:36AM +0200, Marc-André Lureau wrote:
> These messages allow the guest to send the audio device volume to the
> client. It uses an arbitrary scale of 16bits, which works good enough
> for now.
>
> Save VolumeState in {Playback,Record}State, so that we can send the
> current volume on channel connection.
>
> Note about future improvements:
> - add exact dB support
> - add client to guest volume change
>
> Updated since v2:
> - bumped record and playback interface minor version to allow
> conditional compilation
> Updated since v1:
> - sync record volume on connection too
> ---
> client/marshallers.h | 2 +
> common/messages.h | 9 +++
> server/snd_worker.c | 173 +++++++++++++++++++++++++++++++++++++++++++++++++-
> server/spice.h | 10 ++-
> spice.proto | 13 ++++
> 5 files changed, 202 insertions(+), 5 deletions(-)
>
> diff --git a/client/marshallers.h b/client/marshallers.h
> index c913a28..47faeff 100644
> --- a/client/marshallers.h
> +++ b/client/marshallers.h
> @@ -26,6 +26,8 @@
> typedef struct {
> void (*msg_SpiceMsgEmpty)(SpiceMarshaller *m, SpiceMsgEmpty *msg);
> void (*msg_SpiceMsgData)(SpiceMarshaller *m, SpiceMsgData *msg);
> + void (*msg_SpiceMsgAudioVolume)(SpiceMarshaller *m, SpiceMsgAudioVolume *msg);
> + void (*msg_SpiceMsgAudioMute)(SpiceMarshaller *m, SpiceMsgAudioMute *msg);
> void (*msgc_ack_sync)(SpiceMarshaller *m, SpiceMsgcAckSync *msg);
> void (*msgc_pong)(SpiceMarshaller *m, SpiceMsgPing *msg);
> void (*msgc_disconnecting)(SpiceMarshaller *m, SpiceMsgDisconnect *msg);
> diff --git a/common/messages.h b/common/messages.h
> index 6fcd8be..8151dc0 100644
> --- a/common/messages.h
> +++ b/common/messages.h
> @@ -369,6 +369,15 @@ typedef struct SpiceMsgcMouseRelease {
> int32_t buttons_state;
> } SpiceMsgcMouseRelease;
>
> +typedef struct SpiceMsgAudioVolume {
> + uint8_t nchannels;
> + uint16_t volume[0];
> +} SpiceMsgAudioVolume;
> +
> +typedef struct SpiceMsgAudioMute {
> + uint8_t mute;
> +} SpiceMsgAudioMute;
> +
> typedef struct SpiceMsgPlaybackMode {
> uint32_t time;
> uint32_t mode; //SPICE_AUDIO_DATA_MODE_?
> diff --git a/server/snd_worker.c b/server/snd_worker.c
> index 8da11e1..e4cefb1 100644
> --- a/server/snd_worker.c
> +++ b/server/snd_worker.c
> @@ -52,20 +52,24 @@ enum PlaybackeCommand {
> SND_PLAYBACK_MODE,
> SND_PLAYBACK_CTRL,
> SND_PLAYBACK_PCM,
> + SND_PLAYBACK_VOLUME,
> };
>
> enum RecordCommand {
> SND_RECORD_MIGRATE,
> SND_RECORD_CTRL,
> + SND_RECORD_VOLUME,
> };
>
> #define SND_PLAYBACK_MIGRATE_MASK (1 << SND_PLAYBACK_MIGRATE)
> #define SND_PLAYBACK_MODE_MASK (1 << SND_PLAYBACK_MODE)
> #define SND_PLAYBACK_CTRL_MASK (1 << SND_PLAYBACK_CTRL)
> #define SND_PLAYBACK_PCM_MASK (1 << SND_PLAYBACK_PCM)
> +#define SND_PLAYBACK_VOLUME_MASK (1 << SND_PLAYBACK_VOLUME)
>
> #define SND_RECORD_MIGRATE_MASK (1 << SND_RECORD_MIGRATE)
> #define SND_RECORD_CTRL_MASK (1 << SND_RECORD_CTRL)
> +#define SND_RECORD_VOLUME_MASK (1 << SND_RECORD_VOLUME)
>
> typedef struct SndChannel SndChannel;
> typedef void (*send_messages_proc)(void *in_channel);
> @@ -141,14 +145,22 @@ struct SndWorker {
> int active;
> };
>
> +typedef struct SpiceVolumeState {
> + uint8_t volume_nchannels;
> + uint16_t *volume;
> + int mute;
> +} SpiceVolumeState;
> +
> struct SpicePlaybackState {
> struct SndWorker worker;
> SpicePlaybackInstance *sin;
> + SpiceVolumeState volume;
> };
>
> struct SpiceRecordState {
> struct SndWorker worker;
> SpiceRecordInstance *sin;
> + SpiceVolumeState volume;
> };
>
> #define RECORD_MIG_VERSION 1
> @@ -193,7 +205,6 @@ static void snd_disconnect_channel(SndChannel *channel)
> channel->stream->watch = NULL;
> reds_stream_free(channel->stream);
> spice_marshaller_destroy(channel->send_data.marshaller);
> - free(channel);
You remove this line here and put it back in the next patch.
> }
>
> static void snd_playback_free_frame(PlaybackChannel *playback_channel, AudioFrame *frame)
> @@ -508,6 +519,54 @@ static int snd_playback_send_migrate(PlaybackChannel *channel)
> return snd_begin_send_message((SndChannel *)channel);
> }
>
> +static int snd_send_volume(SndChannel *channel, SpiceVolumeState *st, int msg)
> +{
> + SpiceMsgAudioVolume *vol;
> + uint8_t c;
> +
> + vol = alloca(sizeof (SpiceMsgAudioVolume) +
> + st->volume_nchannels * sizeof (uint16_t));
> + if (!snd_reset_send_data(channel, msg)) {
> + return FALSE;
> + }
> + vol->nchannels = st->volume_nchannels;
> + for (c = 0; c < st->volume_nchannels; ++c) {
> + vol->volume[c] = st->volume[c];
> + }
> + spice_marshall_SpiceMsgAudioVolume(channel->send_data.marshaller, vol);
> +
> + return snd_begin_send_message(channel);
> +}
> +
> +static int snd_playback_send_volume(PlaybackChannel *playback_channel)
> +{
> + SndChannel *channel = &playback_channel->base;
> + SpicePlaybackState *st = SPICE_CONTAINEROF(channel->worker, SpicePlaybackState, worker);
> +
> + return snd_send_volume(channel, &st->volume, SPICE_MSG_PLAYBACK_VOLUME);
> +}
> +
> +static int snd_send_mute(SndChannel *channel, SpiceVolumeState *st, int msg)
> +{
> + SpiceMsgAudioMute mute;
> +
> + if (!snd_reset_send_data(channel, msg)) {
> + return FALSE;
> + }
> + mute.mute = st->mute;
> + spice_marshall_SpiceMsgAudioMute(channel->send_data.marshaller, &mute);
> +
> + return snd_begin_send_message(channel);
> +}
> +
> +static int snd_playback_send_mute(PlaybackChannel *playback_channel)
> +{
> + SndChannel *channel = &playback_channel->base;
> + SpicePlaybackState *st = SPICE_CONTAINEROF(channel->worker, SpicePlaybackState, worker);
> +
> + return snd_send_mute(channel, &st->volume, SPICE_MSG_PLAYBACK_MUTE);
> +}
> +
> static int snd_playback_send_start(PlaybackChannel *playback_channel)
> {
> SndChannel *channel = (SndChannel *)playback_channel;
> @@ -589,6 +648,22 @@ static int snd_record_send_ctl(RecordChannel *record_channel)
> }
> }
>
> +static int snd_record_send_volume(RecordChannel *record_channel)
> +{
> + SndChannel *channel = &record_channel->base;
> + SpiceRecordState *st = SPICE_CONTAINEROF(channel->worker, SpiceRecordState, worker);
> +
> + return snd_send_volume(channel, &st->volume, SPICE_MSG_RECORD_VOLUME);
> +}
> +
> +static int snd_record_send_mute(RecordChannel *record_channel)
> +{
> + SndChannel *channel = &record_channel->base;
> + SpiceRecordState *st = SPICE_CONTAINEROF(channel->worker, SpiceRecordState, worker);
> +
> + return snd_send_mute(channel, &st->volume, SPICE_MSG_RECORD_MUTE);
> +}
> +
> static int snd_record_send_migrate(RecordChannel *record_channel)
> {
> SndChannel *channel = (SndChannel *)record_channel;
> @@ -704,6 +779,13 @@ static void snd_playback_send(void* data)
> }
> channel->command &= ~SND_PLAYBACK_CTRL_MASK;
> }
> + if (channel->command & SND_PLAYBACK_VOLUME_MASK) {
> + if (!snd_playback_send_volume(playback_channel) ||
> + !snd_playback_send_mute(playback_channel)) {
> + return;
> + }
> + channel->command &= ~SND_PLAYBACK_VOLUME_MASK;
> + }
> if (channel->command & SND_PLAYBACK_MIGRATE_MASK) {
> if (!snd_playback_send_migrate(playback_channel)) {
> return;
> @@ -729,6 +811,13 @@ static void snd_record_send(void* data)
> }
> channel->command &= ~SND_RECORD_CTRL_MASK;
> }
> + if (channel->command & SND_RECORD_VOLUME_MASK) {
> + if (!snd_record_send_volume(record_channel) ||
> + !snd_record_send_mute(record_channel)) {
> + return;
> + }
> + channel->command &= ~SND_RECORD_VOLUME_MASK;
> + }
> if (channel->command & SND_RECORD_MIGRATE_MASK) {
> if (!snd_record_send_migrate(record_channel)) {
> return;
> @@ -823,6 +912,38 @@ static void snd_set_command(SndChannel *channel, uint32_t command)
> channel->command |= command;
> }
>
> +__visible__ void spice_server_playback_set_volume(SpicePlaybackInstance *sin,
> + uint8_t nchannels,
> + uint16_t *volume)
> +{
> + SpiceVolumeState *st = &sin->st->volume;
> + SndChannel *channel = sin->st->worker.connection;
> + PlaybackChannel *playback_channel = SPICE_CONTAINEROF(channel, PlaybackChannel, base);
> +
> + st->volume_nchannels = nchannels;
> + free(st->volume);
> + st->volume = spice_memdup(volume, sizeof(uint16_t) * nchannels);
> +
> + if (!channel)
> + return;
> +
> + snd_playback_send_volume(playback_channel);
> +}
> +
> +__visible__ void spice_server_playback_set_mute(SpicePlaybackInstance *sin, uint8_t mute)
> +{
> + SpiceVolumeState *st = &sin->st->volume;
> + SndChannel *channel = sin->st->worker.connection;
> + PlaybackChannel *playback_channel = SPICE_CONTAINEROF(channel, PlaybackChannel, base);
> +
> + st->mute = mute;
> +
> + if (!channel)
> + return;
> +
> + snd_playback_send_mute(playback_channel);
> +}
> +
> __visible__ void spice_server_playback_start(SpicePlaybackInstance *sin)
> {
> SndChannel *channel = sin->st->worker.connection;
> @@ -919,6 +1040,7 @@ static void on_new_playback_channel(SndWorker *worker)
> if (!playback_channel->base.migrate && playback_channel->base.active) {
> snd_set_command((SndChannel *)playback_channel, SND_PLAYBACK_CTRL_MASK);
> }
> + snd_set_command((SndChannel *)playback_channel, SND_PLAYBACK_VOLUME_MASK);
> if (playback_channel->base.active) {
> reds_disable_mm_timer();
> }
> @@ -1006,6 +1128,38 @@ static void snd_record_migrate(Channel *channel)
> }
> }
>
> +__visible__ void spice_server_record_set_volume(SpiceRecordInstance *sin,
> + uint8_t nchannels,
> + uint16_t *volume)
> +{
> + SpiceVolumeState *st = &sin->st->volume;
> + SndChannel *channel = sin->st->worker.connection;
> + RecordChannel *record_channel = SPICE_CONTAINEROF(channel, RecordChannel, base);
> +
> + st->volume_nchannels = nchannels;
> + free(st->volume);
> + st->volume = spice_memdup(volume, sizeof(uint16_t) * nchannels);
> +
> + if (!channel)
> + return;
> +
> + snd_record_send_volume(record_channel);
> +}
> +
> +__visible__ void spice_server_record_set_mute(SpiceRecordInstance *sin, uint8_t mute)
> +{
> + SpiceVolumeState *st = &sin->st->volume;
> + SndChannel *channel = sin->st->worker.connection;
> + RecordChannel *record_channel = SPICE_CONTAINEROF(channel, RecordChannel, base);
> +
> + st->mute = mute;
> +
> + if (!channel)
> + return;
> +
> + snd_record_send_mute(record_channel);
> +}
> +
> __visible__ void spice_server_record_start(SpiceRecordInstance *sin)
> {
> SndChannel *channel = sin->st->worker.connection;
> @@ -1087,6 +1241,7 @@ static void on_new_record_channel(SndWorker *worker)
> RecordChannel *record_channel = (RecordChannel *)worker->connection;
> ASSERT(record_channel);
>
> + snd_set_command((SndChannel *)record_channel, SND_RECORD_VOLUME_MASK);
> if (!record_channel->base.migrate) {
> if (record_channel->base.active) {
> snd_set_command((SndChannel *)record_channel, SND_RECORD_CTRL_MASK);
> @@ -1242,16 +1397,28 @@ static void snd_detach_common(SndWorker *worker)
> reds_channel_dispose(&worker->base);
> }
>
> +static void spice_playback_state_free(SpicePlaybackState *st)
> +{
> + free(st->volume.volume);
> + free(st);
> +}
> +
> void snd_detach_playback(SpicePlaybackInstance *sin)
> {
> snd_detach_common(&sin->st->worker);
> - free(sin->st);
> + spice_playback_state_free(sin->st);
> +}
> +
> +static void spice_record_state_free(SpiceRecordState *st)
> +{
> + free(st->volume.volume);
> + free(st);
> }
>
> void snd_detach_record(SpiceRecordInstance *sin)
> {
> snd_detach_common(&sin->st->worker);
> - free(sin->st);
> + spice_record_state_free(sin->st);
> }
>
> void snd_set_playback_compression(int on)
> diff --git a/server/spice.h b/server/spice.h
> index 425d586..f64ff41 100644
> --- a/server/spice.h
> +++ b/server/spice.h
> @@ -268,7 +268,7 @@ struct SpiceTabletInstance {
>
> #define SPICE_INTERFACE_PLAYBACK "playback"
> #define SPICE_INTERFACE_PLAYBACK_MAJOR 1
> -#define SPICE_INTERFACE_PLAYBACK_MINOR 1
> +#define SPICE_INTERFACE_PLAYBACK_MINOR 2
> typedef struct SpicePlaybackInterface SpicePlaybackInterface;
> typedef struct SpicePlaybackInstance SpicePlaybackInstance;
> typedef struct SpicePlaybackState SpicePlaybackState;
> @@ -296,10 +296,13 @@ void spice_server_playback_get_buffer(SpicePlaybackInstance *sin,
> uint32_t **samples, uint32_t *nsamples);
> void spice_server_playback_put_samples(SpicePlaybackInstance *sin,
> uint32_t *samples);
> +void spice_server_playback_set_volume(SpicePlaybackInstance *sin,
> + uint8_t nchannels, uint16_t *volume);
> +void spice_server_playback_set_mute(SpicePlaybackInstance *sin, uint8_t mute);
>
> #define SPICE_INTERFACE_RECORD "record"
> #define SPICE_INTERFACE_RECORD_MAJOR 2
> -#define SPICE_INTERFACE_RECORD_MINOR 1
> +#define SPICE_INTERFACE_RECORD_MINOR 2
> typedef struct SpiceRecordInterface SpiceRecordInterface;
> typedef struct SpiceRecordInstance SpiceRecordInstance;
> typedef struct SpiceRecordState SpiceRecordState;
> @@ -321,6 +324,9 @@ void spice_server_record_start(SpiceRecordInstance *sin);
> void spice_server_record_stop(SpiceRecordInstance *sin);
> uint32_t spice_server_record_get_samples(SpiceRecordInstance *sin,
> uint32_t *samples, uint32_t bufsize);
> +void spice_server_record_set_volume(SpiceRecordInstance *sin,
> + uint8_t nchannels, uint16_t *volume);
> +void spice_server_record_set_mute(SpiceRecordInstance *sin, uint8_t mute);
>
> /* char device interfaces */
>
> diff --git a/spice.proto b/spice.proto
> index 6160de1..80c40d4 100644
> --- a/spice.proto
> +++ b/spice.proto
> @@ -926,6 +926,15 @@ enum16 audio_fmt {
> S16,
> };
>
> +message AudioVolume {
> + uint8 nchannels;
> + uint16 volume[nchannels] @end;
> +};
> +
> +message AudioMute {
> + uint8 mute;
> +};
> +
> channel PlaybackChannel : BaseChannel {
> server:
> message {
> @@ -947,6 +956,8 @@ channel PlaybackChannel : BaseChannel {
> } start;
>
> Empty stop;
> + AudioVolume volume;
> + AudioMute mute;
> };
>
> channel RecordChannel : BaseChannel {
> @@ -958,6 +969,8 @@ channel RecordChannel : BaseChannel {
> } start = 101;
>
> Empty stop;
> + AudioVolume volume;
> + AudioMute mute;
> client:
> message {
> uint32 time;
> --
> 1.7.5.2
>
> _______________________________________________
> Spice-devel mailing list
> Spice-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/spice-devel
More information about the Spice-devel
mailing list