[Spice-devel] [vdagent-linux PATCH v2 1/2] audio: add functions to set volume/mute with alsa
Marc-André Lureau
mlureau at redhat.com
Mon Mar 23 06:28:03 PDT 2015
Hi
----- Original Message -----
> This patch includes the vdagentd-audio.[ch] files in order to
> communicate with backend audio server.
>
> The two functions provide a way to set volume and mute in the guest
> by connecting to default mixer control in alsa which is 'Master' for
> playback and 'Capture' for record.
> ---
> Makefile.am | 6 +-
> configure.ac | 1 +
> src/vdagentd-audio.c | 160
> +++++++++++++++++++++++++++++++++++++++++++++++++++
> src/vdagentd-audio.h | 27 +++++++++
> 4 files changed, 192 insertions(+), 2 deletions(-)
> create mode 100644 src/vdagentd-audio.c
> create mode 100644 src/vdagentd-audio.h
>
> diff --git a/Makefile.am b/Makefile.am
> index 510f460..d789cc1 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -9,11 +9,12 @@ src_spice_vdagent_LDADD = $(X_LIBS) $(SPICE_LIBS)
> $(GLIB2_LIBS)
> src_spice_vdagent_SOURCES = src/vdagent.c src/vdagent-x11.c
> src/vdagent-x11-randr.c src/vdagent-file-xfers.c src/udscs.c
>
> src_spice_vdagentd_CFLAGS = $(DBUS_CFLAGS) $(LIBSYSTEMD_LOGIN_CFLAGS) \
> - $(PCIACCESS_CFLAGS) $(SPICE_CFLAGS) $(GLIB2_CFLAGS) $(PIE_CFLAGS)
> + $(PCIACCESS_CFLAGS) $(SPICE_CFLAGS) $(GLIB2_CFLAGS) $(PIE_CFLAGS)
> $(ALSA_CFLAGS)
> src_spice_vdagentd_LDADD = $(DBUS_LIBS) $(LIBSYSTEMD_LOGIN_LIBS) \
> - $(PCIACCESS_LIBS) $(SPICE_LIBS) $(GLIB2_LIBS) $(PIE_LDFLAGS)
> + $(PCIACCESS_LIBS) $(SPICE_LIBS) $(GLIB2_LIBS) $(PIE_LDFLAGS) $(ALSA_LIBS)
> src_spice_vdagentd_SOURCES = src/vdagentd.c \
> src/vdagentd-uinput.c \
> + src/vdagentd-audio.c \
> src/vdagentd-xorg-conf.c \
> src/vdagent-virtio-port.c \
> src/udscs.c
> @@ -37,6 +38,7 @@ noinst_HEADERS = src/glib-compat.h \
> src/vdagentd-proto.h \
> src/vdagentd-proto-strings.h \
> src/vdagentd-uinput.h \
> + src/vdagentd-audio.h \
> src/vdagentd-xorg-conf.h
>
> xdgautostartdir = $(sysconfdir)/xdg/autostart
> diff --git a/configure.ac b/configure.ac
> index 79905a8..b011358 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -79,6 +79,7 @@ AC_ARG_ENABLE([static-uinput],
> PKG_CHECK_MODULES([GLIB2], [glib-2.0 >= 2.12])
> PKG_CHECK_MODULES(X, [xfixes xrandr >= 1.3 xinerama x11])
> PKG_CHECK_MODULES(SPICE, [spice-protocol >= 0.12.5])
> +PKG_CHECK_MODULES(ALSA, [alsa >= 1.0.22])
>
> if test "$with_session_info" = "auto" || test "$with_session_info" =
> "systemd"; then
> PKG_CHECK_MODULES([LIBSYSTEMD_LOGIN],
> diff --git a/src/vdagentd-audio.c b/src/vdagentd-audio.c
> new file mode 100644
> index 0000000..6e43e27
> --- /dev/null
> +++ b/src/vdagentd-audio.c
> @@ -0,0 +1,160 @@
> +/* vdagentd-audio.c vdagentd audio handling code
> +
> + Copyright 2015 Red Hat, Inc.
> +
> + This program is free software: you can redistribute it and/or modify
> + it under the terms of the GNU General Public License as published by
> + the Free Software Foundation, either version 3 of the License, or
> + (at your option) any later version.
> +
> + This program is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + GNU General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with this program. If not, see <http://www.gnu.org/licenses/>.
> +*/
> +
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#include <syslog.h>
> +#include <stdbool.h>
> +#include <alsa/asoundlib.h>
> +#include <alsa/mixer.h>
> +#include <alsa/error.h>
> +#include "vdagentd-audio.h"
> +
> +#define CLAMP(x,a,b) ((x)<(a) ? (a) : ((x)>(b) ? (b) : (x)))
You should #include <glib.h> instead.
> +
> +static snd_mixer_elem_t *
> +alsa_get_default_mixer_by_name(snd_mixer_t **handle, const char *name)
> +{
> + snd_mixer_selem_id_t *sid;
> + int err = 0;
> +
> + if ((err = snd_mixer_open(handle, 0)) < 0)
> + goto fail;
> +
> + if ((err = snd_mixer_attach(*handle, "default")) < 0)
> + goto fail;
> +
> + if ((err = snd_mixer_selem_register(*handle, NULL, NULL)) < 0)
> + goto fail;
> +
> + if ((err = snd_mixer_load(*handle)) < 0)
> + goto fail;
> +
> + snd_mixer_selem_id_alloca(&sid);
> + snd_mixer_selem_id_set_index(sid, 0);
> + snd_mixer_selem_id_set_name(sid, name);
> + return snd_mixer_find_selem(*handle, sid);
> +
> +fail:
> + syslog(LOG_WARNING, "%s fail: %s", __func__, snd_strerror(err));
> + return NULL;
> +}
> +
> +static bool alsa_set_capture(uint8_t mute, uint8_t nchannels, uint16_t
> *volume)
> +{
> + snd_mixer_t *handle = NULL;
> + snd_mixer_elem_t *e;
> + long min, max, vol;
> + bool ret = true;
> +
> + e = alsa_get_default_mixer_by_name (&handle, "Capture");
> + if (e == NULL) {
> + syslog(LOG_WARNING, "vdagentd-audio: can't get default alsa mixer");
> + ret = false;
> + goto end;
> + }
> +
> + snd_mixer_selem_get_capture_volume_range(e, &min, &max);
> +
> + switch (nchannels) {
> + case 1: /* MONO */
> + vol = (mute) ? min : CLAMP(volume[0], min, max);
> + snd_mixer_selem_set_capture_volume(e, SND_MIXER_SCHN_MONO, vol);
> + syslog(LOG_DEBUG, "vdagentd-audio: (capture-mono) %lu (%%%0.2f)",
> + vol, (float) (100*vol/max));
> + break;
> + case 2: /* LEFT-RIGHT */
> + vol = (mute) ? min : CLAMP(volume[0], min, max);
> + snd_mixer_selem_set_capture_volume(e, SND_MIXER_SCHN_FRONT_LEFT,
> vol);
> + syslog(LOG_DEBUG, "vdagentd-audio: (capture-left) %lu (%%%0.2f)",
> + vol, (float) (100*vol/max));
> + vol = (mute) ? min : CLAMP(volume[1], min, max);
> + snd_mixer_selem_set_capture_volume(e, SND_MIXER_SCHN_FRONT_RIGHT,
> vol);
> + syslog(LOG_DEBUG, "vdagentd-audio: (capture-right) %lu (%%%0.2f)",
> + vol, (float) (100*vol/max));
> + break;
> + default:
> + syslog(LOG_WARNING, "vdagentd-audio: number of channels not
> supported");
> + ret = false;
> + }
> +end:
> + if (handle != NULL)
> + snd_mixer_close(handle);
> + return ret;
> +}
> +
> +static bool alsa_set_playback (uint8_t mute, uint8_t nchannels, uint16_t
> *volume)
> +{
> + snd_mixer_t *handle = NULL;
> + snd_mixer_elem_t* e;
> + long min, max, vol;
> + bool ret = true;
> +
> + e = alsa_get_default_mixer_by_name (&handle, "Master");
> + if (e == NULL) {
> + syslog(LOG_WARNING, "vdagentd-audio: can't get default alsa mixer");
> + ret = false;
> + goto end;
> + }
> +
> + snd_mixer_selem_get_playback_volume_range(e, &min, &max);
> +
> + switch (nchannels) {
> + case 1: /* MONO */
> + vol = (mute) ? min : CLAMP(volume[0], min, max);
It probably doesn't make a big difference, but why did you not set mute?
> + snd_mixer_selem_set_playback_volume(e, SND_MIXER_SCHN_MONO, vol);
> + syslog(LOG_DEBUG, "vdagentd-audio: (playback-mono) %lu (%%%0.2f)",
> + vol, (float) (100*vol/max));
> + break;
> + case 2: /* LEFT-RIGHT */
> + vol = (mute) ? min : CLAMP(volume[0], min, max);
> + snd_mixer_selem_set_playback_volume(e, SND_MIXER_SCHN_FRONT_LEFT,
> vol);
> + syslog(LOG_DEBUG, "vdagentd-audio: (playback-left) %lu (%%%0.2f)",
> + vol, (float) (100*vol/max));
> + vol = (mute) ? min : CLAMP(volume[1], min, max);
> + snd_mixer_selem_set_playback_volume(e, SND_MIXER_SCHN_FRONT_RIGHT,
> vol);
> + syslog(LOG_DEBUG, "vdagentd-audio: (playback-right) %lu (%%%0.2f)",
> + vol, (float) (100*vol/max));
> + break;
> + default:
> + syslog(LOG_WARNING, "vdagentd-audio: number of channels not
> supported");
> + ret = false;
> + }
> +end:
> + if (handle != NULL)
> + snd_mixer_close(handle);
> + return ret;
> +}
> +
> +void vdagent_audio_playback_sync(uint8_t mute, uint8_t nchannels, uint16_t
> *volume)
> +{
> + syslog(LOG_DEBUG, "%s mute=%s nchannels=%u",
> + __func__, (mute) ? "yes" : "no", nchannels);
> + if (alsa_set_playback (mute, nchannels, volume) == false)
> + syslog(LOG_WARNING, "Fail to sync playback volume");
> +}
> +
> +void vdagent_audio_record_sync(uint8_t mute, uint8_t nchannels, uint16_t
> *volume)
> +{
> + syslog(LOG_DEBUG, "%s mute=%s nchannels=%u",
> + __func__, (mute) ? "yes" : "no", nchannels);
> + if (alsa_set_capture (mute, nchannels, volume) == false)
> + syslog(LOG_WARNING, "Fail to sync record volume");
> +}
> diff --git a/src/vdagentd-audio.h b/src/vdagentd-audio.h
> new file mode 100644
> index 0000000..950827a
> --- /dev/null
> +++ b/src/vdagentd-audio.h
> @@ -0,0 +1,27 @@
> +/* vdagentd-audio.h vdagentd audio handling header
> +
> + Copyright 2015 Red Hat, Inc.
> +
> + This program is free software: you can redistribute it and/or modify
> + it under the terms of the GNU General Public License as published by
> + the Free Software Foundation, either version 3 of the License, or
> + (at your option) any later version.
> +
> + This program is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + GNU General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with this program. If not, see <http://www.gnu.org/licenses/>.
> +*/
> +#ifndef __VDAGENTD_AUDIO_H
> +#define __VDAGENTD_AUDIO_H
> +
> +#include <stdio.h>
> +#include <stdint.h>
> +
> +void vdagent_audio_playback_sync(uint8_t mute, uint8_t nchannels, uint16_t
> *volume);
> +void vdagent_audio_record_sync(uint8_t mute, uint8_t nchannels, uint16_t
> *volume);
> +
> +#endif
Assuming this has been testing under valgrind with no memory error/leak, it looks good to me.
(I'd first get the protocol bits ack before pushing this)
More information about the Spice-devel
mailing list