/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set et sw=2 ts=2: */ /*************************************************************************** * device.cc * * Wed Sep 24 08:54:47 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 "device.h" Device::Device(std::string device) { card = device; } Device::~Device() { } std::vector Device::mixerNames() { std::vector mlist; int err; snd_mixer_t *handle; snd_mixer_selem_id_t *sid; snd_mixer_elem_t *elem; snd_mixer_selem_id_alloca(&sid); if((err = snd_mixer_open(&handle, 0)) < 0) { printf("Mixer %s open error: %s", card.c_str(), snd_strerror(err)); return mlist; } if((err = snd_mixer_attach(handle, card.c_str())) < 0) { printf("Mixer attach %s error: %s", card.c_str(), snd_strerror(err)); snd_mixer_close(handle); return mlist; } if((err = snd_mixer_selem_register(handle, NULL, NULL)) < 0) { printf("Mixer register error: %s", snd_strerror(err)); snd_mixer_close(handle); return mlist; } err = snd_mixer_load(handle); if (err < 0) { printf("Mixer %s load error: %s", card.c_str(), snd_strerror(err)); snd_mixer_close(handle); return mlist; } for(elem = snd_mixer_first_elem(handle); elem; elem = snd_mixer_elem_next(elem)) { snd_mixer_selem_get_id(elem, sid); if(snd_mixer_selem_is_active(elem) == 0) continue; char cname[256]; snprintf(cname, sizeof(cname), "'%s',%i", snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid)); mlist.push_back(cname); } snd_mixer_close(handle); return mlist; } Mixer *Device::getMixer(std::string name) { int err; snd_mixer_t *handle; snd_mixer_selem_id_t *sid; snd_mixer_elem_t *elem; snd_mixer_selem_id_alloca(&sid); if((err = snd_mixer_open(&handle, 0)) < 0) { printf("Mixer %s open error: %s", card.c_str(), snd_strerror(err)); return NULL; } if((err = snd_mixer_attach(handle, card.c_str())) < 0) { printf("Mixer attach %s error: %s", card.c_str(), snd_strerror(err)); snd_mixer_close(handle); return NULL; } if((err = snd_mixer_selem_register(handle, NULL, NULL)) < 0) { printf("Mixer register error: %s", snd_strerror(err)); snd_mixer_close(handle); return NULL; } err = snd_mixer_load(handle); if (err < 0) { printf("Mixer %s load error: %s", card.c_str(), snd_strerror(err)); snd_mixer_close(handle); return NULL; } for(elem = snd_mixer_first_elem(handle); elem; elem = snd_mixer_elem_next(elem)) { snd_mixer_selem_get_id(elem, sid); if(snd_mixer_selem_is_active(elem) == 0) continue; char cname[256]; snprintf(cname, sizeof(cname), "'%s',%i", snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid)); if(std::string(cname) == name) { // NOTE: The Mixer object takes ownership of 'handle' which closed in // its destructor. return new Mixer(handle, elem); } } snd_mixer_close(handle); printf("Mixer element \"%s\" not found.\n", name.c_str()); return NULL; } static int pcm_init(snd_pcm_t *handle, unsigned int *samplerate, unsigned int channels, snd_pcm_uframes_t *frames) { int err; snd_pcm_hw_params_t *params; // Allocate a hardware parameters object. snd_pcm_hw_params_alloca(¶ms); // Fill it in with default values. err = snd_pcm_hw_params_any(handle, params); if(err) { printf("snd_pcm_hw_params_any: %s, %d\n", snd_strerror(err), err); return 1; } // Interleaved mode err = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); if(err) { printf("snd_pcm_hw_params_set_access: %s, %d\n", snd_strerror(err), err); return 1; } // Signed 16-bit little-endian format err = snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE); if(err) { printf("snd_pcm_hw_params_set_format: %s, %d\n", snd_strerror(err), err); return 1; } // Set channels (stereo/mono) err = snd_pcm_hw_params_set_channels(handle, params, channels); if(err) { printf("snd_pcm_hw_params_set_channels: %s, %d\n", snd_strerror(err), err); return 1; } // dir: -1 := exact or first below // 0 := exact (error if not?) // 1 := exact or first above int dir = 1; // Set sampling rate err = snd_pcm_hw_params_set_rate_near(handle, params, samplerate, &dir); if(err) { printf("snd_pcm_hw_params_set_rate_near: %s, %d\n", snd_strerror(err), err); return 1; } // printf("Actual samplerate: %d\n", samplerate); err = snd_pcm_hw_params_set_period_size_near(handle, params, frames, &dir); if(err) { printf("snd_pcm_hw_params_set_period_size_near: %s, %d\n", snd_strerror(err), err); return 1; } // printf("Actual buffersize: %d\n", (int)frames); // Write the parameters to the driver err = snd_pcm_hw_params(handle, params); if(err) { printf("snd_pcm_hw_params: %s, %d\n", snd_strerror(err), err); return 1; } return 0; } Source *Device::getSource(std::string name, unsigned int samplerate, unsigned int channels) { int open_mode = 0; //open_mode |= SND_PCM_NONBLOCK; //open_mode |= SND_PCM_NO_AUTO_RESAMPLE; //open_mode |= SND_PCM_NO_AUTO_CHANNELS; //open_mode |= SND_PCM_NO_AUTO_FORMAT; //open_mode |= SND_PCM_NO_SOFTVOL; int err; snd_pcm_t *handle; // Open PCM device for recording (capture). err = snd_pcm_open(&handle, name.c_str(), SND_PCM_STREAM_CAPTURE, open_mode); if(err) { printf("snd_pcm_open: %s, %d\n", snd_strerror(err), err); return NULL; } snd_pcm_uframes_t frames = 512; if(pcm_init(handle, &samplerate, channels, &frames)) return NULL; return new Source(handle, samplerate, channels, frames); } Sink *Device::getSink(std::string name, unsigned int samplerate, unsigned int channels) { int open_mode = 0; //open_mode |= SND_PCM_NONBLOCK; //open_mode |= SND_PCM_NO_AUTO_RESAMPLE; //open_mode |= SND_PCM_NO_AUTO_CHANNELS; //open_mode |= SND_PCM_NO_AUTO_FORMAT; //open_mode |= SND_PCM_NO_SOFTVOL; int err; snd_pcm_t *handle; // Open PCM device for recording (capture). err = snd_pcm_open(&handle, name.c_str(), SND_PCM_STREAM_PLAYBACK, open_mode); if(err) { printf("snd_pcm_open: %s, %d\n", snd_strerror(err), err); return NULL; } snd_pcm_uframes_t frames = 2048; if(pcm_init(handle, &samplerate, channels, &frames)) return NULL; return new Sink(handle, samplerate, channels, frames); }