summaryrefslogtreecommitdiffstats
path: root/flow/audioioalsa9.cpp
diff options
context:
space:
mode:
authorBobby Bingham <koorogi@koorogi.info>2023-06-15 23:59:13 -0500
committerBobby Bingham <koorogi@koorogi.info>2023-06-16 08:10:59 -0500
commit596d2accf4533768bf81b91a87bc6d653caac26b (patch)
tree55120a1cb248e58c11f02f48c1c16f2286693783 /flow/audioioalsa9.cpp
parentc9092132fd7020cdb6f39aa7ed749f695fb98d26 (diff)
downloadarts-596d2accf4533768bf81b91a87bc6d653caac26b.tar.gz
arts-596d2accf4533768bf81b91a87bc6d653caac26b.zip
Rename file
Now that we use the 1.x ALSA APIs, naming the file `audioioalsa9.cpp` (revering to ALSA version 0.9) is misleading. Signed-off-by: Bobby Bingham <koorogi@koorogi.info>
Diffstat (limited to 'flow/audioioalsa9.cpp')
-rw-r--r--flow/audioioalsa9.cpp595
1 files changed, 0 insertions, 595 deletions
diff --git a/flow/audioioalsa9.cpp b/flow/audioioalsa9.cpp
deleted file mode 100644
index 9162d41..0000000
--- a/flow/audioioalsa9.cpp
+++ /dev/null
@@ -1,595 +0,0 @@
- /*
-
- Copyright (C) 2001 Takashi Iwai <tiwai@suse.de>
- Copyright (C) 2004 Allan Sandfeld Jensen <kde@carewolf.com>
-
- based on audioalsa.cpp:
- 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 <config.h>
-#endif
-
-/**
- * only compile 'alsa' AudioIO class if configure thinks it is a good idea
- */
-#ifdef HAVE_LIBASOUND2
-
-#ifdef HAVE_ALSA_ASOUNDLIB_H
-#include <alsa/asoundlib.h>
-#elif defined(HAVE_SYS_ASOUNDLIB_H)
-#include <sys/asoundlib.h>
-#endif
-
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <sys/time.h>
-#include <sys/stat.h>
-
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <iostream>
-#include <algorithm>
-
-#include "debug.h"
-#include "audioio.h"
-#include "audiosubsys.h"
-#include "dispatcher.h"
-#include "iomanager.h"
-
-namespace Arts {
-
-class AudioIOALSA : public AudioIO, public IONotify {
-protected:
- // List of file descriptors
- struct poll_descriptors {
- poll_descriptors() : nfds(0), pfds(0) {};
- int nfds;
- struct pollfd *pfds;
- } audio_write_pds, audio_read_pds;
-
- snd_pcm_t *m_pcm_playback;
- snd_pcm_t *m_pcm_capture;
- snd_pcm_format_t m_format;
- snd_pcm_uframes_t m_period_size;
- unsigned m_periods;
-
- void startIO();
- int setPcmParams(snd_pcm_t *pcm);
- static int poll2iomanager(int pollTypes);
- static int iomanager2poll(int ioTypes);
- void getDescriptors(snd_pcm_t *pcm, poll_descriptors *pds);
- void watchDescriptors(poll_descriptors *pds);
-
- void notifyIO(int fd, int types);
-
- int xrun(snd_pcm_t *pcm);
-#ifdef HAVE_SND_PCM_RESUME
- int resume(snd_pcm_t *pcm);
-#endif
-
-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) = "default"; // ALSA pcm device name - not file name
- param(fragmentSize) = 1024;
- param(fragmentCount) = 7;
- param(channels) = 2;
- param(direction) = directionWrite;
- param(format) = 16;
- /*
- * default parameters
- */
- m_format = SND_PCM_FORMAT_S16_LE;
- m_pcm_playback = NULL;
- m_pcm_capture = NULL;
-}
-
-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);
-
- m_pcm_playback = NULL;
- m_pcm_capture = NULL;
-
- /* initialize format */
- switch(_format) {
- case 16: // 16bit, signed little endian
- m_format = SND_PCM_FORMAT_S16_LE;
- break;
- case 17: // 16bit, signed big endian
- m_format = SND_PCM_FORMAT_S16_BE;
- break;
- case 8: // 8bit, unsigned
- m_format = SND_PCM_FORMAT_U8;
- break;
- default: // test later
- m_format = SND_PCM_FORMAT_UNKNOWN;
- break;
- }
-
- /* open pcm device */
- int err;
- if (_direction & directionWrite) {
- if ((err = snd_pcm_open(&m_pcm_playback, _deviceName.c_str(),
- SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0) {
- _error = "device: ";
- _error += _deviceName.c_str();
- _error += " can't be opened for playback (";
- _error += snd_strerror(err);
- _error += ")";
- return false;
- }
- snd_pcm_nonblock(m_pcm_playback, 0);
- }
- if (_direction & directionRead) {
- if ((err = snd_pcm_open(&m_pcm_capture, _deviceName.c_str(),
- SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0) {
- _error = "device: ";
- _error += _deviceName.c_str();
- _error += " can't be opened for capture (";
- _error += snd_strerror(err);
- _error += ")";
- snd_pcm_close(m_pcm_playback);
- return false;
- }
- snd_pcm_nonblock(m_pcm_capture, 0);
- }
-
- artsdebug("ALSA driver: %s", _deviceName.c_str());
-
- /* check device capabilities */
- // checkCapabilities();
-
- /* set PCM communication parameters */
- if (((_direction & directionWrite) && setPcmParams(m_pcm_playback)) ||
- ((_direction & directionRead) && setPcmParams(m_pcm_capture))) {
- snd_pcm_close(m_pcm_playback);
- snd_pcm_close(m_pcm_capture);
- return false;
- }
-
- 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);
-
-
- startIO();
- /* restore the format value */
- switch (m_format) {
- case SND_PCM_FORMAT_S16_LE:
- _format = 16;
- break;
- case SND_PCM_FORMAT_S16_BE:
- _format = 17;
- break;
- case SND_PCM_FORMAT_U8:
- _format = 8;
- break;
- default:
- _error = "Unknown PCM format";
- return false;
- }
-
- /* start recording */
- if (_direction & directionRead)
- snd_pcm_start(m_pcm_capture);
-
- return true;
-}
-
-void AudioIOALSA::close()
-{
- arts_debug("Closing ALSA-driver");
- int& _direction = param(direction);
- if ((_direction & directionRead) && m_pcm_capture) {
- (void)snd_pcm_drop(m_pcm_capture);
- (void)snd_pcm_close(m_pcm_capture);
- m_pcm_capture = NULL;
- }
- if ((_direction & directionWrite) && m_pcm_playback) {
- (void)snd_pcm_drop(m_pcm_playback);
- (void)snd_pcm_close(m_pcm_playback);
- m_pcm_playback = NULL;
- }
- Dispatcher::the()->ioManager()->remove(this, IOType::all);
-
- delete[] audio_read_pds.pfds;
- delete[] audio_write_pds.pfds;
- audio_read_pds.pfds = NULL; audio_write_pds.pfds = NULL;
- audio_read_pds.nfds = 0; audio_write_pds.nfds = 0;
-}
-
-void AudioIOALSA::setParam(AudioParam p, int& value)
-{
- param(p) = value;
- if (m_pcm_playback != NULL) {
- setPcmParams(m_pcm_playback);
- }
- if (m_pcm_capture != NULL) {
- setPcmParams(m_pcm_capture);
- }
-}
-
-int AudioIOALSA::getParam(AudioParam p)
-{
- snd_pcm_sframes_t avail;
- switch(p) {
-
- case canRead:
- if (! m_pcm_capture) return -1;
- while ((avail = snd_pcm_avail_update(m_pcm_capture)) < 0) {
- if (avail == -EPIPE)
- avail = xrun(m_pcm_capture);
-#ifdef HAVE_SND_PCM_RESUME
- else if (avail == -ESTRPIPE)
- avail = resume(m_pcm_capture);
-#endif
- if (avail < 0) {
- arts_info("Capture error: %s", snd_strerror(avail));
- return -1;
- }
- }
- return snd_pcm_frames_to_bytes(m_pcm_capture, avail);
-
- case canWrite:
- if (! m_pcm_playback) return -1;
- while ((avail = snd_pcm_avail_update(m_pcm_playback)) < 0) {
- if (avail == -EPIPE)
- avail = xrun(m_pcm_playback);
-#ifdef HAVE_SND_PCM_RESUME
- else if (avail == -ESTRPIPE)
- avail = resume(m_pcm_playback);
-#endif
- if (avail < 0) {
- arts_info("Playback error: %s", snd_strerror(avail));
- return -1;
- }
- }
- return snd_pcm_frames_to_bytes(m_pcm_playback, avail);
-
- case selectReadFD:
- return -1;
-
- case selectWriteFD:
- return -1;
-
- 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).
- * If we can open the device, it'll work - and we'll have to use
- * a higher number than OSS to avoid buggy OSS emulation being used.
- */
- int card = -1;
- if (snd_card_next(&card) < 0 || card < 0) {
- // No ALSA drivers in use...
- return 0;
- }
- return 15;
- }
-
- default:
- return param(p);
- }
-}
-
-void AudioIOALSA::startIO()
-{
- /* get & watch PCM file descriptor(s) */
- if (m_pcm_playback) {
- getDescriptors(m_pcm_playback, &audio_write_pds);
- watchDescriptors(&audio_write_pds);
- }
- if (m_pcm_capture) {
- getDescriptors(m_pcm_capture, &audio_read_pds);
- watchDescriptors(&audio_read_pds);
- }
-
-}
-
-int AudioIOALSA::poll2iomanager(int pollTypes)
-{
- int types = 0;
-
- if(pollTypes & POLLIN)
- types |= IOType::read;
- if(pollTypes & POLLOUT)
- types |= IOType::write;
- if(pollTypes & POLLERR)
- types |= IOType::except;
-
- return types;
-}
-
-int AudioIOALSA::iomanager2poll(int ioTypes)
-{
- int types = 0;
-
- if(ioTypes & IOType::read)
- types |= POLLIN;
- if(ioTypes & IOType::write)
- types |= POLLOUT;
- if(ioTypes & IOType::except)
- types |= POLLERR;
-
- return types;
-}
-
-void AudioIOALSA::getDescriptors(snd_pcm_t *pcm, poll_descriptors *pds)
-{
- pds->nfds = snd_pcm_poll_descriptors_count(pcm);
- pds->pfds = new struct pollfd[pds->nfds];
-
- if (snd_pcm_poll_descriptors(pcm, pds->pfds, pds->nfds) != pds->nfds) {
- arts_info("Cannot get poll descriptor(s)\n");
- }
-
-}
-
-void AudioIOALSA::watchDescriptors(poll_descriptors *pds)
-{
- for(int i=0; i<pds->nfds; i++) {
- // Check in which direction this handle is supposed to be watched
- int types = poll2iomanager(pds->pfds[i].events);
- Dispatcher::the()->ioManager()->watchFD(pds->pfds[i].fd, types, this);
- }
-}
-
-int AudioIOALSA::xrun(snd_pcm_t *pcm)
-{
- int err;
- artsdebug("xrun!!\n");
- if ((err = snd_pcm_prepare(pcm)) < 0)
- return err;
- if (pcm == m_pcm_capture)
- snd_pcm_start(pcm); // ignore error here..
- return 0;
-}
-
-#ifdef HAVE_SND_PCM_RESUME
-int AudioIOALSA::resume(snd_pcm_t *pcm)
-{
- int err;
- artsdebug("resume!\n");
- while ((err = snd_pcm_resume(pcm)) == -EAGAIN)
- sleep(1); /* wait until suspend flag is not released */
- if (err < 0) {
- if ((err = snd_pcm_prepare(pcm)) < 0)
- return err;
- if (pcm == m_pcm_capture)
- snd_pcm_start(pcm); // ignore error here..
- }
- return 0;
-}
-#endif
-
-int AudioIOALSA::read(void *buffer, int size)
-{
- int frames = snd_pcm_bytes_to_frames(m_pcm_capture, size);
- int length;
- while ((length = snd_pcm_readi(m_pcm_capture, buffer, frames)) < 0) {
- if (length == -EINTR)
- continue; // Try again
- else if (length == -EPIPE)
- length = xrun(m_pcm_capture);
-#ifdef HAVE_SND_PCM_RESUME
- else if (length == -ESTRPIPE)
- length = resume(m_pcm_capture);
-#endif
- if (length < 0) {
- arts_info("Capture error: %s", snd_strerror(length));
- return -1;
- }
- }
- return snd_pcm_frames_to_bytes(m_pcm_capture, length);
-}
-
-int AudioIOALSA::write(void *buffer, int size)
-{
- int frames = snd_pcm_bytes_to_frames(m_pcm_playback, size);
- int length;
- while ((length = snd_pcm_writei(m_pcm_playback, buffer, frames)) < 0) {
- if (length == -EINTR)
- continue; // Try again
- else if (length == -EPIPE)
- length = xrun(m_pcm_playback);
-#ifdef HAVE_SND_PCM_RESUME
- else if (length == -ESTRPIPE)
- length = resume(m_pcm_playback);
-#endif
- if (length < 0) {
- arts_info("Playback error: %s", snd_strerror(length));
- return -1;
- }
- }
-
- // Start the sink if it needs it
- if (snd_pcm_state( m_pcm_playback ) == SND_PCM_STATE_PREPARED)
- snd_pcm_start(m_pcm_playback);
-
- if (length == frames) // Sometimes the fragments are "odd" in alsa
- return size;
- else
- return snd_pcm_frames_to_bytes(m_pcm_playback, length);
-}
-
-void AudioIOALSA::notifyIO(int fd, int type)
-{
- int todo = 0;
-
- // Translate from iomanager-types to poll-types,
- // inorder to fake a snd_pcm_poll_descriptors_revents call.
- if(m_pcm_playback) {
- for(int i=0; i < audio_write_pds.nfds; i++) {
- if(fd == audio_write_pds.pfds[i].fd) {
- audio_write_pds.pfds[i].revents = iomanager2poll(type);
- todo |= AudioSubSystem::ioWrite;
- }
- }
- if (todo & AudioSubSystem::ioWrite) {
- unsigned short revents;
- snd_pcm_poll_descriptors_revents(m_pcm_playback,
- audio_write_pds.pfds,
- audio_write_pds.nfds,
- &revents);
- if (! (revents & POLLOUT)) todo &= ~AudioSubSystem::ioWrite;
- }
- }
- if(m_pcm_capture) {
- for(int i=0; i < audio_read_pds.nfds; i++) {
- if(fd == audio_read_pds.pfds[i].fd) {
- audio_read_pds.pfds[i].revents = iomanager2poll(type);
- todo |= AudioSubSystem::ioRead;
- }
- }
- if (todo & AudioSubSystem::ioRead) {
- unsigned short revents;
- snd_pcm_poll_descriptors_revents(m_pcm_capture,
- audio_read_pds.pfds,
- audio_read_pds.nfds,
- &revents);
- if (! (revents & POLLIN)) todo &= ~AudioSubSystem::ioRead;
- }
- }
-
- if (type & IOType::except) todo |= AudioSubSystem::ioExcept;
-
- if (todo != 0) AudioSubSystem::the()->handleIO(todo);
-}
-
-int AudioIOALSA::setPcmParams(snd_pcm_t *pcm)
-{
- int &_samplingRate = param(samplingRate);
- int &_channels = param(channels);
- int &_fragmentSize = param(fragmentSize);
- int &_fragmentCount = param(fragmentCount);
- string& _error = paramStr(lastError);
-
- snd_pcm_hw_params_t *hw;
- snd_pcm_hw_params_alloca(&hw);
- snd_pcm_hw_params_any(pcm, hw);
-
- if (snd_pcm_hw_params_set_access(pcm, hw, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
- _error = "Unable to set interleaved!";
- return 1;
- }
- if (m_format == SND_PCM_FORMAT_UNKNOWN) {
- // test the available formats
- // try 16bit first, then fall back to 8bit
- if (! snd_pcm_hw_params_test_format(pcm, hw, SND_PCM_FORMAT_S16_LE))
- m_format = SND_PCM_FORMAT_S16_LE;
- else if (! snd_pcm_hw_params_test_format(pcm, hw, SND_PCM_FORMAT_S16_BE))
- m_format = SND_PCM_FORMAT_S16_BE;
- else if (! snd_pcm_hw_params_test_format(pcm, hw, SND_PCM_FORMAT_U8))
- m_format = SND_PCM_FORMAT_U8;
- else
- m_format = SND_PCM_FORMAT_UNKNOWN;
- }
- if (snd_pcm_hw_params_set_format(pcm, hw, m_format) < 0) {
- _error = "Unable to set format!";
- return 1;
- }
-
- unsigned rate = _samplingRate;
- if (snd_pcm_hw_params_set_rate_near(pcm, hw, &rate, 0) < 0) {
- _error = "Unable to set sampling rate!";
- return 1;
- }
- const unsigned int tolerance = _samplingRate/10+1000;
- if (abs((int)rate - (int)_samplingRate) > (int)tolerance) {
- _error = "Can't set requested sampling rate!";
- char details[80];
- sprintf(details," (requested rate %d, got rate %d)",
- _samplingRate, rate);
- _error += details;
- return 1;
- }
- _samplingRate = rate;
-
- if (snd_pcm_hw_params_set_channels(pcm, hw, _channels) < 0) {
- _error = "Unable to set channels!";
- return 1;
- }
-
- m_period_size = _fragmentSize;
- if (m_format != SND_PCM_FORMAT_U8)
- m_period_size <<= 1;
- if (_channels > 1)
- m_period_size /= _channels;
- if (snd_pcm_hw_params_set_period_size_near(pcm, hw, &m_period_size, 0) < 0) {
- _error = "Unable to set period size!";
- return 1;
- }
- m_periods = _fragmentCount;
- if (snd_pcm_hw_params_set_periods_near(pcm, hw, &m_periods, 0) < 0) {
- _error = "Unable to set periods!";
- return 1;
- }
-
- if (snd_pcm_hw_params(pcm, hw) < 0) {
- _error = "Unable to set hw params!";
- return 1;
- }
-
- _fragmentSize = m_period_size;
- _fragmentCount = m_periods;
- if (m_format != SND_PCM_FORMAT_U8)
- _fragmentSize >>= 1;
- if (_channels > 1)
- _fragmentSize *= _channels;
-
- return 0; // ok, we're ready..
-}
-
-#endif /* HAVE_LIBASOUND2 */