/* vdagent-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 .
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include
#include
#include
#include
#include
#include "vdagent-audio.h"
#define ALSA_MUTE 0
#define ALSA_UNMUTE 1
static snd_mixer_elem_t *
get_alsa_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 set_alsa_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;
int alsa_mute;
e = get_alsa_default_mixer_by_name (&handle, "Capture");
if (e == NULL) {
syslog(LOG_WARNING, "vdagent-audio: can't get default alsa mixer");
ret = false;
goto end;
}
alsa_mute = (mute) ? ALSA_MUTE : ALSA_UNMUTE;
snd_mixer_selem_set_capture_switch_all(e, alsa_mute);
snd_mixer_selem_get_capture_volume_range(e, &min, &max);
switch (nchannels) {
case 1: /* MONO */
vol = CLAMP(volume[0], min, max);
snd_mixer_selem_set_capture_volume(e, SND_MIXER_SCHN_MONO, vol);
syslog(LOG_DEBUG, "vdagent-audio: (capture-mono) %lu (%%%0.2f)",
vol, (float) (100*vol/max));
break;
case 2: /* LEFT-RIGHT */
vol = CLAMP(volume[0], min, max);
snd_mixer_selem_set_capture_volume(e, SND_MIXER_SCHN_FRONT_LEFT, vol);
syslog(LOG_DEBUG, "vdagent-audio: (capture-left) %lu (%%%0.2f)",
vol, (float) (100*vol/max));
vol = CLAMP(volume[1], min, max);
snd_mixer_selem_set_capture_volume(e, SND_MIXER_SCHN_FRONT_RIGHT, vol);
syslog(LOG_DEBUG, "vdagent-audio: (capture-right) %lu (%%%0.2f)",
vol, (float) (100*vol/max));
break;
default:
syslog(LOG_WARNING, "vdagent-audio: number of channels not supported");
ret = false;
}
end:
if (handle != NULL)
snd_mixer_close(handle);
return ret;
}
static bool set_alsa_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;
int alsa_mute;
e = get_alsa_default_mixer_by_name (&handle, "Master");
if (e == NULL) {
syslog(LOG_WARNING, "vdagent-audio: can't get default alsa mixer");
ret = false;
goto end;
}
alsa_mute = (mute) ? ALSA_MUTE : ALSA_UNMUTE;
snd_mixer_selem_set_playback_switch_all(e, alsa_mute);
snd_mixer_selem_get_playback_volume_range(e, &min, &max);
switch (nchannels) {
case 1: /* MONO */
vol = CLAMP(volume[0], min, max);
snd_mixer_selem_set_playback_volume(e, SND_MIXER_SCHN_MONO, vol);
syslog(LOG_DEBUG, "vdagent-audio: (playback-mono) %lu (%%%0.2f)",
vol, (float) (100*vol/max));
break;
case 2: /* LEFT-RIGHT */
vol = CLAMP(volume[0], min, max);
snd_mixer_selem_set_playback_volume(e, SND_MIXER_SCHN_FRONT_LEFT, vol);
syslog(LOG_DEBUG, "vdagent-audio: (playback-left) %lu (%%%0.2f)",
vol, (float) (100*vol/max));
vol = CLAMP(volume[1], min, max);
snd_mixer_selem_set_playback_volume(e, SND_MIXER_SCHN_FRONT_RIGHT, vol);
syslog(LOG_DEBUG, "vdagent-audio: (playback-right) %lu (%%%0.2f)",
vol, (float) (100*vol/max));
break;
default:
syslog(LOG_WARNING, "vdagent-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 (set_alsa_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 (set_alsa_capture (mute, nchannels, volume) == false)
syslog(LOG_WARNING, "Fail to sync record volume");
}