diff options
author | Bent Bisballe Nyeng <deva@aasimon.org> | 2014-09-25 17:08:44 +0200 |
---|---|---|
committer | Bent Bisballe Nyeng <deva@aasimon.org> | 2014-09-25 17:08:44 +0200 |
commit | 4f6b15ea26b5fa09f300f67e4ce1057c2b39a3aa (patch) | |
tree | 45d7bb4a9a90ef603b5a7a65a4d4d4309a7a1538 /src/device.cc | |
parent | 0602763044f0f0f9163f2a888627213347d3dbb7 (diff) |
New API, new name, new version.
Diffstat (limited to 'src/device.cc')
-rw-r--r-- | src/device.cc | 275 |
1 files changed, 275 insertions, 0 deletions
diff --git a/src/device.cc b/src/device.cc new file mode 100644 index 0000000..f68a90a --- /dev/null +++ b/src/device.cc @@ -0,0 +1,275 @@ +/* -*- 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() +{ + /* + if(handle) { + snd_pcm_drain(handle); + snd_pcm_close(handle); + } + */ +} + +std::vector<std::string> Device::mixerNames() +{ + std::vector<std::string> 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 = 512; + if(pcm_init(handle, &samplerate, channels, &frames)) return NULL; + + return new Sink(handle, samplerate, channels, frames); +} |