diff --git a/flow/CMakeLists.txt b/flow/CMakeLists.txt index 14a72aa..32bb29b 100644 --- a/flow/CMakeLists.txt +++ b/flow/CMakeLists.txt @@ -56,7 +56,7 @@ set( ${target}_SRCS stereovolumecontrol_impl.cpp stereoeffectstack_impl.cpp fft.c stereofftscope_impl.cpp virtualports.cpp bus.cpp audiomanager_impl.cpp synth_record_impl.cpp resample.cpp - audioio.cpp audioiooss.cpp audioioalsa.cpp audioioalsa9.cpp + audioio.cpp audioiooss.cpp audioioalsa9.cpp audioionull.cpp audioiolibaudioio.cpp audioioesd.cpp audioiosndio.cpp audioiojack.cpp audioiosun.cpp audioioaix.cpp audioionas.cpp cpuinfo.cpp audioioossthreaded.cpp audiotobytestream_impl.cpp diff --git a/flow/audioioalsa.cpp b/flow/audioioalsa.cpp deleted file mode 100644 index 5b8d485..0000000 --- a/flow/audioioalsa.cpp +++ /dev/null @@ -1,561 +0,0 @@ - /* - - Copyright (C) 2000,2001 Jozef Kosoru - jozef.kosoru@pobox.sk - (C) 2000,2001 Stefan Westerfeld - stefan@space.twc.de - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. - - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -/** - * only compile 'alsa' AudioIO class if configure thinks it is a good idea - */ -#ifdef HAVE_LIBASOUND - -#ifdef HAVE_ALSA_ASOUNDLIB_H -#include -#elif defined(HAVE_SYS_ASOUNDLIB_H) -#include -#endif - -#include -#include -#include -#include - -#ifdef HAVE_SYS_SELECT_H -#include // Needed on some systems. -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "debug.h" -#include "audioio.h" - -namespace Arts { - -class AudioIOALSA : public AudioIO { -protected: - int audio_read_fd; - int audio_write_fd; - int requestedFragmentSize; - int requestedFragmentCount; - - enum BufferMode{block, stream}; - int m_card; - int m_device; - int m_format; - BufferMode m_bufferMode; - - snd_pcm_t *m_pcm_handle; - snd_pcm_channel_info_t m_cinfo; - snd_pcm_format_t m_cformat; - snd_pcm_channel_params_t m_params; - snd_pcm_channel_setup_t m_setup; - - int setPcmParams(const int channel); - void checkCapabilities(); - -public: - AudioIOALSA(); - - void setParam(AudioParam param, int& value); - int getParam(AudioParam param); - - bool open(); - void close(); - int read(void *buffer, int size); - int write(void *buffer, int size); -}; - -REGISTER_AUDIO_IO(AudioIOALSA,"alsa","Advanced Linux Sound Architecture"); -}; - -using namespace std; -using namespace Arts; - -AudioIOALSA::AudioIOALSA() -{ - param(samplingRate) = 44100; - paramStr(deviceName) = "/dev/dsp"; //!! alsa doesn't need this - requestedFragmentSize = param(fragmentSize) = 1024; - requestedFragmentCount = param(fragmentCount) = 7; - param(channels) = 2; - param(direction) = directionWrite; - - /* - * default parameters - */ - m_card = snd_defaults_pcm_card(); //!! need interface !! - m_device = snd_defaults_pcm_device(); //!! -#ifdef WORDS_BIGENDIAN - m_format = SND_PCM_SFMT_S16_BE; -#else - m_format = SND_PCM_SFMT_S16_LE; -#endif - m_bufferMode = block; //block/stream (stream mode doesn't work yet) - - if(m_card >= 0) { - char* cardname = 0; - - if(snd_card_get_name(m_card, &cardname) == 0 && cardname != 0) - { - //!! thats not what devicename is intended to do - //!! devicename is an input information into - //!! the "driver", to select which card to use - //!! not an output information - paramStr(deviceName) = cardname; - free(cardname); - } - } -} - -bool AudioIOALSA::open() -{ - string& _error = paramStr(lastError); - string& _deviceName = paramStr(deviceName); - int& _channels = param(channels); - int& _fragmentSize = param(fragmentSize); - int& _fragmentCount = param(fragmentCount); - int& _samplingRate = param(samplingRate); - int& _direction = param(direction); - int& _format = param(format); - - /* - * initialize format - TODO: implement fallback (i.e. if no format given, - * it should try 16bit first, then fall back to 8bit) - */ - switch(_format) - { - default: _format = 16; - - case 16: // 16bit, signed little endian - m_format = SND_PCM_SFMT_S16_LE; - break; - - case 17: // 16bit, signed big endian - m_format = SND_PCM_SFMT_S16_BE; - break; - - case 8: // 8bit, unsigned - m_format = SND_PCM_SFMT_U8; - break; - } - - /* open pcm device */ - int mode = SND_PCM_OPEN_NONBLOCK; - - if(_direction == directionReadWrite) - mode |= SND_PCM_OPEN_DUPLEX; - else if(_direction == directionWrite) - mode |= SND_PCM_OPEN_PLAYBACK; - else - { - _error = "invalid direction"; - return false; - } - - int err; - if((err = snd_pcm_open(&m_pcm_handle, m_card, m_device, mode)) < 0) { - _error = "device: "; - _error += _deviceName.c_str(); - _error += " can't be opened ("; - _error += snd_strerror(err); - _error += ")"; - return false; - } - else { - artsdebug("ALSA driver: %s", _deviceName.c_str()); - } - - snd_pcm_nonblock_mode(m_pcm_handle, 0); - - /* flush buffers */ - (void)snd_pcm_capture_flush(m_pcm_handle); - if(_direction & directionRead) - (void)snd_pcm_channel_flush(m_pcm_handle, SND_PCM_CHANNEL_CAPTURE); - if(_direction & directionWrite) - (void)snd_pcm_channel_flush(m_pcm_handle, SND_PCM_CHANNEL_PLAYBACK); - - /* check device capabilities */ - checkCapabilities(); - - /* set the fragment settings to what the user requested */ - _fragmentSize = requestedFragmentSize; - _fragmentCount = requestedFragmentCount; - - /* set PCM communication parameters */ - if((_direction & directionRead) && setPcmParams(SND_PCM_CHANNEL_CAPTURE)) - return false; - if((_direction & directionWrite) && setPcmParams(SND_PCM_CHANNEL_PLAYBACK)) - return false; - - /* prepare channel */ - if((_direction & directionRead) && - snd_pcm_channel_prepare(m_pcm_handle, SND_PCM_CHANNEL_CAPTURE) < 0) - { - _error = "Unable to prepare capture channel!"; - return false; - } - if((_direction & directionWrite) && - snd_pcm_channel_prepare(m_pcm_handle, SND_PCM_CHANNEL_PLAYBACK) < 0) - { - _error = "Unable to prepare playback channel!"; - return false; - } - - /* obtain current PCM setup (may differ from requested one) */ - (void)memset(&m_setup, 0, sizeof(m_setup)); - - m_setup.channel = SND_PCM_CHANNEL_PLAYBACK; - if(snd_pcm_channel_setup(m_pcm_handle, &m_setup) < 0) { - _error = "Unable to obtain channel setup!"; - return false; - } - - /* check samplerate */ - const int tolerance = _samplingRate/10+1000; - if(abs(m_setup.format.rate-_samplingRate) > tolerance) - { - _error = "Can't set requested sampling rate!"; - char details[80]; - sprintf(details," (requested rate %d, got rate %d)", - _samplingRate, m_setup.format.rate); - _error += details; - return false; - } - _samplingRate = m_setup.format.rate; - - /* check format */ - if(m_setup.format.format != m_format) { - _error = "Can't set requested format:"; - _error += snd_pcm_get_format_name(m_format); - return false; - } - - /* check voices */ - if(m_setup.format.voices != _channels) { - _error = "Audio device doesn't support number of requested channels!"; - return false; - } - - /* update fragment settings with what we got */ - switch(m_bufferMode) { - case block: - _fragmentSize = m_setup.buf.block.frag_size; - _fragmentCount = m_setup.buf.block.frags_max-1; - break; - case stream: - _fragmentSize = m_setup.buf.stream.queue_size; - _fragmentCount = 1; - break; - } - - artsdebug("buffering: %d fragments with %d bytes " - "(audio latency is %1.1f ms)", _fragmentCount, _fragmentSize, - (float)(_fragmentSize*_fragmentCount) / - (float)(2.0 * _samplingRate * _channels)*1000.0); - - /* obtain PCM file descriptor(s) */ - audio_read_fd = audio_write_fd = -1; - - if(_direction & directionRead) - audio_read_fd = snd_pcm_file_descriptor(m_pcm_handle, - SND_PCM_CHANNEL_CAPTURE); - if(_direction & directionWrite) - audio_write_fd = snd_pcm_file_descriptor(m_pcm_handle, - SND_PCM_CHANNEL_PLAYBACK); - - /* start recording */ - if((_direction & directionRead) && snd_pcm_capture_go(m_pcm_handle)) { - _error = "Can't start recording!"; - return false; - } - - return true; -} - -void AudioIOALSA::close() -{ - int& _direction = param(direction); - if(_direction & directionRead) - (void)snd_pcm_channel_flush(m_pcm_handle, SND_PCM_CHANNEL_CAPTURE); - if(_direction & directionWrite) - (void)snd_pcm_channel_flush(m_pcm_handle, SND_PCM_CHANNEL_PLAYBACK); - (void)snd_pcm_close(m_pcm_handle); -} - -void AudioIOALSA::setParam(AudioParam p, int& value) -{ - switch(p) - { - case fragmentSize: - param(p) = requestedFragmentSize = value; - break; - case fragmentCount: - param(p) = requestedFragmentCount = value; - break; - default: - param(p) = value; - break; - } -} - -int AudioIOALSA::getParam(AudioParam p) -{ - snd_pcm_channel_status_t status; - (void)memset(&status, 0, sizeof(status)); - - switch(p) - { - case canRead: - status.channel = SND_PCM_CHANNEL_CAPTURE; - if(snd_pcm_channel_status(m_pcm_handle, &status) < 0) { - arts_warning("Capture channel status error!"); - return -1; - } - return status.free; - break; - - case canWrite: - status.channel = SND_PCM_CHANNEL_PLAYBACK; - if(snd_pcm_channel_status(m_pcm_handle, &status) < 0) { - arts_warning("Playback channel status error!"); - return -1; - } - return status.free; - break; - - case selectReadFD: - return audio_read_fd; - break; - - case selectWriteFD: - return audio_write_fd; - break; - - case autoDetect: - /* - * that the ALSA driver could be compiled doesn't say anything - * about whether it will work (the user might be using an OSS - * kernel driver) so we'll use a value less than the OSS one - * here, because OSS will most certainly work (ALSA's OSS emu) - */ - return 5; - break; - - default: - return param(p); - break; - } -} - -int AudioIOALSA::read(void *buffer, int size) -{ - int length; - do { - length = snd_pcm_read(m_pcm_handle, buffer, size); - } while (length == -EINTR); - if(length == -EPIPE) { - snd_pcm_channel_status_t status; - (void)memset(&status, 0, sizeof(status)); - status.channel = SND_PCM_CHANNEL_CAPTURE; - if(snd_pcm_channel_status(m_pcm_handle, &status) < 0) { - arts_info("Capture channel status error!"); - return -1; - } - else if(status.status == SND_PCM_STATUS_RUNNING) { - length = 0; - } - else if(status.status == SND_PCM_STATUS_OVERRUN) { - artsdebug("Overrun at position: %d" ,status.scount); - if(snd_pcm_channel_prepare(m_pcm_handle, SND_PCM_CHANNEL_CAPTURE)<0) - { - arts_info("Overrun: capture prepare error!"); - return -1; - } - length = 0; - } - else { - arts_info("Unknown capture error!"); - return -1; - } - } - else if(length < 0) { - arts_info("Capture error: %s", snd_strerror(length)); - return -1; - } - return length; -} - -int AudioIOALSA::write(void *buffer, int size) -{ - int length; - while((length = snd_pcm_write(m_pcm_handle, buffer, size)) != size) { - if (length == -EINTR) - continue; // Try again - snd_pcm_channel_status_t status; - (void)memset(&status, 0, sizeof(status)); - status.channel = SND_PCM_CHANNEL_PLAYBACK; - - if(snd_pcm_channel_status(m_pcm_handle, &status) < 0) { - arts_warning("Playback channel status error!"); - return -1; - } - else if(status.status == SND_PCM_STATUS_UNDERRUN) { - artsdebug("Underrun at position: %d", status.scount); - if(snd_pcm_channel_prepare(m_pcm_handle, SND_PCM_CHANNEL_PLAYBACK) - < 0) { - arts_warning("Underrun: playback prepare error!"); - return -1; - } - } - else { - arts_warning("Unknown playback error!"); - return -1; - } - } - return size; -} - -int AudioIOALSA::setPcmParams(const int channel) -{ - int &_samplingRate = param(samplingRate); - int &_channels = param(channels); - int &_fragmentSize = param(fragmentSize); - int &_fragmentCount = param(fragmentCount); - - (void)memset(&m_cformat, 0, sizeof(m_cformat)); - m_cformat.interleave = 1; - m_cformat.format = m_format; - m_cformat.rate = _samplingRate; - m_cformat.voices = _channels; - - (void)memset(&m_params, 0, sizeof(m_params)); - switch(m_bufferMode){ - case stream: - m_params.mode=SND_PCM_MODE_STREAM; - break; - case block: - m_params.mode=SND_PCM_MODE_BLOCK; - break; - } - m_params.channel=channel; - (void)memcpy(&m_params.format, &m_cformat, sizeof(m_cformat)); - if(channel==SND_PCM_CHANNEL_CAPTURE){ - m_params.start_mode=SND_PCM_START_GO; - m_params.stop_mode=SND_PCM_STOP_ROLLOVER; - } - else{ //SND_PCM_CHANNEL_PLAYBACK - m_params.start_mode= (m_bufferMode==block) ? SND_PCM_START_FULL : SND_PCM_START_DATA; - m_params.stop_mode=SND_PCM_STOP_ROLLOVER; // SND_PCM_STOP_STOP - //use this ^^^ if you want to track underruns - } - - switch(m_bufferMode){ - case stream: - m_params.buf.stream.queue_size=1024*1024; //_fragmentSize*_fragmentCount; - m_params.buf.stream.fill=SND_PCM_FILL_SILENCE_WHOLE; - m_params.buf.stream.max_fill=1024; - break; - case block: - m_params.buf.block.frag_size=_fragmentSize; - if(channel==SND_PCM_CHANNEL_CAPTURE){ - m_params.buf.block.frags_max=1; - m_params.buf.block.frags_min=1; - } - else{ //SND_PCM_CHANNEL_PLAYBACK - m_params.buf.block.frags_max=_fragmentCount+1; - m_params.buf.block.frags_min=1; - } - } - if(snd_pcm_channel_params(m_pcm_handle, &m_params)<0){ - paramStr(lastError) = "Unable to set channel params!"; - return 1; - } - else { - return 0; - } -} - -void AudioIOALSA::checkCapabilities() -{ - snd_pcm_info_t info; - (void)memset(&info, 0, sizeof(info)); - if(!snd_pcm_info(m_pcm_handle, &info)) { - string flags = ""; - if(info.flags & SND_PCM_INFO_PLAYBACK) flags += "playback "; - if(info.flags & SND_PCM_INFO_CAPTURE) flags += "capture "; - if(info.flags & SND_PCM_INFO_DUPLEX) flags += "duplex "; - if(info.flags & SND_PCM_INFO_DUPLEX_RATE) flags += "duplex_rate "; - artsdebug(" type:%d id:%s\n" - " flags:%s\n" - " playback_subdevices:%d capture_subdevices:%d", - info.type, info.id, - flags.c_str(), - info.playback+1, info.capture+1); - } - else { - arts_warning("Can't get device info!"); //not fatal error - } - - (void)memset(&m_cinfo, 0, sizeof(m_cinfo)); - m_cinfo.channel = SND_PCM_CHANNEL_PLAYBACK; - if(!snd_pcm_channel_info(m_pcm_handle, &m_cinfo)) { - string flags = ""; - if(m_cinfo.flags & SND_PCM_CHNINFO_MMAP) flags += "mmap "; - if(m_cinfo.flags & SND_PCM_CHNINFO_STREAM) flags += "stream "; - if(m_cinfo.flags & SND_PCM_CHNINFO_BLOCK) flags += "block "; - if(m_cinfo.flags & SND_PCM_CHNINFO_BATCH) flags += "batch "; - if(m_cinfo.flags & SND_PCM_CHNINFO_INTERLEAVE) flags += "interleave "; - if(m_cinfo.flags & SND_PCM_CHNINFO_NONINTERLEAVE) flags += "noninterleave "; - if(m_cinfo.flags & SND_PCM_CHNINFO_BLOCK_TRANSFER) flags += "block_transfer "; - if(m_cinfo.flags & SND_PCM_CHNINFO_OVERRANGE) flags += "overrange "; - if(m_cinfo.flags & SND_PCM_CHNINFO_MMAP_VALID) flags += "mmap_valid "; - if(m_cinfo.flags & SND_PCM_CHNINFO_PAUSE) flags += "pause "; - - artsdebug(" subdevice:%d\n" - " flags:%s\n" - " min_rate:%d max_rate:%d\n" - " buffer_size:%d min_fragment_size:%d max_fragment_size:%d\n" - " fragment_align:%d fifo_size:%d transfer_block_size:%d\n" - " mmap_size:%d", - m_cinfo.subdevice, - flags.c_str(), - m_cinfo.min_rate, m_cinfo.max_rate, - m_cinfo.buffer_size, m_cinfo.min_fragment_size, m_cinfo.max_fragment_size, - m_cinfo.fragment_align, m_cinfo.fifo_size, m_cinfo.transfer_block_size, - m_cinfo.mmap_size); - } - else { - arts_warning("Can't get channel info!"); //not fatal error - } -} - -#endif /* HAVE_LIBASOUND */