From 4f6b15ea26b5fa09f300f67e4ce1057c2b39a3aa Mon Sep 17 00:00:00 2001 From: Bent Bisballe Nyeng Date: Thu, 25 Sep 2014 17:08:44 +0200 Subject: New API, new name, new version. --- src/audioin.cc | 445 --------------------------------------------------------- 1 file changed, 445 deletions(-) delete mode 100644 src/audioin.cc (limited to 'src/audioin.cc') diff --git a/src/audioin.cc b/src/audioin.cc deleted file mode 100644 index cc6fffc..0000000 --- a/src/audioin.cc +++ /dev/null @@ -1,445 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/*************************************************************************** - * audioin.cc - * - * Wed Sep 30 11:36:18 CEST 2009 - * Copyright 2011 Bent Bisballe Nyeng - * deva@aasimon.org - ****************************************************************************/ - -/* - * This file is part of libaudioin. - * - * libaudioin 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 2 of the License, or - * (at your option) any later version. - * - * libaudioin 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 libaudioin; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ -#include "audioin.h" - -// Use the newer ALSA API -#define ALSA_PCM_NEW_HW_PARAMS_API - -#include -#include -#include -#include -#include - -class AudioIn { -public: - class CouldNotOpenPCMDevice : public std::exception {}; - class UnableToSetHWParams : public std::exception {}; - class PcmBufferTooSmall : public std::exception {}; - class OverRun : public std::exception {}; - class ReadError : public std::exception {}; - class ShortRead : public std::exception {}; - class CouldNotInitialiseParams : public std::exception {}; - class CouldNotSetAccessMode : public std::exception {}; - class CouldNotSetFormat : public std::exception {}; - class CouldNotSetChannelNumber : public std::exception {}; - class UnableToSetSampleRate : public std::exception {}; - class UnableToSetPeriodSize : public std::exception {}; - class MixerInitilisationFailed : public std::exception {}; - class MixerNotInitialised : public std::exception {}; - class InvalidMixerLevel : public std::exception {}; - class IllegalChannelNumber : public std::exception {}; - class CouldNotSetMixerLevel : public std::exception {}; - - AudioIn(std::string device, std::string mixer, unsigned int srate, int ch); - ~AudioIn(); - - /** - * Reads a number of samples from the soundcard. - * The returned signal is a 16bit mono pcm signal. - */ - size_t read(void *buf, size_t size); - - int set_level(unsigned int channel, float level); - - unsigned int get_samplerate(); - - void set_enable_noise_fix(bool fixit); - -private: - bool noisefix; - unsigned int samplerate; - int channels; - snd_pcm_t *handle; - snd_pcm_hw_params_t *params; - unsigned int val; - int dir; - snd_pcm_uframes_t frames; - - snd_mixer_t *mixhnd; - snd_mixer_elem_t *elem; - long lvl_min, lvl_max; -}; - -AudioIn::AudioIn(std::string device, std::string mixer_interface, - unsigned int srate, int ch) -{ - 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; - elem = NULL; - mixhnd = NULL; - - noisefix = false; - - samplerate = 0; - - int rc; - - // Open PCM device for recording (capture). - rc = snd_pcm_open(&handle, device.c_str(), SND_PCM_STREAM_CAPTURE, open_mode); - if (rc < 0) throw CouldNotOpenPCMDevice(); - - // Allocate a hardware parameters object. - snd_pcm_hw_params_alloca(¶ms); - - // Fill it in with default values. - rc = snd_pcm_hw_params_any(handle, params); - if (rc < 0) throw CouldNotInitialiseParams(); - - // Set the desired hardware parameters. - - // Interleaved mode - rc = snd_pcm_hw_params_set_access(handle, params, - SND_PCM_ACCESS_RW_INTERLEAVED); - if (rc < 0) throw CouldNotSetAccessMode(); - - // Signed 16-bit little-endian format - rc = snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE); - if (rc < 0) throw CouldNotSetFormat(); - - // Set channels (stereo/mono) - rc = snd_pcm_hw_params_set_channels(handle, params, ch); - channels = ch; - if (rc < 0) throw CouldNotSetChannelNumber(); - - // Set sampling rate - samplerate = srate; - rc = snd_pcm_hw_params_set_rate_near(handle, params, &samplerate, &dir); - if(rc < 0) throw UnableToSetSampleRate(); - //if(samplerate != srate) throw UnableToSetSampleRate(); - - // NOTE: Setting period size to 32 frames will force use of lowest possible value. - frames = 512; - rc = snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir); - if(rc < 0) throw UnableToSetPeriodSize(); - - // Write the parameters to the driver - rc = snd_pcm_hw_params(handle, params); - if (rc < 0) throw UnableToSetHWParams(); - - if(mixer_interface == "") return; - - // - // Set up mixer - // - snd_mixer_selem_id_t *mixer; - - // Open mixer device - if(snd_mixer_open(&mixhnd, 0) != 0) throw MixerInitilisationFailed(); - - if(snd_mixer_attach(mixhnd, device.c_str()) != 0) - throw MixerInitilisationFailed(); - - if(snd_mixer_selem_register(mixhnd, NULL, NULL) < 0) - throw MixerInitilisationFailed(); - - if(snd_mixer_load(mixhnd) < 0) - throw MixerInitilisationFailed(); - - // Obtain mixer element - snd_mixer_selem_id_alloca(&mixer); - if(mixer == NULL) throw MixerInitilisationFailed(); - snd_mixer_selem_id_set_name(mixer, mixer_interface.c_str()); - - elem = snd_mixer_find_selem(mixhnd, mixer); - if(elem == NULL) throw MixerInitilisationFailed(); - - if(snd_mixer_selem_get_capture_volume_range(elem, &lvl_min, &lvl_max) != 0) { - throw MixerInitilisationFailed(); - } - - if(snd_mixer_selem_set_capture_switch(elem, - SND_MIXER_SCHN_FRONT_LEFT, 1) != 0) { - throw MixerInitilisationFailed(); - } - - if(snd_mixer_selem_set_capture_switch(elem, - SND_MIXER_SCHN_FRONT_RIGHT, 1) != 0) { - throw MixerInitilisationFailed(); - } - - // Obtain mixer enumeration element "Input Source" and set it to 2 (line). - snd_mixer_selem_id_set_name(mixer, "Input Source"); - - snd_mixer_elem_t *iselem = snd_mixer_find_selem(mixhnd, mixer); - if(iselem == NULL) return; - - if(snd_mixer_selem_is_enumerated(iselem)) { - // Set to line-in - for(int i = 0; i < 3; i++) { - char name[16]; - snd_mixer_selem_get_enum_item_name(iselem, i, sizeof(name), name); - if(std::string(name) == "Line") { - snd_mixer_selem_set_enum_item(iselem, SND_MIXER_SCHN_MONO, i); - } - } - } -} - -AudioIn::~AudioIn() -{ - if(handle) { - snd_pcm_drain(handle); - snd_pcm_close(handle); - } - if(mixhnd) snd_mixer_close(mixhnd); -} - -size_t AudioIn::read(void *buf, size_t size) -{ - int rc; - - if(size < frames * sizeof(short) * channels) { - throw PcmBufferTooSmall(); - } - - rc = snd_pcm_readi(handle, buf, frames); - if (rc == -EPIPE) { - // EPIPE means overrun - snd_pcm_prepare(handle); - throw OverRun(); - return 0; - } else if (rc < 0) { - throw ReadError(); - } else if (rc != (int)frames) { - throw ShortRead(); - } - - return rc * sizeof(short) * channels; -} - -unsigned int AudioIn::get_samplerate() -{ - return samplerate; -} - -int AudioIn::set_level(unsigned int channel, float level) -{ - - if(!elem) throw MixerNotInitialised(); - - if(level > 1.0 || level < 0.0) throw InvalidMixerLevel(); - - long lvl = ((lvl_max - lvl_min) * level) + lvl_min; - - snd_mixer_selem_channel_id_t ch; - switch(channel) { - case 0: - ch = SND_MIXER_SCHN_FRONT_LEFT; - break; - case 1: - ch = SND_MIXER_SCHN_FRONT_RIGHT; - break; - default: - throw IllegalChannelNumber(); - break; - } - if(snd_mixer_selem_set_capture_volume(elem, ch, lvl) != 0) { - throw CouldNotSetMixerLevel(); - } - return 0; -} - - -#define MAGIC 0xdeadbeef - -struct ai_t { - unsigned int magic; - AudioIn *ai; -}; - -struct ai_t *ai_init(int *err, const char *device, const char *mixer, - unsigned int srate, unsigned int ch) -{ - *err = NO_ERROR; - - struct ai_t *handle = new ai_t; - handle->magic = MAGIC; - - if(handle == NULL) { - *err = OUT_OF_MEMORY; - return NULL; - } - - try { - handle->ai = new AudioIn(device, mixer, srate, ch); - } catch(AudioIn::CouldNotOpenPCMDevice &e) { *err = COULD_NOT_OPEN_DEVICE; - } catch(AudioIn::UnableToSetHWParams &e) { *err = COULD_NOT_SET_HW_PARAMS; - } catch(AudioIn::CouldNotInitialiseParams &e) { *err = COULD_NOT_INIT_PARAMS; - } catch(AudioIn::CouldNotSetAccessMode &e) { *err = COULD_NOT_SET_ACCESS_MODE; - } catch(AudioIn::CouldNotSetFormat &e) { *err = COULD_NOT_SET_FORMAT; - } catch(AudioIn::CouldNotSetChannelNumber &e) { *err = COULD_NOT_SET_CHANNELS; - } catch(AudioIn::UnableToSetSampleRate &e) { *err = COULD_NOT_SET_SAMPLE_RATE; - } catch(AudioIn::UnableToSetPeriodSize &e) { *err = COULD_NOT_SET_PERIOD_SIZE; - } catch(AudioIn::MixerInitilisationFailed &e) { *err = MIXER_INIT_FAILED; - } - - if(*err != NO_ERROR) { - handle->magic = 0; - delete handle; - return NULL; - } - - return handle; -} - -int ai_read(int *err, struct ai_t *handle, void *pcm, unsigned int maxsize) -{ - if(*err == 42) { // Magic debug function - short *p = (short*)pcm; - for(size_t i = 0; i < maxsize / sizeof(short); i++) { - p[i] = i; - } - *err = NO_ERROR; - return maxsize; - } - - *err = NO_ERROR; - - if(handle == NULL || handle->magic != MAGIC || handle->ai == NULL) { - *err = MISSING_HANDLE; - return -1; - } - - try { - return handle->ai->read(pcm, maxsize); - } catch(AudioIn::PcmBufferTooSmall &e) { *err = BUFFER_TOO_SMALL; - } catch(AudioIn::OverRun &e) { *err = BUFFER_OVERRUN; - } catch(AudioIn::ReadError &e) { *err = READ_ERROR; - } catch(AudioIn::ShortRead &e) { *err = SHORT_READ; - } - - return -1; -} - -int ai_get_samplerate(int *err, struct ai_t *handle) -{ - *err = NO_ERROR; - - if(handle == NULL || handle->magic != MAGIC || handle->ai == NULL) { - *err = MISSING_HANDLE; - return -1; - } - - return (int)handle->ai->get_samplerate(); -} - - -int ai_set_mixer_level(int *err, struct ai_t *handle, unsigned int channel, - float level) -{ - *err = NO_ERROR; - - if(handle == NULL || handle->magic != MAGIC || handle->ai == NULL) { - *err = MISSING_HANDLE; - return -1; - } - - try { - return handle->ai->set_level(channel, level); - } catch(AudioIn::MixerNotInitialised &e) { *err = MIXER_NOT_INITIALISED; - } catch(AudioIn::InvalidMixerLevel &e) { *err = INVALID_MIXER_LEVEL; - } catch(AudioIn::IllegalChannelNumber &e) { *err = INVALID_CHANNEL_NUMBER; - } catch(AudioIn::CouldNotSetMixerLevel &e) { *err = COULD_NOT_SET_MIXER_LEVEL; - } - - return -1; -} - -void ai_close(int *err, struct ai_t *handle) -{ - *err = NO_ERROR; - - if(handle == NULL || handle->magic != MAGIC || handle->ai == NULL) { - *err = MISSING_HANDLE; - return; - } - - delete handle->ai; - handle->ai = NULL; - handle->magic = 0; - delete handle; -} - -#ifdef TEST_AUDIOIN -//deps: -//cflags: $(ALSA_CFLAGS) -//libs: $(ALSA_LIBS) - -#include -#include "test_audio.h" -#include - -TEST_BEGIN; -int err; -struct ai_t *h; - -h = ai_init(&err, "default", "H/W Multi", 44100, 2); -TEST_EQUAL_INT(err, 0, "Check for errors."); -TEST_NOTEQUAL(h, NULL, "Check handle."); - -ai_close(&err, h); -TEST_EQUAL_INT(err, 0, "Check for errors."); - -h = ai_init(&err, "default", "H/W Multi", 22050, 1); -TEST_EQUAL_INT(err, 0, "Check for errors."); -TEST_NOTEQUAL(h, NULL, "Check handle."); - -char pcm[1880]; // Hold exactly one frame. -int r; - -r = ai_read(&err, h, pcm, 0); -TEST_EQUAL_INT(r, -1, "We should read something."); -TEST_EQUAL_INT(err, BUFFER_TOO_SMALL, "Check for errors."); - -for(int i = 0; i < 100; i++) { - r = ai_read(&err, h, pcm, sizeof(pcm)); -} -TEST_EQUAL_INT(err, 0, "Check for errors."); -TEST_NOTEQUAL_INT(r, 0, "We should read something."); - -char ref[sizeof(pcm)]; -memset(ref, 0, sizeof(ref)); -double diff = compareBuffers(r/sizeof(short), 1, pcm, ref); -TEST_LESS_THAN_FLOAT(diff, 1000.0, "Compare buffers (with no mic on the soundcard)"); - -short p[1024]; -err = 42; -ai_read(&err, h, p, sizeof(p)); -for(size_t i = 0; i < sizeof(p) / sizeof(short); i++) { - TEST_EQUAL_INT(p[i], i, "Compare slide."); -} - -ai_close(&err, h); - -TEST_END; - -#endif/*TEST_AUDIOIN*/ -- cgit v1.2.3