[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