summaryrefslogtreecommitdiff
path: root/src/device.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/device.cc')
-rw-r--r--src/device.cc275
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(&params);
+
+ // 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);
+}