/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set et sw=2 ts=2: */ /*************************************************************************** * mixer.cc * * Tue Sep 23 14:38:54 CEST 2014 * Copyright 2014 Bent Bisballe Nyeng * deva@aasimon.org ****************************************************************************/ /* * This file is part of LibAudioIO. * * LibAudioIO is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * LibAudioIO 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with LibAudioIO; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "mixer.h" #include #include #define fERROR (strtof("-INF", NULL)) Mixer::Mixer(snd_mixer_t *handle, snd_mixer_elem_t *elem) { this->handle = handle; this->elem = elem; } Mixer::~Mixer() { if(handle) snd_mixer_close(handle); } snd_mixer_selem_channel_id_t Mixer::chanId(int idx) { int num = 0; for(int ichn = 0; ichn <= (int)SND_MIXER_SCHN_LAST; ichn++) { snd_mixer_selem_channel_id_t chn = (snd_mixer_selem_channel_id_t)ichn; if(!snd_mixer_selem_has_capture_channel(elem, chn) && !snd_mixer_selem_has_playback_channel(elem, chn)) continue; if(idx == num) return chn; num++; } return SND_MIXER_SCHN_UNKNOWN; } int Mixer::numberOfChannels() { int num = 0; for(int ichn = 0; ichn <= (int)SND_MIXER_SCHN_LAST; ichn++) { snd_mixer_selem_channel_id_t chn = (snd_mixer_selem_channel_id_t)ichn; if(!snd_mixer_selem_has_capture_channel(elem, chn) && !snd_mixer_selem_has_playback_channel(elem, chn)) continue; num++; } return num; } bool Mixer::isCapture() { return snd_mixer_selem_has_capture_volume(elem) || snd_mixer_selem_has_capture_switch(elem); } bool Mixer::isPlayback() { return snd_mixer_selem_has_playback_volume(elem); } bool Mixer::isEnum() { return snd_mixer_selem_is_enumerated(elem); } void Mixer::setEnumValue(std::string value) { if(!isEnum()) return; int i, items; char itemname[40]; // TODO: Always MONO for enums? snd_mixer_selem_channel_id_t channel_id = SND_MIXER_SCHN_MONO; items = snd_mixer_selem_get_enum_items(elem); for (i = 0; i < items; i++) { snd_mixer_selem_get_enum_item_name(elem, i, sizeof(itemname) - 1, itemname); if(value == itemname) { snd_mixer_selem_set_enum_item(elem, channel_id, i); return; } } } std::string Mixer::enumValue() { if(!isEnum()) return ""; unsigned int idx; char itemname[40]; // TODO: Always MONO for enums? snd_mixer_selem_channel_id_t channel_id = SND_MIXER_SCHN_MONO; if(!snd_mixer_selem_get_enum_item(elem, channel_id, &idx)) { snd_mixer_selem_get_enum_item_name(elem, idx, sizeof(itemname) - 1, itemname); return itemname; } return ""; } std::vector Mixer::enumValues() { std::vector values; if(!isEnum()) return values; int i, items; char itemname[40]; items = snd_mixer_selem_get_enum_items(elem); for (i = 0; i < items; i++) { snd_mixer_selem_get_enum_item_name(elem, i, sizeof(itemname) - 1, itemname); values.push_back(itemname); } return values; } int Mixer::setLevel(int channel, float level) { int err; long int value = level * 100; // dir: -1 := exact or first below // 0 := exact (error if not?) // 1 := exact or first above int dir = 1; if(isCapture()) { err = snd_mixer_selem_set_capture_dB(elem, chanId(channel), value, dir); if(err) { printf("snd_mixer_selem_set_capture_dB: %s, %d\n", snd_strerror(err), err); return 1; } } if(isPlayback()) { err = snd_mixer_selem_set_playback_dB(elem, chanId(channel), value, dir); if(err) { printf("snd_mixer_selem_set_playback_dB: %s, %d\n", snd_strerror(err), err); return 1; } } return 0; } float Mixer::level(int channel) { int err; long int value; if(isCapture()) { err = snd_mixer_selem_get_capture_dB(elem, chanId(channel), &value); if(err) { printf("snd_mixer_selem_get_capture_dB: %s, %d\n", snd_strerror(err), err); return fERROR; } } else if(isPlayback()) { err = snd_mixer_selem_get_playback_dB(elem, chanId(channel), &value); if(err) { printf("snd_mixer_selem_get_playback_dB: %s, %d\n", snd_strerror(err), err); return fERROR; } } else { return fERROR; } return (float)value / 100.0; } Mixer::range_t Mixer::range() { Mixer::range_t range; int err; long int lvl_min, lvl_max; if(isCapture()) { err = snd_mixer_selem_get_capture_dB_range(elem, &lvl_min, &lvl_max); if(err) { printf("snd_mixer_selem_get_capture_dB_range: %s, %d\n", snd_strerror(err), err); } } else if(isPlayback()) { err = snd_mixer_selem_get_playback_dB_range(elem, &lvl_min, &lvl_max); if(err) { printf("snd_mixer_selem_get_playback_dB_range: %s, %d\n", snd_strerror(err), err); } } else { range.min = fERROR; range.max = fERROR; return range; } range.min = (float)lvl_min / 100.0; range.max = (float)lvl_max / 100.0; return range; } void Mixer::setCapture(bool capture) { if(!isCapture()) return; int c = capture?1:0; int err; err = snd_mixer_selem_set_capture_switch_all(elem, c); if(err) { printf("snd_mixer_selem_set_capture_switch_all: %s, %d\n", snd_strerror(err), err); } } bool Mixer::capture() { if(!isCapture()) return false; int err; int num = numberOfChannels(); for(int idx = 0; idx < num; idx++) { int value; err = snd_mixer_selem_get_capture_switch(elem, chanId(idx), &value); if(err) { printf(" snd_mixer_selem_get_capture_switch: %s, %d\n", snd_strerror(err), err); return false; } if(value == 0) return false; } return true; } void Mixer::setMuted(bool muted) { if(!isPlayback()) return; int p = muted?0:1; int err; err = snd_mixer_selem_set_playback_switch_all(elem, p); if(err) { printf("snd_mixer_selem_set_playback_switch_all: %s, %d\n", snd_strerror(err), err); } } bool Mixer::muted() { if(!isPlayback()) return false; int err; int num = numberOfChannels(); for(int idx = 0; idx < num; idx++) { int value; err = snd_mixer_selem_get_playback_switch(elem, chanId(idx), &value); if(err) { printf(" snd_mixer_selem_get_playback_switch: %s, %d\n", snd_strerror(err), err); return true; } if(value == 0) return true; } return false; }