svxlink/src/async/audio/AsyncAudioIO.cpp

481 lines
11 KiB
C++

/**
@file AsyncAudioIO.cpp
@brief Contains a class for handling audio input/output to an audio device
@author Tobias Blomberg
@date 2003-03-23
This file contains a class for handling audio input and output to an audio
device. See usage instruction in the class documentation.
\verbatim
Async - A library for programming event driven applications
Copyright (C) 2003 Tobias Blomberg
This program 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.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
\endverbatim
*/
/****************************************************************************
*
* System Includes
*
****************************************************************************/
#include <sigc++/sigc++.h>
#include <stdint.h>
#include <cstdio>
#include <cassert>
#include <cerrno>
#include <cmath>
/****************************************************************************
*
* Project Includes
*
****************************************************************************/
/****************************************************************************
*
* Local Includes
*
****************************************************************************/
#include "AsyncAudioDevice.h"
#include "AsyncFdWatch.h"
#include "AsyncAudioReader.h"
#include "AsyncAudioFifo.h"
#include "AsyncAudioValve.h"
#include "AsyncAudioIO.h"
#include "AsyncAudioDebugger.h"
/****************************************************************************
*
* Namespaces to use
*
****************************************************************************/
using namespace std;
using namespace Async;
/****************************************************************************
*
* Defines & typedefs
*
****************************************************************************/
/****************************************************************************
*
* Local class definitions
*
****************************************************************************/
class Async::AudioIO::InputFifo : public AudioFifo
{
public:
InputFifo(int size, AudioDevice *audio_dev)
: AudioFifo(size), audio_dev(audio_dev), do_flush(false)
{
}
virtual int writeSamples(const float *samples, int count)
{
do_flush = false;
if ((audio_dev->mode() != AudioDevice::MODE_WR) &&
(audio_dev->mode() != AudioDevice::MODE_RDWR))
{
return count;
}
int ret = AudioFifo::writeSamples(samples, count);
audio_dev->audioToWriteAvailable();
return ret;
}
virtual void flushSamples(void)
{
if ((audio_dev->mode() != AudioDevice::MODE_WR) &&
(audio_dev->mode() != AudioDevice::MODE_RDWR))
{
do_flush = false;
sourceAllSamplesFlushed();
return;
}
do_flush = true;
if (!empty())
{
audio_dev->audioToWriteAvailable();
}
AudioFifo::flushSamples();
}
virtual void allSamplesFlushed(void)
{
do_flush = false;
AudioFifo::allSamplesFlushed();
}
bool doFlush(void) const { return do_flush; }
private:
AudioDevice *audio_dev;
bool do_flush;
}; /* Async::AudioIO::InputFifo */
class Async::AudioIO::DelayedFlushAudioReader
: public AudioReader, public sigc::trackable
{
public:
DelayedFlushAudioReader(AudioDevice *audio_dev)
: audio_dev(audio_dev), flush_timer(0, Timer::TYPE_ONESHOT, false),
is_idle(true)
{
flush_timer.expired.connect(
mem_fun(*this, &DelayedFlushAudioReader::flushDone));
}
~DelayedFlushAudioReader(void) {}
bool isIdle(void) const { return is_idle; }
virtual int writeSamples(const float *samples, int count)
{
is_idle = false;
flush_timer.setEnable(false);
return AudioReader::writeSamples(samples, count);
}
virtual void flushSamples(void)
{
is_idle = true;
audio_dev->flushSamples();
long flushtime =
1000 * audio_dev->samplesToWrite() / audio_dev->sampleRate();
if (flushtime < 0)
{
flushtime = 0;
}
flush_timer.setEnable(false);
flush_timer.setTimeout(flushtime);
flush_timer.setEnable(true);
}
private:
AudioDevice *audio_dev;
Timer flush_timer;
bool is_idle;
void flushDone(Timer *timer)
{
flush_timer.setEnable(false);
AudioReader::flushSamples();
} /* AudioIO::flushDone */
}; /* class Async::AudioIO::DelayedFlushAudioReader */
/****************************************************************************
*
* Prototypes
*
****************************************************************************/
/****************************************************************************
*
* Exported Global Variables
*
****************************************************************************/
/****************************************************************************
*
* Local Global Variables
*
****************************************************************************/
/****************************************************************************
*
* Public member functions
*
****************************************************************************/
void AudioIO::setSampleRate(int rate)
{
AudioDevice::setSampleRate(rate);
} /* AudioIO::setSampleRate */
void AudioIO::setBlocksize(int size)
{
AudioDevice::setBlocksize(size);
} /* AudioIO::setBlocksize */
int AudioIO::readBlocksize(void)
{
return audio_dev->readBlocksize();
} /* AudioIO::readBlocksize */
int AudioIO::writeBlocksize(void)
{
return audio_dev->writeBlocksize();
} /* AudioIO::writeBlocksize */
void AudioIO::setBlockCount(int count)
{
AudioDevice::setBlockCount(count);
} /* AudioIO::setBlockCount */
void AudioIO::setChannels(int channels)
{
return AudioDevice::setChannels(channels);
} /* AudioIO::setBufferCount */
AudioIO::AudioIO(const string& dev_name, int channel)
: io_mode(MODE_NONE), audio_dev(0),
/* lead_in_pos(0), */ m_gain(1.0), sample_rate(-1),
m_channel(channel), input_valve(0), input_fifo(0), audio_reader(0)
{
audio_dev = AudioDevice::registerAudioIO(dev_name, this);
if (audio_dev == 0)
{
return;
}
sample_rate = audio_dev->sampleRate();
input_valve = new AudioValve;
input_valve->setOpen(false);
AudioSink::setHandler(input_valve);
AudioSource *prev_src = input_valve;
input_fifo = new InputFifo(1, audio_dev);
input_fifo->setOverwrite(false);
prev_src->registerSink(input_fifo, true);
prev_src = input_fifo;
audio_reader = new DelayedFlushAudioReader(audio_dev);
prev_src->registerSink(audio_reader, true);
prev_src = 0;
//new AudioDebugger(input_fifo);
} /* AudioIO::AudioIO */
AudioIO::~AudioIO(void)
{
close();
AudioSink::clearHandler();
delete input_valve;
AudioDevice::unregisterAudioIO(this);
} /* AudioIO::~AudioIO */
bool AudioIO::isFullDuplexCapable(void)
{
return audio_dev->isFullDuplexCapable();
} /* AudioIO::isFullDuplexCapable */
bool AudioIO::open(Mode mode)
{
if (m_channel >= AudioDevice::getChannels())
{
std::cerr << "*** ERROR: Audio channel out of range when opening audio "
"device \"" << audio_dev->devName() << ". "
<< "The card have " << AudioDevice::getChannels()
<< " channel(s) configured, but (zero based) channel number "
<< m_channel << " was requested." << std::endl;
return false;
}
if (audio_dev == 0)
{
return false;
}
if (mode == io_mode)
{
return true;
}
close();
if (mode == MODE_NONE)
{
return true;
}
/* FIXME: Yes, I knwow... Ugly cast... */
bool open_ok = audio_dev->open((AudioDevice::Mode)mode);
if (open_ok)
{
io_mode = mode;
input_fifo->setSize(audio_dev->writeBlocksize() * 2 + 1);
input_fifo->setPrebufSamples(audio_dev->writeBlocksize() * 2 + 1);
}
input_valve->setOpen(true);
return open_ok;
} /* AudioIO::open */
void AudioIO::close(void)
{
if (io_mode == MODE_NONE)
{
return;
}
/*
if ((io_mode == MODE_RD) || (io_mode == MODE_RDWR))
{
read_con.disconnect();
}
*/
io_mode = MODE_NONE;
input_valve->setOpen(false);
input_fifo->clear();
audio_dev->close();
} /* AudioIO::close */
/****************************************************************************
*
* Protected member functions
*
****************************************************************************/
/*
*------------------------------------------------------------------------
* Method:
* Purpose:
* Input:
* Output:
* Author:
* Created:
* Remarks:
* Bugs:
*------------------------------------------------------------------------
*/
/****************************************************************************
*
* Private member functions
*
****************************************************************************/
/****************************************************************************
*
* Private member functions used by friend class AudioDevice
*
****************************************************************************/
int AudioIO::readSamples(float *samples, int count)
{
//printf("AudioIO[%s:%d]::readSamples\n", audio_dev->devName().c_str(), m_channel);
int samples_read = audio_reader->readSamples(samples, count);
//printf("AudioIO[%s:%d]::readSamples: count=%d sample_read=%d\n", audio_dev->devName().c_str(), m_channel, count, samples_read);
if (m_gain != 1.0)
{
for (int i=0; i<samples_read; ++i)
{
samples[i] = m_gain * samples[i];
}
}
return samples_read;
} /* AudioIO::readSamples */
bool AudioIO::doFlush(void) const
{
//printf("AudioIO::doFlush\n");
return input_fifo->doFlush();
} /* AudioIO::doFlush */
bool AudioIO::isIdle(void) const
{
//printf("AudioIO::doFlush\n");
return audio_reader->isIdle();
} /* AudioIO::isIdle */
int AudioIO::audioRead(float *samples, int count)
{
return sinkWriteSamples(samples, count);
} /* AudioIO::audioRead */
unsigned AudioIO::samplesAvailable(void)
{
//printf("AudioIO[%s:%d]::samplesAvailable: %d\n", audio_dev->devName().c_str(), m_channel, input_fifo->samplesInFifo(true));
return input_fifo->samplesInFifo();
} /* AudioIO::samplesAvailable */
/*
* This file has not been truncated
*/