/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set et sw=2 ts=2: */ /*************************************************************************** * audioio.cc * * Thu Sep 25 15:55:14 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 "audioio.h" #include #include "device.h" #include "mixer.h" #include "source.h" #include "sink.h" #ifdef __cplusplus extern "C" { #endif #define MAGIC 0xdeadbeef struct aio_t { unsigned int magic; Device *device; Source *source; Mixer *source_mixer; Sink *sink; Mixer *sink_mixer; }; // Check if 'h' is a valid aio_t handle and report/return error if not. #define CHECK_HANDLE(h) \ do { \ if(!h || h->magic != MAGIC) { \ return MISSING_HANDLE; \ } \ } while(0) struct aio_t *aio_init(int *err, const char *playback_device, const char *playback_mixer, const char *capture_device, const char *capture_mixer, unsigned int samplerate, unsigned int channels) { *err = NO_ERROR; const char *device = playback_device; if(device == NULL || strlen(device) == 0) device = capture_device; if(device == NULL || strlen(device) == 0) { *err = COULD_NOT_OPEN_DEVICE; return NULL; } struct aio_t *h = (struct aio_t*)calloc(sizeof(struct aio_t), 1); if(h == NULL) { *err = OUT_OF_MEMORY; return NULL; } h->magic = MAGIC; h->device = new Device(device); if(playback_device != NULL && strlen(playback_device) > 0) { h->sink = h->device->getSink(playback_device, samplerate, channels); if(h->sink == NULL) { *err = COULD_NOT_OPEN_DEVICE; } } if(playback_mixer != NULL && strlen(playback_mixer) > 0) { h->sink_mixer = h->device->getMixer(playback_mixer); if(h->sink_mixer == NULL) { *err = MIXER_INIT_FAILED; } } if(capture_device != NULL && strlen(capture_device) > 0) { h->source = h->device->getSource(capture_device, samplerate, channels); if(h->source == NULL) { *err = COULD_NOT_OPEN_DEVICE; } } if(capture_mixer != NULL && strlen(capture_mixer) > 0) { h->source_mixer = h->device->getMixer(capture_mixer); if(h->source_mixer == NULL) { *err = MIXER_INIT_FAILED; } else { if(h->source_mixer->isCapture()) { h->source_mixer->setCapture(true); } else { *err = MIXER_INIT_FAILED; } } } if(*err != NO_ERROR) { h->magic = 0; if(h->source) delete h->source; if(h->source_mixer) delete h->source_mixer; if(h->sink) delete h->sink; if(h->sink_mixer) delete h->sink_mixer; free(h); return NULL; } return h; } int aio_read(struct aio_t *h, char *pcm, unsigned int maxsize) { CHECK_HANDLE(h); if(!h->source) return MISSING_HANDLE; int s = h->source->readSamples(pcm, maxsize); if(s < 0) return SAMPLE_READ_ERROR; return s; } int aio_write(struct aio_t *h, const char *pcm, unsigned int size) { CHECK_HANDLE(h); if(!h->sink) return MISSING_HANDLE; int s = h->sink->writeSamples(pcm, size); if(s < 0) return SAMPLE_WRITE_ERROR; return s; } static int set_mixer_level(Mixer *m, unsigned int c, float l) { if(!m) return MISSING_MIXER_HANDLE; //if((int)c > m->numberOfChannels() - 1) return NO_SUCH_CHANNEL; if(m->setLevel(c, l)) return NO_SUCH_CHANNEL; return 0; } int aio_set_playback_mixer_level(struct aio_t *h, unsigned int c, float l) { CHECK_HANDLE(h); return set_mixer_level(h->sink_mixer, c, l); } int aio_set_capture_mixer_level(struct aio_t *h, unsigned int c, float l) { CHECK_HANDLE(h); return set_mixer_level(h->source_mixer, c, l); } static int get_mixer_level(Mixer *m, unsigned int c, float *l) { if(!m) return MISSING_MIXER_HANDLE; //if((int)c > m->numberOfChannels() - 1) return NO_SUCH_CHANNEL; float lvl = m->level(c); if(isinf(lvl)) return INVALID_MIXER_LEVEL; *l = lvl; return 0; } int aio_get_playback_mixer_level(struct aio_t *h, unsigned int c, float *l) { CHECK_HANDLE(h); return get_mixer_level(h->sink_mixer, c, l); } int aio_get_capture_mixer_level(struct aio_t *h, unsigned int c, float *l) { CHECK_HANDLE(h); return get_mixer_level(h->source_mixer, c, l); } static int get_mixer_level_range(Mixer *m, float *min, float *max) { if(!m) return MISSING_MIXER_HANDLE; Mixer::range_t r = m->range(); if(isinf(r.min) || isinf(r.max)) return MIXER_ERROR; *min = r.min; *max = r.max; return 0; } int aio_get_playback_mixer_level_range(struct aio_t *h, float *min, float *max) { CHECK_HANDLE(h); return get_mixer_level_range(h->sink_mixer, min, max); } int aio_get_capture_mixer_level_range(struct aio_t *h, float *min, float *max) { CHECK_HANDLE(h); return get_mixer_level_range(h->source_mixer, min, max); } int aio_get_enum_value(struct aio_t *h, const char *name, char *value, size_t maxsize) { CHECK_HANDLE(h); Mixer *m = h->device->getMixer(name); if(!m) return NO_SUCH_ENUM; if(!m->isEnum()) { delete m; return NO_SUCH_ENUM; } std::string e = m->enumValue(); snprintf(value, maxsize, "%s", e.c_str()); return 0; } int aio_set_enum_value(struct aio_t *h, const char *name, const char *value) { CHECK_HANDLE(h); Mixer *m = h->device->getMixer(name); if(!m) return NO_SUCH_ENUM; if(!m->isEnum()) { delete m; return NO_SUCH_ENUM; } m->setEnumValue(value); return 0; } int aio_set_mute(struct aio_t *h, const char *name, int muted) { CHECK_HANDLE(h); Mixer *m = h->device->getMixer(name); if(!m) return NO_SUCH_CHANNEL; if(!m->isPlayback()) { delete m; return NO_SUCH_CHANNEL; } m->setMuted(muted); return 0; } int aio_get_mute(struct aio_t *h, const char *name, int *muted) { CHECK_HANDLE(h); Mixer *m = h->device->getMixer(name); if(!m) return NO_SUCH_CHANNEL; if(!m->isPlayback()) { delete m; return NO_SUCH_CHANNEL; } *muted = m->muted()?1:0; return 0; } int aio_get_samplerate(struct aio_t *h) { CHECK_HANDLE(h); if(h->source) return h->source->samplerate(); else if(h->sink) return h->sink->samplerate(); return MISSING_PCM_HANDLE; } int aio_get_buffer_size(struct aio_t *h) { CHECK_HANDLE(h); if(h->source) return h->source->frames(); else if(h->sink) return h->sink->frames(); return MISSING_PCM_HANDLE; } int aio_close(struct aio_t *h) { CHECK_HANDLE(h); h->magic = 0; if(h->source) delete h->source; if(h->source_mixer) delete h->source_mixer; if(h->sink) delete h->sink; if(h->sink_mixer) delete h->sink_mixer; free(h); return 0; } #ifdef __cplusplus } #endif