[DEV] remove many exception

This commit is contained in:
Edouard DUPIN 2014-03-12 23:55:49 +01:00
parent fca89ede03
commit 366d9a7049
24 changed files with 1215 additions and 1397 deletions

View File

@ -7,6 +7,7 @@
*/
#include <airtaudio/Interface.h>
#include <airtaudio/debug.h>
#include <iostream>
#include <cstdlib>
#include <cstring>
@ -16,8 +17,20 @@
// Static variable definitions.
const uint32_t airtaudio::api::MAX_SAMPLE_RATES = 14;
const uint32_t airtaudio::api::SAMPLE_RATES[] = {
4000, 5512, 8000, 9600, 11025, 16000, 22050,
32000, 44100, 48000, 88200, 96000, 176400, 192000
4000,
5512,
8000,
9600,
11025,
16000,
22050,
32000,
44100,
48000,
88200,
96000,
176400,
192000
};
@ -27,7 +40,6 @@ airtaudio::Api::Api(void) {
m_stream.apiHandle = 0;
m_stream.userBuffer[0] = 0;
m_stream.userBuffer[1] = 0;
m_showWarnings = true;
}
airtaudio::Api::~Api(void) {
@ -41,50 +53,42 @@ enum airtaudio::errorType airtaudio::Api::openStream(airtaudio::StreamParameters
uint32_t *bufferFrames,
airtaudio::AirTAudioCallback callback,
void *userData,
airtaudio::StreamOptions *options,
airtaudio::AirTAudioErrorCallback errorCallback) {
airtaudio::StreamOptions *options) {
if (m_stream.state != airtaudio::api::STREAM_CLOSED) {
m_errorText = "airtaudio::Api::openStream: a stream is already open!";
error(airtaudio::errorInvalidUse);
return;
ATA_ERROR("airtaudio::Api::openStream: a stream is already open!");
return airtaudio::errorInvalidUse;
}
if (oParams && oParams->nChannels < 1) {
m_errorText = "airtaudio::Api::openStream: a non-NULL output StreamParameters structure cannot have an nChannels value less than one.";
error(airtaudio::errorInvalidUse);
return;
ATA_ERROR("airtaudio::Api::openStream: a non-NULL output StreamParameters structure cannot have an nChannels value less than one.");
return airtaudio::errorInvalidUse;
}
if (iParams && iParams->nChannels < 1) {
m_errorText = "airtaudio::Api::openStream: a non-NULL input StreamParameters structure cannot have an nChannels value less than one.";
error(airtaudio::errorInvalidUse);
return;
ATA_ERROR("airtaudio::Api::openStream: a non-NULL input StreamParameters structure cannot have an nChannels value less than one.");
return airtaudio::errorInvalidUse;
}
if (oParams == NULL && iParams == NULL) {
m_errorText = "airtaudio::Api::openStream: input and output StreamParameters structures are both NULL!";
error(airtaudio::errorInvalidUse);
return;
ATA_ERROR("airtaudio::Api::openStream: input and output StreamParameters structures are both NULL!");
return airtaudio::errorInvalidUse;
}
if (formatBytes(format) == 0) {
m_errorText = "airtaudio::Api::openStream: 'format' parameter value is undefined.";
error(airtaudio::errorInvalidUse);
return;
ATA_ERROR("airtaudio::Api::openStream: 'format' parameter value is undefined.");
return airtaudio::errorInvalidUse;
}
uint32_t nDevices = getDeviceCount();
uint32_t oChannels = 0;
if (oParams) {
oChannels = oParams->nChannels;
if (oParams->deviceId >= nDevices) {
m_errorText = "airtaudio::Api::openStream: output device parameter value is invalid.";
error(airtaudio::errorInvalidUse);
return;
ATA_ERROR("airtaudio::Api::openStream: output device parameter value is invalid.");
return airtaudio::errorInvalidUse;
}
}
uint32_t iChannels = 0;
if (iParams) {
iChannels = iParams->nChannels;
if (iParams->deviceId >= nDevices) {
m_errorText = "airtaudio::Api::openStream: input device parameter value is invalid.";
error(airtaudio::errorInvalidUse);
return;
ATA_ERROR("airtaudio::Api::openStream: input device parameter value is invalid.");
return airtaudio::errorInvalidUse;
}
}
clearStreamInfo();
@ -99,8 +103,8 @@ enum airtaudio::errorType airtaudio::Api::openStream(airtaudio::StreamParameters
bufferFrames,
options);
if (result == false) {
error(airtaudio::errorSystemError);
return;
ATA_ERROR("system ERROR");
return airtaudio::errorSystemError;
}
}
if (iChannels > 0) {
@ -116,17 +120,17 @@ enum airtaudio::errorType airtaudio::Api::openStream(airtaudio::StreamParameters
if (oChannels > 0) {
closeStream();
}
error(airtaudio::errorSystemError);
return;
ATA_ERROR("system error");
return airtaudio::errorSystemError;
}
}
m_stream.callbackInfo.callback = (void *) callback;
m_stream.callbackInfo.userData = userData;
m_stream.callbackInfo.errorCallback = (void *) errorCallback;
if (options != NULL) {
options->numberOfBuffers = m_stream.nBuffers;
}
m_stream.state = airtaudio::api::STREAM_STOPPED;
return airtaudio::errorNone;
}
uint32_t airtaudio::Api::getDefaultInputDevice(void) {
@ -167,19 +171,25 @@ void airtaudio::Api::tickStreamTime(void) {
}
long airtaudio::Api::getStreamLatency(void) {
verifyStream();
if (verifyStream() != airtaudio::errorNone) {
return 0;
}
long totalLatency = 0;
if (m_stream.mode == airtaudio::api::OUTPUT || m_stream.mode == airtaudio::api::DUPLEX) {
if ( m_stream.mode == airtaudio::api::OUTPUT
|| m_stream.mode == airtaudio::api::DUPLEX) {
totalLatency = m_stream.latency[0];
}
if (m_stream.mode == airtaudio::api::INPUT || m_stream.mode == airtaudio::api::DUPLEX) {
if ( m_stream.mode == airtaudio::api::INPUT
|| m_stream.mode == airtaudio::api::DUPLEX) {
totalLatency += m_stream.latency[1];
}
return totalLatency;
}
double airtaudio::Api::getStreamTime(void) {
verifyStream();
if (verifyStream() != airtaudio::errorNone) {
return 0.0f;
}
#if defined(HAVE_GETTIMEOFDAY)
// Return a very accurate estimate of the stream time by
// adding in the elapsed time since the last tick.
@ -199,49 +209,18 @@ double airtaudio::Api::getStreamTime(void) {
}
uint32_t airtaudio::Api::getStreamSampleRate(void) {
verifyStream();
if (verifyStream() != airtaudio::errorNone) {
return 0;
}
return m_stream.sampleRate;
}
// *************************************************** //
//
// Protected common (OS-independent) RtAudio methods.
//
// *************************************************** //
// This method can be modified to control the behavior of error
// message printing.
void airtaudio::Api::error(airtaudio::errorType _type) {
m_errorStream.str(""); // clear the ostringstream
airtaudio::AirTAudioErrorCallback errorCallback = (airtaudio::AirTAudioErrorCallback) m_stream.callbackInfo.errorCallback;
if (errorCallback) {
// abortStream() can generate new error messages. Ignore them. Just keep original one.
static bool firstErrorOccured = false;
if (firstErrorOccured) {
return;
}
firstErrorOccured = true;
const std::string errorMessage = m_errorText;
if (_type != airtaudio::errorWarning && m_stream.state != airtaudio::api::STREAM_STOPPED) {
m_stream.callbackInfo.isRunning = false; // exit from the thread
abortStream();
}
errorCallback(_type, errorMessage);
firstErrorOccured = false;
return;
}
if (_type == airtaudio::errorWarning && m_showWarnings == true) {
std::cerr << '\n' << m_errorText << "\n\n";
} else if (_type != airtaudio::errorWarning) {
//throw(RtError(m_errorText, type));
std::cout << m_errorText << std::endl;
}
}
void airtaudio::Api::verifyStream(void) {
enum airtaudio::errorType airtaudio::Api::verifyStream(void) {
if (m_stream.state == airtaudio::api::STREAM_CLOSED) {
m_errorText = "airtaudio::Api:: a stream is not open!";
error(airtaudio::errorInvalidUse);
ATA_ERROR("airtaudio::Api:: a stream is not open!");
return airtaudio::errorInvalidUse;
}
return airtaudio::errorNone;
}
void airtaudio::Api::clearStreamInfo(void) {
@ -258,7 +237,6 @@ void airtaudio::Api::clearStreamInfo(void) {
m_stream.callbackInfo.callback = 0;
m_stream.callbackInfo.userData = 0;
m_stream.callbackInfo.isRunning = false;
m_stream.callbackInfo.errorCallback = 0;
for (int32_t iii=0; iii<2; ++iii) {
m_stream.device[iii] = 11111;
m_stream.doConvertBuffer[iii] = false;
@ -294,8 +272,8 @@ uint32_t airtaudio::Api::formatBytes(airtaudio::format _format)
} else if (_format == airtaudio::SINT8) {
return 1;
}
m_errorText = "airtaudio::Api::formatBytes: undefined format.";
error(airtaudio::errorWarning);
ATA_ERROR("airtaudio::Api::formatBytes: undefined format.");
// TODO : airtaudio::errorWarning;
return 0;
}

View File

@ -130,8 +130,7 @@ namespace airtaudio {
uint32_t *_bufferFrames,
airtaudio::AirTAudioCallback _callback,
void *_userData,
airtaudio::StreamOptions *_options,
airtaudio::AirTAudioErrorCallback _errorCallback);
airtaudio::StreamOptions *_options);
virtual enum airtaudio::errorType closeStream(void);
virtual enum airtaudio::errorType startStream(void) = 0;
virtual enum airtaudio::errorType stopStream(void) = 0;
@ -145,14 +144,8 @@ namespace airtaudio {
bool isStreamRunning(void) const {
return m_stream.state == airtaudio::api::STREAM_RUNNING;
}
void showWarnings(bool _value) {
m_showWarnings = _value;
}
protected:
std::ostringstream m_errorStream;
std::string m_errorText;
bool m_showWarnings;
airtaudio::api::Stream m_stream;
/*!
@ -175,17 +168,13 @@ namespace airtaudio {
void tickStreamTime(void);
//! Protected common method to clear an RtApiStream structure.
void clearStreamInfo();
void clearStreamInfo(void);
/*!
Protected common method that throws an RtError (type =
INVALID_USE) if a stream is not open.
*/
void verifyStream(void);
//! Protected common error method to allow global control over error handling.
void error(airtaudio::errorType _type);
enum airtaudio::errorType verifyStream(void);
/**
* @brief Protected method used to perform format, channel number, and/or interleaving
* conversions between the user and device buffers.

View File

@ -21,7 +21,6 @@ namespace airtaudio {
std::thread* thread;
void* callback;
void* userData;
void* errorCallback;
void* apiInfo; // void pointer for API specific callback information
bool isRunning;
bool doRealtime;
@ -32,7 +31,6 @@ namespace airtaudio {
object(0),
callback(0),
userData(0),
errorCallback(0),
apiInfo(0),
isRunning(false),
doRealtime(false) {

View File

@ -7,6 +7,7 @@
*/
#include <airtaudio/Interface.h>
#include <airtaudio/debug.h>
#include <iostream>
std::vector<airtaudio::api::type> airtaudio::Interface::getCompiledApi(void) {
@ -117,10 +118,9 @@ enum airtaudio::errorType airtaudio::Interface::openStream(
uint32_t* _bufferFrames,
airtaudio::AirTAudioCallback _callback,
void* _userData,
airtaudio::StreamOptions* _options,
airtaudio::AirTAudioErrorCallback _errorCallback) {
airtaudio::StreamOptions* _options) {
if (m_rtapi == NULL) {
return;
return airtaudio::errorInputNull;
}
return m_rtapi->openStream(_outputParameters,
_inputParameters,
@ -129,8 +129,7 @@ enum airtaudio::errorType airtaudio::Interface::openStream(
_bufferFrames,
_callback,
_userData,
_options,
_errorCallback);
_options);
}

View File

@ -192,8 +192,7 @@ namespace airtaudio {
uint32_t *_bufferFrames,
airtaudio::AirTAudioCallback _callback,
void *_userData = NULL,
airtaudio::StreamOptions *_options = NULL,
airtaudio::AirTAudioErrorCallback _errorCallback = NULL);
airtaudio::StreamOptions *_options = NULL);
/**
* @brief A function that closes a stream and frees any associated stream memory.
@ -203,7 +202,7 @@ namespace airtaudio {
*/
enum airtaudio::errorType closeStream(void) {
if (m_rtapi == NULL) {
return;
return airtaudio::errorInputNull;
}
return m_rtapi->closeStream();
}
@ -217,7 +216,7 @@ namespace airtaudio {
*/
enum airtaudio::errorType startStream(void) {
if (m_rtapi == NULL) {
return;
return airtaudio::errorInputNull;
}
return m_rtapi->startStream();
}
@ -231,7 +230,7 @@ namespace airtaudio {
*/
enum airtaudio::errorType stopStream(void) {
if (m_rtapi == NULL) {
return;
return airtaudio::errorInputNull;
}
return m_rtapi->stopStream();
}
@ -244,7 +243,7 @@ namespace airtaudio {
*/
enum airtaudio::errorType abortStream(void) {
if (m_rtapi == NULL) {
return;
return airtaudio::errorInputNull;
}
return m_rtapi->abortStream();
}
@ -303,15 +302,6 @@ namespace airtaudio {
}
return m_rtapi->getStreamSampleRate();
}
/**
* @brief Specify whether warning messages should be printed to stderr.
*/
void showWarnings(bool _value = true) {
if (m_rtapi == NULL) {
return;
}
m_rtapi->showWarnings(_value);
}
protected:
void openRtApi(airtaudio::api::type _api);
};

View File

@ -12,6 +12,7 @@
#include <alsa/asoundlib.h>
#include <unistd.h>
#include <airtaudio/Interface.h>
#include <airtaudio/debug.h>
#include <limits.h>
airtaudio::Api* airtaudio::api::Alsa::Create(void) {
@ -60,18 +61,16 @@ uint32_t airtaudio::api::Alsa::getDeviceCount(void) {
sprintf(name, "hw:%d", card);
result = snd_ctl_open(&handle, name, 0);
if (result < 0) {
m_errorStream << "airtaudio::api::Alsa::getDeviceCount: control open, card = " << card << ", " << snd_strerror(result) << ".";
m_errorText = m_errorStream.str();
error(airtaudio::errorWarning);
ATA_ERROR("airtaudio::api::Alsa::getDeviceCount: control open, card = " << card << ", " << snd_strerror(result) << ".");
// TODO : Return error airtaudio::errorWarning;
goto nextcard;
}
subdevice = -1;
while(1) {
result = snd_ctl_pcm_next_device(handle, &subdevice);
if (result < 0) {
m_errorStream << "airtaudio::api::Alsa::getDeviceCount: control next device, card = " << card << ", " << snd_strerror(result) << ".";
m_errorText = m_errorStream.str();
error(airtaudio::errorWarning);
ATA_ERROR("airtaudio::api::Alsa::getDeviceCount: control next device, card = " << card << ", " << snd_strerror(result) << ".");
// TODO : Return error airtaudio::errorWarning;
break;
}
if (subdevice < 0) {
@ -79,7 +78,6 @@ uint32_t airtaudio::api::Alsa::getDeviceCount(void) {
}
nDevices++;
}
nextcard:
snd_ctl_close(handle);
snd_card_next(&card);
@ -106,18 +104,14 @@ airtaudio::DeviceInfo airtaudio::api::Alsa::getDeviceInfo(uint32_t _device) {
sprintf(name, "hw:%d", card);
result = snd_ctl_open(&chandle, name, SND_CTL_NONBLOCK);
if (result < 0) {
m_errorStream << "airtaudio::api::Alsa::getDeviceInfo: control open, card = " << card << ", " << snd_strerror(result) << ".";
m_errorText = m_errorStream.str();
error(airtaudio::errorWarning);
ATA_WARNING("airtaudio::api::Alsa::getDeviceInfo: control open, card = " << card << ", " << snd_strerror(result) << ".");
goto nextcard;
}
subdevice = -1;
while(1) {
result = snd_ctl_pcm_next_device(chandle, &subdevice);
if (result < 0) {
m_errorStream << "airtaudio::api::Alsa::getDeviceInfo: control next device, card = " << card << ", " << snd_strerror(result) << ".";
m_errorText = m_errorStream.str();
error(airtaudio::errorWarning);
ATA_WARNING("airtaudio::api::Alsa::getDeviceInfo: control next device, card = " << card << ", " << snd_strerror(result) << ".");
break;
}
if (subdevice < 0) {
@ -142,13 +136,13 @@ airtaudio::DeviceInfo airtaudio::api::Alsa::getDeviceInfo(uint32_t _device) {
nDevices++;
}
if (nDevices == 0) {
m_errorText = "airtaudio::api::Alsa::getDeviceInfo: no devices found!";
error(airtaudio::errorInvalidUse);
ATA_ERROR("airtaudio::api::Alsa::getDeviceInfo: no devices found!");
// TODO : airtaudio::errorInvalidUse;
return info;
}
if (_device >= nDevices) {
m_errorText = "airtaudio::api::Alsa::getDeviceInfo: device ID is invalid!";
error(airtaudio::errorInvalidUse);
ATA_ERROR("airtaudio::api::Alsa::getDeviceInfo: device ID is invalid!");
// TODO : airtaudio::errorInvalidUse;
return info;
}
@ -160,8 +154,8 @@ foundDevice:
|| m_stream.device[1] == _device)) {
snd_ctl_close(chandle);
if (_device >= m_devices.size()) {
m_errorText = "airtaudio::api::Alsa::getDeviceInfo: device ID was not present before stream was opened.";
error(airtaudio::errorWarning);
ATA_ERROR("airtaudio::api::Alsa::getDeviceInfo: device ID was not present before stream was opened.");
// TODO : return airtaudio::errorWarning;
return info;
}
return m_devices[ _device ];
@ -187,18 +181,16 @@ foundDevice:
}
result = snd_pcm_open(&phandle, name, stream, openMode | SND_PCM_NONBLOCK);
if (result < 0) {
m_errorStream << "airtaudio::api::Alsa::getDeviceInfo: snd_pcm_open error for device (" << name << "), " << snd_strerror(result) << ".";
m_errorText = m_errorStream.str();
error(airtaudio::errorWarning);
ATA_ERROR("airtaudio::api::Alsa::getDeviceInfo: snd_pcm_open error for device (" << name << "), " << snd_strerror(result) << ".");
// TODO : Return airtaudio::errorWarning;
goto captureProbe;
}
// The device is open ... fill the parameter structure.
result = snd_pcm_hw_params_any(phandle, params);
if (result < 0) {
snd_pcm_close(phandle);
m_errorStream << "airtaudio::api::Alsa::getDeviceInfo: snd_pcm_hw_params error for device (" << name << "), " << snd_strerror(result) << ".";
m_errorText = m_errorStream.str();
error(airtaudio::errorWarning);
ATA_ERROR("airtaudio::api::Alsa::getDeviceInfo: snd_pcm_hw_params error for device (" << name << "), " << snd_strerror(result) << ".");
// TODO : Return airtaudio::errorWarning;
goto captureProbe;
}
// Get output channel information.
@ -206,9 +198,8 @@ foundDevice:
result = snd_pcm_hw_params_get_channels_max(params, &value);
if (result < 0) {
snd_pcm_close(phandle);
m_errorStream << "airtaudio::api::Alsa::getDeviceInfo: error getting device (" << name << ") output channels, " << snd_strerror(result) << ".";
m_errorText = m_errorStream.str();
error(airtaudio::errorWarning);
ATA_ERROR("airtaudio::api::Alsa::getDeviceInfo: error getting device (" << name << ") output channels, " << snd_strerror(result) << ".");
// TODO : Return airtaudio::errorWarning;
goto captureProbe;
}
info.outputChannels = value;
@ -231,9 +222,8 @@ captureProbe:
}
result = snd_pcm_open(&phandle, name, stream, openMode | SND_PCM_NONBLOCK);
if (result < 0) {
m_errorStream << "airtaudio::api::Alsa::getDeviceInfo: snd_pcm_open error for device (" << name << "), " << snd_strerror(result) << ".";
m_errorText = m_errorStream.str();
error(airtaudio::errorWarning);
ATA_ERROR("airtaudio::api::Alsa::getDeviceInfo: snd_pcm_open error for device (" << name << "), " << snd_strerror(result) << ".");
// TODO : Return airtaudio::errorWarning;
if (info.outputChannels == 0) {
return info;
}
@ -243,9 +233,8 @@ captureProbe:
result = snd_pcm_hw_params_any(phandle, params);
if (result < 0) {
snd_pcm_close(phandle);
m_errorStream << "airtaudio::api::Alsa::getDeviceInfo: snd_pcm_hw_params error for device (" << name << "), " << snd_strerror(result) << ".";
m_errorText = m_errorStream.str();
error(airtaudio::errorWarning);
ATA_ERROR("airtaudio::api::Alsa::getDeviceInfo: snd_pcm_hw_params error for device (" << name << "), " << snd_strerror(result) << ".");
// TODO : Return airtaudio::errorWarning;
if (info.outputChannels == 0) {
return info;
}
@ -254,9 +243,8 @@ captureProbe:
result = snd_pcm_hw_params_get_channels_max(params, &value);
if (result < 0) {
snd_pcm_close(phandle);
m_errorStream << "airtaudio::api::Alsa::getDeviceInfo: error getting device (" << name << ") input channels, " << snd_strerror(result) << ".";
m_errorText = m_errorStream.str();
error(airtaudio::errorWarning);
ATA_ERROR("airtaudio::api::Alsa::getDeviceInfo: error getting device (" << name << ") input channels, " << snd_strerror(result) << ".");
// TODO : Return airtaudio::errorWarning;
if (info.outputChannels == 0) {
return info;
}
@ -290,18 +278,16 @@ probeParameters:
snd_pcm_info_set_stream(pcminfo, stream);
result = snd_pcm_open(&phandle, name, stream, openMode | SND_PCM_NONBLOCK);
if (result < 0) {
m_errorStream << "airtaudio::api::Alsa::getDeviceInfo: snd_pcm_open error for device (" << name << "), " << snd_strerror(result) << ".";
m_errorText = m_errorStream.str();
error(airtaudio::errorWarning);
ATA_ERROR("airtaudio::api::Alsa::getDeviceInfo: snd_pcm_open error for device (" << name << "), " << snd_strerror(result) << ".");
// TODO : Return airtaudio::errorWarning;
return info;
}
// The device is open ... fill the parameter structure.
result = snd_pcm_hw_params_any(phandle, params);
if (result < 0) {
snd_pcm_close(phandle);
m_errorStream << "airtaudio::api::Alsa::getDeviceInfo: snd_pcm_hw_params error for device (" << name << "), " << snd_strerror(result) << ".";
m_errorText = m_errorStream.str();
error(airtaudio::errorWarning);
ATA_ERROR("airtaudio::api::Alsa::getDeviceInfo: snd_pcm_hw_params error for device (" << name << "), " << snd_strerror(result) << ".");
// TODO : Return airtaudio::errorWarning;
return info;
}
// Test our discrete set of sample rate values.
@ -313,9 +299,8 @@ probeParameters:
}
if (info.sampleRates.size() == 0) {
snd_pcm_close(phandle);
m_errorStream << "airtaudio::api::Alsa::getDeviceInfo: no supported sample rates found for device (" << name << ").";
m_errorText = m_errorStream.str();
error(airtaudio::errorWarning);
ATA_ERROR("airtaudio::api::Alsa::getDeviceInfo: no supported sample rates found for device (" << name << ").");
// TODO : Return airtaudio::errorWarning;
return info;
}
// Probe the supported data formats ... we don't care about endian-ness just yet
@ -347,9 +332,8 @@ probeParameters:
}
// Check that we have at least one supported format
if (info.nativeFormats == 0) {
m_errorStream << "airtaudio::api::Alsa::getDeviceInfo: pcm device (" << name << ") data format not supported by RtAudio.";
m_errorText = m_errorStream.str();
error(airtaudio::errorWarning);
ATA_ERROR("airtaudio::api::Alsa::getDeviceInfo: pcm device (" << name << ") data format not supported by RtAudio.");
// TODO : Return airtaudio::errorWarning;
return info;
}
// Get the device name
@ -382,10 +366,6 @@ bool airtaudio::api::Alsa::probeDeviceOpen(uint32_t _device,
airtaudio::format _format,
uint32_t *_bufferSize,
airtaudio::StreamOptions *_options) {
#if defined(__RTAUDIO_DEBUG__)
snd_output_t *out;
snd_output_stdio_attach(&out, stderr, 0);
#endif
// I'm not using the "plug" interface ... too much inconsistent behavior.
unsigned nDevices = 0;
int32_t result, subdevice, card;
@ -401,8 +381,7 @@ bool airtaudio::api::Alsa::probeDeviceOpen(uint32_t _device,
sprintf(name, "hw:%d", card);
result = snd_ctl_open(&chandle, name, SND_CTL_NONBLOCK);
if (result < 0) {
m_errorStream << "airtaudio::api::Alsa::probeDeviceOpen: control open, card = " << card << ", " << snd_strerror(result) << ".";
m_errorText = m_errorStream.str();
ATA_ERROR("airtaudio::api::Alsa::probeDeviceOpen: control open, card = " << card << ", " << snd_strerror(result) << ".");
return FAILURE;
}
subdevice = -1;
@ -430,12 +409,12 @@ bool airtaudio::api::Alsa::probeDeviceOpen(uint32_t _device,
}
if (nDevices == 0) {
// This should not happen because a check is made before this function is called.
m_errorText = "airtaudio::api::Alsa::probeDeviceOpen: no devices found!";
ATA_ERROR("airtaudio::api::Alsa::probeDeviceOpen: no devices found!");
return FAILURE;
}
if (_device >= nDevices) {
// This should not happen because a check is made before this function is called.
m_errorText = "airtaudio::api::Alsa::probeDeviceOpen: device ID is invalid!";
ATA_ERROR("airtaudio::api::Alsa::probeDeviceOpen: device ID is invalid!");
return FAILURE;
}
}
@ -461,11 +440,10 @@ foundDevice:
result = snd_pcm_open(&phandle, name, stream, openMode);
if (result < 0) {
if (_mode == OUTPUT) {
m_errorStream << "airtaudio::api::Alsa::probeDeviceOpen: pcm device (" << name << ") won't open for output.";
ATA_ERROR("airtaudio::api::Alsa::probeDeviceOpen: pcm device (" << name << ") won't open for output.");
} else {
m_errorStream << "airtaudio::api::Alsa::probeDeviceOpen: pcm device (" << name << ") won't open for input.";
ATA_ERROR("airtaudio::api::Alsa::probeDeviceOpen: pcm device (" << name << ") won't open for input.");
}
m_errorText = m_errorStream.str();
return FAILURE;
}
// Fill the parameter structure.
@ -474,14 +452,9 @@ foundDevice:
result = snd_pcm_hw_params_any(phandle, hw_params);
if (result < 0) {
snd_pcm_close(phandle);
m_errorStream << "airtaudio::api::Alsa::probeDeviceOpen: error getting pcm device (" << name << ") parameters, " << snd_strerror(result) << ".";
m_errorText = m_errorStream.str();
ATA_ERROR("airtaudio::api::Alsa::probeDeviceOpen: error getting pcm device (" << name << ") parameters, " << snd_strerror(result) << ".");
return FAILURE;
}
#if defined(__RTAUDIO_DEBUG__)
fprintf(stderr, "\nRtApiAlsa: dump hardware params just after device open:\n\n");
snd_pcm_hw_params_dump(hw_params, out);
#endif
// Set access ... check user preference.
if ( _options != NULL
&& _options->flags & airtaudio::NONINTERLEAVED) {
@ -505,8 +478,7 @@ foundDevice:
}
if (result < 0) {
snd_pcm_close(phandle);
m_errorStream << "airtaudio::api::Alsa::probeDeviceOpen: error setting pcm device (" << name << ") access, " << snd_strerror(result) << ".";
m_errorText = m_errorStream.str();
ATA_ERROR("airtaudio::api::Alsa::probeDeviceOpen: error setting pcm device (" << name << ") access, " << snd_strerror(result) << ".");
return FAILURE;
}
// Determine how to set the device format.
@ -562,16 +534,14 @@ foundDevice:
}
// If we get here, no supported format was found.
snd_pcm_close(phandle);
m_errorStream << "airtaudio::api::Alsa::probeDeviceOpen: pcm device " << _device << " data format not supported by RtAudio.";
m_errorText = m_errorStream.str();
ATA_ERROR("airtaudio::api::Alsa::probeDeviceOpen: pcm device " << _device << " data format not supported by RtAudio.");
return FAILURE;
setFormat:
result = snd_pcm_hw_params_set_format(phandle, hw_params, deviceFormat);
if (result < 0) {
snd_pcm_close(phandle);
m_errorStream << "airtaudio::api::Alsa::probeDeviceOpen: error setting pcm device (" << name << ") data format, " << snd_strerror(result) << ".";
m_errorText = m_errorStream.str();
ATA_ERROR("airtaudio::api::Alsa::probeDeviceOpen: error setting pcm device (" << name << ") data format, " << snd_strerror(result) << ".");
return FAILURE;
}
// Determine whether byte-swaping is necessary.
@ -582,8 +552,7 @@ setFormat:
m_stream.doByteSwap[_mode] = true;
} else if (result < 0) {
snd_pcm_close(phandle);
m_errorStream << "airtaudio::api::Alsa::probeDeviceOpen: error getting pcm device (" << name << ") endian-ness, " << snd_strerror(result) << ".";
m_errorText = m_errorStream.str();
ATA_ERROR("airtaudio::api::Alsa::probeDeviceOpen: error getting pcm device (" << name << ") endian-ness, " << snd_strerror(result) << ".");
return FAILURE;
}
}
@ -591,8 +560,7 @@ setFormat:
result = snd_pcm_hw_params_set_rate_near(phandle, hw_params, (uint32_t*) &_sampleRate, 0);
if (result < 0) {
snd_pcm_close(phandle);
m_errorStream << "airtaudio::api::Alsa::probeDeviceOpen: error setting sample rate on device (" << name << "), " << snd_strerror(result) << ".";
m_errorText = m_errorStream.str();
ATA_ERROR("airtaudio::api::Alsa::probeDeviceOpen: error setting sample rate on device (" << name << "), " << snd_strerror(result) << ".");
return FAILURE;
}
// Determine the number of channels for this device. We support a possible
@ -604,15 +572,13 @@ setFormat:
if ( result < 0
|| deviceChannels < _channels + _firstChannel) {
snd_pcm_close(phandle);
m_errorStream << "airtaudio::api::Alsa::probeDeviceOpen: requested channel parameters not supported by device (" << name << "), " << snd_strerror(result) << ".";
m_errorText = m_errorStream.str();
ATA_ERROR("airtaudio::api::Alsa::probeDeviceOpen: requested channel parameters not supported by device (" << name << "), " << snd_strerror(result) << ".");
return FAILURE;
}
result = snd_pcm_hw_params_get_channels_min(hw_params, &value);
if (result < 0) {
snd_pcm_close(phandle);
m_errorStream << "airtaudio::api::Alsa::probeDeviceOpen: error getting minimum channels for device (" << name << "), " << snd_strerror(result) << ".";
m_errorText = m_errorStream.str();
ATA_ERROR("airtaudio::api::Alsa::probeDeviceOpen: error getting minimum channels for device (" << name << "), " << snd_strerror(result) << ".");
return FAILURE;
}
deviceChannels = value;
@ -624,8 +590,7 @@ setFormat:
result = snd_pcm_hw_params_set_channels(phandle, hw_params, deviceChannels);
if (result < 0) {
snd_pcm_close(phandle);
m_errorStream << "airtaudio::api::Alsa::probeDeviceOpen: error setting channels for device (" << name << "), " << snd_strerror(result) << ".";
m_errorText = m_errorStream.str();
ATA_ERROR("airtaudio::api::Alsa::probeDeviceOpen: error setting channels for device (" << name << "), " << snd_strerror(result) << ".");
return FAILURE;
}
// Set the buffer (or period) size.
@ -634,8 +599,7 @@ setFormat:
result = snd_pcm_hw_params_set_period_size_near(phandle, hw_params, &periodSize, &dir);
if (result < 0) {
snd_pcm_close(phandle);
m_errorStream << "airtaudio::api::Alsa::probeDeviceOpen: error setting period size for device (" << name << "), " << snd_strerror(result) << ".";
m_errorText = m_errorStream.str();
ATA_ERROR("airtaudio::api::Alsa::probeDeviceOpen: error setting period size for device (" << name << "), " << snd_strerror(result) << ".");
return FAILURE;
}
*_bufferSize = periodSize;
@ -647,16 +611,14 @@ setFormat:
result = snd_pcm_hw_params_set_periods_near(phandle, hw_params, &periods, &dir);
if (result < 0) {
snd_pcm_close(phandle);
m_errorStream << "airtaudio::api::Alsa::probeDeviceOpen: error setting periods for device (" << name << "), " << snd_strerror(result) << ".";
m_errorText = m_errorStream.str();
ATA_ERROR("airtaudio::api::Alsa::probeDeviceOpen: error setting periods for device (" << name << "), " << snd_strerror(result) << ".");
return FAILURE;
}
// If attempting to setup a duplex stream, the bufferSize parameter
// MUST be the same in both directions!
if (m_stream.mode == OUTPUT && _mode == INPUT && *_bufferSize != m_stream.bufferSize) {
snd_pcm_close(phandle);
m_errorStream << "airtaudio::api::Alsa::probeDeviceOpen: system error setting buffer size for duplex stream on device (" << name << ").";
m_errorText = m_errorStream.str();
ATA_ERROR("airtaudio::api::Alsa::probeDeviceOpen: system error setting buffer size for duplex stream on device (" << name << ").");
return FAILURE;
}
m_stream.bufferSize = *_bufferSize;
@ -664,14 +626,9 @@ setFormat:
result = snd_pcm_hw_params(phandle, hw_params);
if (result < 0) {
snd_pcm_close(phandle);
m_errorStream << "airtaudio::api::Alsa::probeDeviceOpen: error installing hardware configuration on device (" << name << "), " << snd_strerror(result) << ".";
m_errorText = m_errorStream.str();
ATA_ERROR("airtaudio::api::Alsa::probeDeviceOpen: error installing hardware configuration on device (" << name << "), " << snd_strerror(result) << ".");
return FAILURE;
}
#if defined(__RTAUDIO_DEBUG__)
fprintf(stderr, "\nRtApiAlsa: dump hardware params after installation:\n\n");
snd_pcm_hw_params_dump(hw_params, out);
#endif
// Set the software configuration to fill buffers with zeros and prevent device stopping on xruns.
snd_pcm_sw_params_t *sw_params = NULL;
snd_pcm_sw_params_alloca(&sw_params);
@ -690,14 +647,9 @@ setFormat:
result = snd_pcm_sw_params(phandle, sw_params);
if (result < 0) {
snd_pcm_close(phandle);
m_errorStream << "airtaudio::api::Alsa::probeDeviceOpen: error installing software configuration on device (" << name << "), " << snd_strerror(result) << ".";
m_errorText = m_errorStream.str();
ATA_ERROR("airtaudio::api::Alsa::probeDeviceOpen: error installing software configuration on device (" << name << "), " << snd_strerror(result) << ".");
return FAILURE;
}
#if defined(__RTAUDIO_DEBUG__)
fprintf(stderr, "\nRtApiAlsa: dump software params after installation:\n\n");
snd_pcm_sw_params_dump(sw_params, out);
#endif
// Set flags for buffer conversion
m_stream.doConvertBuffer[_mode] = false;
if (m_stream.userFormat != m_stream.deviceFormat[_mode]) {
@ -713,11 +665,9 @@ setFormat:
// Allocate the ApiHandle if necessary and then save.
AlsaHandle *apiInfo = 0;
if (m_stream.apiHandle == 0) {
try {
apiInfo = (AlsaHandle *) new AlsaHandle;
}
catch (std::bad_alloc&) {
m_errorText = "airtaudio::api::Alsa::probeDeviceOpen: error allocating AlsaHandle memory.";
apiInfo = (AlsaHandle *) new AlsaHandle;
if (apiInfo == NULL) {
ATA_ERROR("airtaudio::api::Alsa::probeDeviceOpen: error allocating AlsaHandle memory.");
goto error;
}
m_stream.apiHandle = (void *) apiInfo;
@ -733,7 +683,7 @@ setFormat:
bufferBytes = m_stream.nUserChannels[_mode] * *_bufferSize * formatBytes(m_stream.userFormat);
m_stream.userBuffer[_mode] = (char *) calloc(bufferBytes, 1);
if (m_stream.userBuffer[_mode] == NULL) {
m_errorText = "airtaudio::api::Alsa::probeDeviceOpen: error allocating user buffer memory.";
ATA_ERROR("airtaudio::api::Alsa::probeDeviceOpen: error allocating user buffer memory.");
goto error;
}
if (m_stream.doConvertBuffer[_mode]) {
@ -755,7 +705,7 @@ setFormat:
}
m_stream.deviceBuffer = (char *) calloc(bufferBytes, 1);
if (m_stream.deviceBuffer == NULL) {
m_errorText = "airtaudio::api::Alsa::probeDeviceOpen: error allocating device buffer memory.";
ATA_ERROR("airtaudio::api::Alsa::probeDeviceOpen: error allocating device buffer memory.");
goto error;
}
}
@ -778,8 +728,8 @@ setFormat:
if (snd_pcm_link(apiInfo->handles[0], apiInfo->handles[1]) == 0) {
apiInfo->synchronized = true;
} else {
m_errorText = "airtaudio::api::Alsa::probeDeviceOpen: unable to synchronize input and output devices.";
error(airtaudio::errorWarning);
ATA_ERROR("airtaudio::api::Alsa::probeDeviceOpen: unable to synchronize input and output devices.");
// TODO : airtaudio::errorWarning;
}
} else {
m_stream.mode = _mode;
@ -789,7 +739,7 @@ setFormat:
m_stream.callbackInfo.thread = new std::thread(alsaCallbackHandler, &m_stream.callbackInfo);
if (m_stream.callbackInfo.thread == NULL) {
m_stream.callbackInfo.isRunning = false;
m_errorText = "airtaudio::api::Alsa::error creating callback thread!";
ATA_ERROR("airtaudio::api::Alsa::error creating callback thread!");
goto error;
}
}
@ -825,9 +775,8 @@ error:
enum airtaudio::errorType airtaudio::api::Alsa::closeStream(void) {
if (m_stream.state == STREAM_CLOSED) {
m_errorText = "airtaudio::api::Alsa::closeStream(): no open stream to close!";
error(airtaudio::errorWarning);
return;
ATA_ERROR("airtaudio::api::Alsa::closeStream(): no open stream to close!");
return airtaudio::errorWarning;
}
AlsaHandle *apiInfo = (AlsaHandle *) m_stream.apiHandle;
m_stream.callbackInfo.isRunning = false;
@ -874,15 +823,17 @@ enum airtaudio::errorType airtaudio::api::Alsa::closeStream(void) {
}
m_stream.mode = UNINITIALIZED;
m_stream.state = STREAM_CLOSED;
return airtaudio::errorNone;
}
enum airtaudio::errorType airtaudio::api::Alsa::startStream(void) {
// This method calls snd_pcm_prepare if the device isn't already in that state.
verifyStream();
if (verifyStream() != airtaudio::errorNone) {
return airtaudio::errorFail;
}
if (m_stream.state == STREAM_RUNNING) {
m_errorText = "airtaudio::api::Alsa::startStream(): the stream is already running!";
error(airtaudio::errorWarning);
return;
ATA_ERROR("airtaudio::api::Alsa::startStream(): the stream is already running!");
return airtaudio::errorWarning;
}
std::unique_lock<std::mutex> lck(m_stream.mutex);
int32_t result = 0;
@ -894,8 +845,7 @@ enum airtaudio::errorType airtaudio::api::Alsa::startStream(void) {
if (state != SND_PCM_STATE_PREPARED) {
result = snd_pcm_prepare(handle[0]);
if (result < 0) {
m_errorStream << "airtaudio::api::Alsa::startStream: error preparing output pcm device, " << snd_strerror(result) << ".";
m_errorText = m_errorStream.str();
ATA_ERROR("airtaudio::api::Alsa::startStream: error preparing output pcm device, " << snd_strerror(result) << ".");
goto unlock;
}
}
@ -907,8 +857,7 @@ enum airtaudio::errorType airtaudio::api::Alsa::startStream(void) {
if (state != SND_PCM_STATE_PREPARED) {
result = snd_pcm_prepare(handle[1]);
if (result < 0) {
m_errorStream << "airtaudio::api::Alsa::startStream: error preparing input pcm device, " << snd_strerror(result) << ".";
m_errorText = m_errorStream.str();
ATA_ERROR("airtaudio::api::Alsa::startStream: error preparing input pcm device, " << snd_strerror(result) << ".");
goto unlock;
}
}
@ -918,17 +867,18 @@ unlock:
apiInfo->runnable = true;
apiInfo->runnable_cv.notify_one();
if (result >= 0) {
return;
return airtaudio::errorNone;
}
error(airtaudio::errorSystemError);
return airtaudio::errorSystemError;
}
enum airtaudio::errorType airtaudio::api::Alsa::stopStream(void) {
verifyStream();
if (verifyStream() != airtaudio::errorNone) {
return airtaudio::errorFail;
}
if (m_stream.state == STREAM_STOPPED) {
m_errorText = "airtaudio::api::Alsa::stopStream(): the stream is already stopped!";
error(airtaudio::errorWarning);
return;
ATA_ERROR("airtaudio::api::Alsa::stopStream(): the stream is already stopped!");
return airtaudio::errorWarning;
}
m_stream.state = STREAM_STOPPED;
std::unique_lock<std::mutex> lck(m_stream.mutex);
@ -943,8 +893,7 @@ enum airtaudio::errorType airtaudio::api::Alsa::stopStream(void) {
result = snd_pcm_drain(handle[0]);
}
if (result < 0) {
m_errorStream << "airtaudio::api::Alsa::stopStream: error draining output pcm device, " << snd_strerror(result) << ".";
m_errorText = m_errorStream.str();
ATA_ERROR("airtaudio::api::Alsa::stopStream: error draining output pcm device, " << snd_strerror(result) << ".");
goto unlock;
}
}
@ -953,24 +902,24 @@ enum airtaudio::errorType airtaudio::api::Alsa::stopStream(void) {
&& !apiInfo->synchronized) {
result = snd_pcm_drop(handle[1]);
if (result < 0) {
m_errorStream << "airtaudio::api::Alsa::stopStream: error stopping input pcm device, " << snd_strerror(result) << ".";
m_errorText = m_errorStream.str();
ATA_ERROR("airtaudio::api::Alsa::stopStream: error stopping input pcm device, " << snd_strerror(result) << ".");
goto unlock;
}
}
unlock:
if (result >= 0) {
return;
return airtaudio::errorNone;
}
error(airtaudio::errorSystemError);
return airtaudio::errorSystemError;
}
enum airtaudio::errorType airtaudio::api::Alsa::abortStream(void) {
verifyStream();
if (verifyStream() != airtaudio::errorNone) {
return airtaudio::errorFail;
}
if (m_stream.state == STREAM_STOPPED) {
m_errorText = "airtaudio::api::Alsa::abortStream(): the stream is already stopped!";
error(airtaudio::errorWarning);
return;
ATA_ERROR("airtaudio::api::Alsa::abortStream(): the stream is already stopped!");
return airtaudio::errorWarning;
}
m_stream.state = STREAM_STOPPED;
std::unique_lock<std::mutex> lck(m_stream.mutex);
@ -981,8 +930,7 @@ enum airtaudio::errorType airtaudio::api::Alsa::abortStream(void) {
|| m_stream.mode == DUPLEX) {
result = snd_pcm_drop(handle[0]);
if (result < 0) {
m_errorStream << "airtaudio::api::Alsa::abortStream: error aborting output pcm device, " << snd_strerror(result) << ".";
m_errorText = m_errorStream.str();
ATA_ERROR("airtaudio::api::Alsa::abortStream: error aborting output pcm device, " << snd_strerror(result) << ".");
goto unlock;
}
}
@ -991,16 +939,15 @@ enum airtaudio::errorType airtaudio::api::Alsa::abortStream(void) {
&& !apiInfo->synchronized) {
result = snd_pcm_drop(handle[1]);
if (result < 0) {
m_errorStream << "airtaudio::api::Alsa::abortStream: error aborting input pcm device, " << snd_strerror(result) << ".";
m_errorText = m_errorStream.str();
ATA_ERROR("airtaudio::api::Alsa::abortStream: error aborting input pcm device, " << snd_strerror(result) << ".");
goto unlock;
}
}
unlock:
if (result >= 0) {
return;
return airtaudio::errorNone;
}
error(airtaudio::errorSystemError);
return airtaudio::errorSystemError;
}
void airtaudio::api::Alsa::callbackEvent(void) {
@ -1018,9 +965,8 @@ void airtaudio::api::Alsa::callbackEvent(void) {
}
}
if (m_stream.state == STREAM_CLOSED) {
m_errorText = "airtaudio::api::Alsa::callbackEvent(): the stream is closed ... this shouldn't happen!";
error(airtaudio::errorWarning);
return;
ATA_CRITICAL("airtaudio::api::Alsa::callbackEvent(): the stream is closed ... this shouldn't happen!");
return; // TODO : notify appl: airtaudio::errorWarning;
}
int32_t doStopStream = 0;
airtaudio::AirTAudioCallback callback = (airtaudio::AirTAudioCallback) m_stream.callbackInfo.callback;
@ -1086,18 +1032,15 @@ void airtaudio::api::Alsa::callbackEvent(void) {
apiInfo->xrun[1] = true;
result = snd_pcm_prepare(handle[1]);
if (result < 0) {
m_errorStream << "airtaudio::api::Alsa::callbackEvent: error preparing device after overrun, " << snd_strerror(result) << ".";
m_errorText = m_errorStream.str();
ATA_ERROR("airtaudio::api::Alsa::callbackEvent: error preparing device after overrun, " << snd_strerror(result) << ".");
}
} else {
m_errorStream << "airtaudio::api::Alsa::callbackEvent: error, current state is " << snd_pcm_state_name(state) << ", " << snd_strerror(result) << ".";
m_errorText = m_errorStream.str();
ATA_ERROR("airtaudio::api::Alsa::callbackEvent: error, current state is " << snd_pcm_state_name(state) << ", " << snd_strerror(result) << ".");
}
} else {
m_errorStream << "airtaudio::api::Alsa::callbackEvent: audio read error, " << snd_strerror(result) << ".";
m_errorText = m_errorStream.str();
ATA_ERROR("airtaudio::api::Alsa::callbackEvent: audio read error, " << snd_strerror(result) << ".");
}
error(airtaudio::errorWarning);
// TODO : Notify application ... airtaudio::errorWarning;
goto tryOutput;
}
// Do byte swapping if necessary.
@ -1110,7 +1053,9 @@ void airtaudio::api::Alsa::callbackEvent(void) {
}
// Check stream latency
result = snd_pcm_delay(handle[1], &frames);
if (result == 0 && frames > 0) m_stream.latency[1] = frames;
if (result == 0 && frames > 0) {
m_stream.latency[1] = frames;
}
}
tryOutput:
@ -1150,23 +1095,22 @@ tryOutput:
apiInfo->xrun[0] = true;
result = snd_pcm_prepare(handle[0]);
if (result < 0) {
m_errorStream << "airtaudio::api::Alsa::callbackEvent: error preparing device after underrun, " << snd_strerror(result) << ".";
m_errorText = m_errorStream.str();
ATA_ERROR("airtaudio::api::Alsa::callbackEvent: error preparing device after underrun, " << snd_strerror(result) << ".");
}
} else {
m_errorStream << "airtaudio::api::Alsa::callbackEvent: error, current state is " << snd_pcm_state_name(state) << ", " << snd_strerror(result) << ".";
m_errorText = m_errorStream.str();
ATA_ERROR("airtaudio::api::Alsa::callbackEvent: error, current state is " << snd_pcm_state_name(state) << ", " << snd_strerror(result) << ".");
}
} else {
m_errorStream << "airtaudio::api::Alsa::callbackEvent: audio write error, " << snd_strerror(result) << ".";
m_errorText = m_errorStream.str();
ATA_ERROR("airtaudio::api::Alsa::callbackEvent: audio write error, " << snd_strerror(result) << ".");
}
error(airtaudio::errorWarning);
// TODO : Notuify application airtaudio::errorWarning;
goto unlock;
}
// Check stream latency
result = snd_pcm_delay(handle[0], &frames);
if (result == 0 && frames > 0) m_stream.latency[0] = frames;
if (result == 0 && frames > 0) {
m_stream.latency[0] = frames;
}
}
unlock:

View File

@ -10,6 +10,7 @@
#if defined(__WINDOWS_ASIO__) // ASIO API on Windows
#include <airtaudio/Interface.h>
#include <airtaudio/debug.h>
airtaudio::Api* airtaudio::api::Asio::Create(void) {
return new airtaudio::api::Asio();
@ -183,15 +184,15 @@ rtaudio::DeviceInfo airtaudio::api::Asio::getDeviceInfo(uint32_t device)
info.nativeFormats = 0;
if (channelInfo.type == ASIOSTInt16MSB || channelInfo.type == ASIOSTInt16LSB)
info.nativeFormats |= RTAUDIO_SINT16;
info.nativeFormats |= SINT16;
else if (channelInfo.type == ASIOSTInt32MSB || channelInfo.type == ASIOSTInt32LSB)
info.nativeFormats |= RTAUDIO_SINT32;
info.nativeFormats |= SINT32;
else if (channelInfo.type == ASIOSTFloat32MSB || channelInfo.type == ASIOSTFloat32LSB)
info.nativeFormats |= RTAUDIO_FLOAT32;
info.nativeFormats |= FLOAT32;
else if (channelInfo.type == ASIOSTFloat64MSB || channelInfo.type == ASIOSTFloat64LSB)
info.nativeFormats |= RTAUDIO_FLOAT64;
info.nativeFormats |= FLOAT64;
else if (channelInfo.type == ASIOSTInt24MSB || channelInfo.type == ASIOSTInt24LSB)
info.nativeFormats |= RTAUDIO_SINT24;
info.nativeFormats |= SINT24;
if (info.outputChannels > 0)
if (getDefaultOutputDevice() == device) info.isDefaultOutput = true;
@ -579,7 +580,7 @@ bool airtaudio::api::Asio::probeDeviceOpen(uint32_t device, StreamMode mode, uin
return FAILURE;
}
void airtaudio::api::Asio::closeStream()
enum airtaudio::errorType airtaudio::api::Asio::closeStream()
{
if (m_stream.state == STREAM_CLOSED) {
m_errorText = "airtaudio::api::Asio::closeStream(): no open stream to close!";
@ -621,9 +622,11 @@ void airtaudio::api::Asio::closeStream()
bool stopThreadCalled = false;
void airtaudio::api::Asio::startStream()
enum airtaudio::errorType airtaudio::api::Asio::startStream()
{
verifyStream();
if (verifyStream() != airtaudio::errorNone) {
return airtaudio::errorFail;
}
if (m_stream.state == STREAM_RUNNING) {
m_errorText = "airtaudio::api::Asio::startStream(): the stream is already running!";
error(airtaudio::errorWarning);
@ -651,9 +654,11 @@ void airtaudio::api::Asio::startStream()
error(airtaudio::errorSystemError);
}
void airtaudio::api::Asio::stopStream()
enum airtaudio::errorType airtaudio::api::Asio::stopStream()
{
verifyStream();
if (verifyStream() != airtaudio::errorNone) {
return airtaudio::errorFail;
}
if (m_stream.state == STREAM_STOPPED) {
m_errorText = "airtaudio::api::Asio::stopStream(): the stream is already stopped!";
error(airtaudio::errorWarning);
@ -680,9 +685,11 @@ void airtaudio::api::Asio::stopStream()
error(airtaudio::errorSystemError);
}
void airtaudio::api::Asio::abortStream()
enum airtaudio::errorType airtaudio::api::Asio::abortStream()
{
verifyStream();
if (verifyStream() != airtaudio::errorNone) {
return airtaudio::errorFail;
}
if (m_stream.state == STREAM_STOPPED) {
m_errorText = "airtaudio::api::Asio::abortStream(): the stream is already stopped!";
error(airtaudio::errorWarning);

View File

@ -22,10 +22,10 @@ namespace airtaudio {
}
uint32_t getDeviceCount(void);
airtaudio::DeviceInfo getDeviceInfo(uint32_t _device);
void closeStream(void);
void startStream(void);
void stopStream(void);
void abortStream(void);
enum airtaudio::errorType closeStream(void);
enum airtaudio::errorType startStream(void);
enum airtaudio::errorType stopStream(void);
enum airtaudio::errorType abortStream(void);
long getStreamLatency(void);
// This function is intended for internal use only. It must be
// public because it is called by the internal callback handler,

File diff suppressed because it is too large Load Diff

View File

@ -26,10 +26,10 @@ namespace airtaudio {
airtaudio::DeviceInfo getDeviceInfo(uint32_t _device);
uint32_t getDefaultOutputDevice(void);
uint32_t getDefaultInputDevice(void);
void closeStream(void);
void startStream(void);
void stopStream(void);
void abortStream(void);
enum airtaudio::errorType closeStream(void);
enum airtaudio::errorType startStream(void);
enum airtaudio::errorType stopStream(void);
enum airtaudio::errorType abortStream(void);
long getStreamLatency(void);
// This function is intended for internal use only. It must be
// public because it is called by the internal callback handler,

View File

@ -9,6 +9,7 @@
// Windows DirectSound API
#if defined(__WINDOWS_DS__)
#include <airtaudio/Interface.h>
#include <airtaudio/debug.h>
airtaudio::Api* airtaudio::api::Ds::Create(void) {
return new airtaudio::api::Ds();
@ -843,7 +844,7 @@ bool airtaudio::api::Ds::probeDeviceOpen(uint32_t device, StreamMode mode, uint3
return FAILURE;
}
void airtaudio::api::Ds::closeStream()
enum airtaudio::errorType airtaudio::api::Ds::closeStream()
{
if (m_stream.state == STREAM_CLOSED) {
m_errorText = "airtaudio::api::Ds::closeStream(): no open stream to close!";
@ -897,9 +898,11 @@ void airtaudio::api::Ds::closeStream()
m_stream.state = STREAM_CLOSED;
}
void airtaudio::api::Ds::startStream()
enum airtaudio::errorType airtaudio::api::Ds::startStream()
{
verifyStream();
if (verifyStream() != airtaudio::errorNone) {
return airtaudio::errorFail;
}
if (m_stream.state == STREAM_RUNNING) {
m_errorText = "airtaudio::api::Ds::startStream(): the stream is already running!";
error(airtaudio::errorWarning);
@ -953,9 +956,11 @@ void airtaudio::api::Ds::startStream()
if (FAILED(result)) error(airtaudio::errorSystemError);
}
void airtaudio::api::Ds::stopStream()
enum airtaudio::errorType airtaudio::api::Ds::stopStream()
{
verifyStream();
if (verifyStream() != airtaudio::errorNone) {
return airtaudio::errorFail;
}
if (m_stream.state == STREAM_STOPPED) {
m_errorText = "airtaudio::api::Ds::stopStream(): the stream is already stopped!";
error(airtaudio::errorWarning);
@ -1050,9 +1055,11 @@ void airtaudio::api::Ds::stopStream()
if (FAILED(result)) error(airtaudio::errorSystemError);
}
void airtaudio::api::Ds::abortStream()
enum airtaudio::errorType airtaudio::api::Ds::abortStream()
{
verifyStream();
if (verifyStream() != airtaudio::errorNone) {
return airtaudio::errorFail;
}
if (m_stream.state == STREAM_STOPPED) {
m_errorText = "airtaudio::api::Ds::abortStream(): the stream is already stopped!";
error(airtaudio::errorWarning);
@ -1492,9 +1499,9 @@ static std::string convertTChar(LPCTSTR name)
}
static BOOL CALLBACK deviceQueryCallback(LPGUID lpguid,
LPCTSTR description,
LPCTSTR module,
LPVOID lpContext)
LPCTSTR description,
LPCTSTR module,
LPVOID lpContext)
{
struct DsProbeData& probeInfo = *(struct DsProbeData*) lpContext;
std::vector<struct DsDevice>& dsDevices = *probeInfo.dsDevices;
@ -1572,55 +1579,39 @@ static BOOL CALLBACK deviceQueryCallback(LPGUID lpguid,
static const char* getErrorString(int32_t code)
{
switch (code) {
case DSERR_ALLOCATED:
return "Already allocated";
case DSERR_CONTROLUNAVAIL:
return "Control unavailable";
case DSERR_INVALIDPARAM:
return "Invalid parameter";
case DSERR_INVALIDCALL:
return "Invalid call";
case DSERR_GENERIC:
return "Generic error";
case DSERR_PRIOLEVELNEEDED:
return "Priority level needed";
case DSERR_OUTOFMEMORY:
return "Out of memory";
case DSERR_BADFORMAT:
return "The sample rate or the channel format is not supported";
case DSERR_UNSUPPORTED:
return "Not supported";
case DSERR_NODRIVER:
return "No driver";
case DSERR_ALREADYINITIALIZED:
return "Already initialized";
case DSERR_NOAGGREGATION:
return "No aggregation";
case DSERR_BUFFERLOST:
return "Buffer lost";
case DSERR_OTHERAPPHASPRIO:
return "Another application already has priority";
case DSERR_UNINITIALIZED:
return "Uninitialized";
default:
return "DirectSound unknown error";
case DSERR_ALLOCATED:
return "Already allocated";
case DSERR_CONTROLUNAVAIL:
return "Control unavailable";
case DSERR_INVALIDPARAM:
return "Invalid parameter";
case DSERR_INVALIDCALL:
return "Invalid call";
case DSERR_GENERIC:
return "Generic error";
case DSERR_PRIOLEVELNEEDED:
return "Priority level needed";
case DSERR_OUTOFMEMORY:
return "Out of memory";
case DSERR_BADFORMAT:
return "The sample rate or the channel format is not supported";
case DSERR_UNSUPPORTED:
return "Not supported";
case DSERR_NODRIVER:
return "No driver";
case DSERR_ALREADYINITIALIZED:
return "Already initialized";
case DSERR_NOAGGREGATION:
return "No aggregation";
case DSERR_BUFFERLOST:
return "Buffer lost";
case DSERR_OTHERAPPHASPRIO:
return "Another application already has priority";
case DSERR_UNINITIALIZED:
return "Uninitialized";
default:
return "DirectSound unknown error";
}
}
//******************** End of __WINDOWS_DS__ *********************//
#endif

View File

@ -24,10 +24,10 @@ namespace airtaudio {
uint32_t getDefaultOutputDevice(void);
uint32_t getDefaultInputDevice(void);
airtaudio::DeviceInfo getDeviceInfo(uint32_t _device);
void closeStream(void);
void startStream(void);
void stopStream(void);
void abortStream(void);
enum airtaudio::errorType closeStream(void);
enum airtaudio::errorType startStream(void);
enum airtaudio::errorType stopStream(void);
enum airtaudio::errorType abortStream(void);
long getStreamLatency(void);
// This function is intended for internal use only. It must be
// public because it is called by the internal callback handler,

View File

@ -7,6 +7,8 @@
*/
#if defined(__AIRTAUDIO_DUMMY__)
#include <airtaudio/api/Dummy.h>
#include <airtaudio/debug.h>
airtaudio::Api* airtaudio::api::Dummy::Create(void) {
return new airtaudio::api::Dummy();
@ -28,20 +30,20 @@ rtaudio::DeviceInfo airtaudio::api::Dummy::getDeviceInfo(uint32_t _device) {
return info;
}
void airtaudio::api::Dummy::closeStream(void) {
enum airtaudio::errorType airtaudio::api::Dummy::closeStream(void) {
return airtaudio::errorNone;
}
void airtaudio::api::Dummy::startStream(void) {
enum airtaudio::errorType airtaudio::api::Dummy::startStream(void) {
return airtaudio::errorNone;
}
void airtaudio::api::Dummy::stopStream(void) {
enum airtaudio::errorType airtaudio::api::Dummy::stopStream(void) {
return airtaudio::errorNone;
}
void airtaudio::api::Dummy::abortStream(void) {
enum airtaudio::errorType airtaudio::api::Dummy::abortStream(void) {
return airtaudio::errorNone;
}
bool airtaudio::api::Dummy::probeDeviceOpen(uint32_t _device,

View File

@ -23,10 +23,10 @@ namespace airtaudio {
}
uint32_t getDeviceCount(void);
airtaudio::DeviceInfo getDeviceInfo(uint32_t _device);
void closeStream(void);
void startStream(void);
void stopStream(void);
void abortStream(void);
enum airtaudio::errorType closeStream(void);
enum airtaudio::errorType startStream(void);
enum airtaudio::errorType stopStream(void);
enum airtaudio::errorType abortStream(void);
private:
bool probeDeviceOpen(uint32_t _device,
airtaudio::api::StreamMode _mode,

View File

@ -12,6 +12,7 @@
#include <limits.h>
#include <iostream>
#include <airtaudio/Interface.h>
#include <airtaudio/debug.h>
#include <string.h>
airtaudio::Api* airtaudio::api::Jack::Create(void) {
@ -74,14 +75,8 @@ struct JackHandle {
}
};
static void jackSilentError(const char *) {};
airtaudio::api::Jack::Jack(void) {
// Nothing to do here.
#if !defined(__RTAUDIO_DEBUG__)
// Turn off Jack's internal error reporting.
jack_set_error_function(&jackSilentError);
#endif
}
airtaudio::api::Jack::~Jack(void) {
@ -122,16 +117,15 @@ uint32_t airtaudio::api::Jack::getDeviceCount(void) {
return nDevices;
}
airtaudio::DeviceInfo airtaudio::api::Jack::getDeviceInfo(uint32_t _device)
{
airtaudio::DeviceInfo airtaudio::api::Jack::getDeviceInfo(uint32_t _device) {
airtaudio::DeviceInfo info;
info.probed = false;
jack_options_t options = (jack_options_t) (JackNoStartServer); //JackNullOption
jack_status_t *status = NULL;
jack_client_t *client = jack_client_open("RtApiJackInfo", options, status);
if (client == NULL) {
m_errorText = "airtaudio::api::Jack::getDeviceInfo: Jack server not found or connection error!";
error(airtaudio::errorWarning);
ATA_ERROR("airtaudio::api::Jack::getDeviceInfo: Jack server not found or connection error!");
// TODO : airtaudio::errorWarning;
return info;
}
const char **ports;
@ -157,18 +151,15 @@ airtaudio::DeviceInfo airtaudio::api::Jack::getDeviceInfo(uint32_t _device)
} while (ports[++nPorts]);
free(ports);
}
if (_device >= nDevices) {
jack_client_close(client);
m_errorText = "airtaudio::api::Jack::getDeviceInfo: device ID is invalid!";
error(airtaudio::errorInvalidUse);
ATA_ERROR("airtaudio::api::Jack::getDeviceInfo: device ID is invalid!");
// TODO : airtaudio::errorInvalidUse;
return info;
}
// Get the current jack server sample rate.
info.sampleRates.clear();
info.sampleRates.push_back(jack_get_sample_rate(client));
// Count the available ports containing the client name as device
// channels. Jack "input ports" equal RtAudio output channels.
uint32_t nChannels = 0;
@ -192,8 +183,8 @@ airtaudio::DeviceInfo airtaudio::api::Jack::getDeviceInfo(uint32_t _device)
}
if (info.outputChannels == 0 && info.inputChannels == 0) {
jack_client_close(client);
m_errorText = "airtaudio::api::Jack::getDeviceInfo: error determining Jack input/output channels!";
error(airtaudio::errorWarning);
ATA_ERROR("airtaudio::api::Jack::getDeviceInfo: error determining Jack input/output channels!");
// TODO : airtaudio::errorWarning;
return info;
}
// If device opens for both playback and capture, we determine the channels.
@ -229,11 +220,10 @@ static int32_t jackCallbackHandler(jack_nframes_t _nframes, void *_infoPointer)
// server signals that it is shutting down. It is necessary to handle
// it this way because the jackShutdown() function must return before
// the jack_deactivate() function (in closeStream()) will return.
static void *jackCloseStream(void *_ptr) {
static void jackCloseStream(void *_ptr) {
airtaudio::CallbackInfo* info = (airtaudio::CallbackInfo*)_ptr;
airtaudio::api::Jack* object = (airtaudio::api::Jack*)info->object;
object->closeStream();
pthread_exit(NULL);
}
static void jackShutdown(void* _infoPointer) {
@ -247,9 +237,8 @@ static void jackShutdown(void* _infoPointer) {
if (object->isStreamRunning() == false) {
return;
}
pthread_t threadId;
pthread_create(&threadId, NULL, jackCloseStream, info);
std::cerr << "\nRtApiJack: the Jack server is shutting down this client ... stream stopped and closed!!\n" << std::endl;
new std::thread(jackCloseStream, info);
ATA_ERROR("RtApiJack: the Jack server is shutting down this client ... stream stopped and closed!!");
}
static int32_t jackXrun(void* _infoPointer) {
@ -263,36 +252,35 @@ static int32_t jackXrun(void* _infoPointer) {
return 0;
}
bool airtaudio::api::Jack::probeDeviceOpen(uint32_t device,
airtaudio::api::StreamMode mode,
uint32_t channels,
uint32_t firstChannel,
uint32_t sampleRate,
airtaudio::format format,
uint32_t *bufferSize,
airtaudio::StreamOptions *options) {
bool airtaudio::api::Jack::probeDeviceOpen(uint32_t _device,
airtaudio::api::StreamMode _mode,
uint32_t _channels,
uint32_t _firstChannel,
uint32_t _sampleRate,
airtaudio::format _format,
uint32_t* _bufferSize,
airtaudio::StreamOptions* _options) {
JackHandle *handle = (JackHandle *) m_stream.apiHandle;
// Look for jack server and try to become a client (only do once per stream).
jack_client_t *client = 0;
if (mode == OUTPUT || (mode == INPUT && m_stream.mode != OUTPUT)) {
if ( _mode == OUTPUT
|| ( _mode == INPUT
&& m_stream.mode != OUTPUT)) {
jack_options_t jackoptions = (jack_options_t) (JackNoStartServer); //JackNullOption;
jack_status_t *status = NULL;
if (options && !options->streamName.empty()) {
client = jack_client_open(options->streamName.c_str(), jackoptions, status);
if (_options && !_options->streamName.empty()) {
client = jack_client_open(_options->streamName.c_str(), jackoptions, status);
} else {
client = jack_client_open("RtApiJack", jackoptions, status);
}
if (client == 0) {
m_errorText = "airtaudio::api::Jack::probeDeviceOpen: Jack server not found or connection error!";
error(airtaudio::errorWarning);
ATA_ERROR("airtaudio::api::Jack::probeDeviceOpen: Jack server not found or connection error!");
return FAILURE;
}
}
else {
} else {
// The handle must have been created on an earlier pass.
client = handle->client;
}
const char **ports;
std::string port, previousPort, deviceName;
uint32_t nPorts = 0, nDevices = 0;
@ -306,7 +294,9 @@ bool airtaudio::api::Jack::probeDeviceOpen(uint32_t device,
if (iColon != std::string::npos) {
port = port.substr(0, iColon);
if (port != previousPort) {
if (nDevices == device) deviceName = port;
if (nDevices == _device) {
deviceName = port;
}
nDevices++;
previousPort = port;
}
@ -314,156 +304,141 @@ bool airtaudio::api::Jack::probeDeviceOpen(uint32_t device,
} while (ports[++nPorts]);
free(ports);
}
if (device >= nDevices) {
m_errorText = "airtaudio::api::Jack::probeDeviceOpen: device ID is invalid!";
if (_device >= nDevices) {
ATA_ERROR("airtaudio::api::Jack::probeDeviceOpen: device ID is invalid!");
return FAILURE;
}
// Count the available ports containing the client name as device
// channels. Jack "input ports" equal RtAudio output channels.
uint32_t nChannels = 0;
uint64_t flag = JackPortIsInput;
if (mode == INPUT) flag = JackPortIsOutput;
if (_mode == INPUT) flag = JackPortIsOutput;
ports = jack_get_ports(client, deviceName.c_str(), NULL, flag);
if (ports) {
while (ports[ nChannels ]) nChannels++;
while (ports[ nChannels ]) {
nChannels++;
}
free(ports);
}
// Compare the jack ports for specified client to the requested number of channels.
if (nChannels < (channels + firstChannel)) {
m_errorStream << "airtaudio::api::Jack::probeDeviceOpen: requested number of channels (" << channels << ") + offset (" << firstChannel << ") not found for specified device (" << device << ":" << deviceName << ").";
m_errorText = m_errorStream.str();
if (nChannels < (_channels + _firstChannel)) {
ATA_ERROR("airtaudio::api::Jack::probeDeviceOpen: requested number of channels (" << _channels << ") + offset (" << _firstChannel << ") not found for specified device (" << _device << ":" << deviceName << ").");
return FAILURE;
}
// Check the jack server sample rate.
uint32_t jackRate = jack_get_sample_rate(client);
if (sampleRate != jackRate) {
if (_sampleRate != jackRate) {
jack_client_close(client);
m_errorStream << "airtaudio::api::Jack::probeDeviceOpen: the requested sample rate (" << sampleRate << ") is different than the JACK server rate (" << jackRate << ").";
m_errorText = m_errorStream.str();
ATA_ERROR("airtaudio::api::Jack::probeDeviceOpen: the requested sample rate (" << _sampleRate << ") is different than the JACK server rate (" << jackRate << ").");
return FAILURE;
}
m_stream.sampleRate = jackRate;
// Get the latency of the JACK port.
ports = jack_get_ports(client, deviceName.c_str(), NULL, flag);
if (ports[ firstChannel ]) {
if (ports[ _firstChannel ]) {
// Added by Ge Wang
jack_latency_callback_mode_t cbmode = (mode == INPUT ? JackCaptureLatency : JackPlaybackLatency);
jack_latency_callback_mode_t cbmode = (_mode == INPUT ? JackCaptureLatency : JackPlaybackLatency);
// the range (usually the min and max are equal)
jack_latency_range_t latrange; latrange.min = latrange.max = 0;
// get the latency range
jack_port_get_latency_range(jack_port_by_name(client, ports[firstChannel]), cbmode, &latrange);
jack_port_get_latency_range(jack_port_by_name(client, ports[_firstChannel]), cbmode, &latrange);
// be optimistic, use the min!
m_stream.latency[mode] = latrange.min;
//m_stream.latency[mode] = jack_port_get_latency(jack_port_by_name(client, ports[ firstChannel ]));
m_stream.latency[_mode] = latrange.min;
//m_stream.latency[_mode] = jack_port_get_latency(jack_port_by_name(client, ports[ _firstChannel ]));
}
free(ports);
// The jack server always uses 32-bit floating-point data.
m_stream.deviceFormat[mode] = FLOAT32;
m_stream.userFormat = format;
if (options && options->flags & NONINTERLEAVED) m_stream.userInterleaved = false;
else m_stream.userInterleaved = true;
m_stream.deviceFormat[_mode] = FLOAT32;
m_stream.userFormat = _format;
if (_options && _options->flags & NONINTERLEAVED) {
m_stream.userInterleaved = false;
} else {
m_stream.userInterleaved = true;
}
// Jack always uses non-interleaved buffers.
m_stream.deviceInterleaved[mode] = false;
m_stream.deviceInterleaved[_mode] = false;
// Jack always provides host byte-ordered data.
m_stream.doByteSwap[mode] = false;
m_stream.doByteSwap[_mode] = false;
// Get the buffer size. The buffer size and number of buffers
// (periods) is set when the jack server is started.
m_stream.bufferSize = (int) jack_get_buffer_size(client);
*bufferSize = m_stream.bufferSize;
m_stream.nDeviceChannels[mode] = channels;
m_stream.nUserChannels[mode] = channels;
*_bufferSize = m_stream.bufferSize;
m_stream.nDeviceChannels[_mode] = _channels;
m_stream.nUserChannels[_mode] = _channels;
// Set flags for buffer conversion.
m_stream.doConvertBuffer[mode] = false;
if (m_stream.userFormat != m_stream.deviceFormat[mode])
m_stream.doConvertBuffer[mode] = true;
if (m_stream.userInterleaved != m_stream.deviceInterleaved[mode] &&
m_stream.nUserChannels[mode] > 1)
m_stream.doConvertBuffer[mode] = true;
m_stream.doConvertBuffer[_mode] = false;
if (m_stream.userFormat != m_stream.deviceFormat[_mode]) {
m_stream.doConvertBuffer[_mode] = true;
}
if ( m_stream.userInterleaved != m_stream.deviceInterleaved[_mode]
&& m_stream.nUserChannels[_mode] > 1) {
m_stream.doConvertBuffer[_mode] = true;
}
// Allocate our JackHandle structure for the stream.
if (handle == 0) {
try {
handle = new JackHandle;
}
catch (std::bad_alloc&) {
m_errorText = "airtaudio::api::Jack::probeDeviceOpen: error allocating JackHandle memory.";
handle = new JackHandle;
if (handle == NULL) {
ATA_ERROR("airtaudio::api::Jack::probeDeviceOpen: error allocating JackHandle memory.");
goto error;
}
m_stream.apiHandle = (void *) handle;
handle->client = client;
}
handle->deviceName[mode] = deviceName;
handle->deviceName[_mode] = deviceName;
// Allocate necessary internal buffers.
uint64_t bufferBytes;
bufferBytes = m_stream.nUserChannels[mode] * *bufferSize * formatBytes(m_stream.userFormat);
m_stream.userBuffer[mode] = (char *) calloc(bufferBytes, 1);
if (m_stream.userBuffer[mode] == NULL) {
m_errorText = "airtaudio::api::Jack::probeDeviceOpen: error allocating user buffer memory.";
bufferBytes = m_stream.nUserChannels[_mode] * *_bufferSize * formatBytes(m_stream.userFormat);
m_stream.userBuffer[_mode] = (char *) calloc(bufferBytes, 1);
if (m_stream.userBuffer[_mode] == NULL) {
ATA_ERROR("airtaudio::api::Jack::probeDeviceOpen: error allocating user buffer memory.");
goto error;
}
if (m_stream.doConvertBuffer[mode]) {
if (m_stream.doConvertBuffer[_mode]) {
bool makeBuffer = true;
if (mode == OUTPUT)
if (_mode == OUTPUT) {
bufferBytes = m_stream.nDeviceChannels[0] * formatBytes(m_stream.deviceFormat[0]);
else { // mode == INPUT
} else { // _mode == INPUT
bufferBytes = m_stream.nDeviceChannels[1] * formatBytes(m_stream.deviceFormat[1]);
if (m_stream.mode == OUTPUT && m_stream.deviceBuffer) {
uint64_t bytesOut = m_stream.nDeviceChannels[0] * formatBytes(m_stream.deviceFormat[0]);
if (bufferBytes < bytesOut) makeBuffer = false;
if (bufferBytes < bytesOut) {
makeBuffer = false;
}
}
}
if (makeBuffer) {
bufferBytes *= *bufferSize;
bufferBytes *= *_bufferSize;
if (m_stream.deviceBuffer) free(m_stream.deviceBuffer);
m_stream.deviceBuffer = (char *) calloc(bufferBytes, 1);
if (m_stream.deviceBuffer == NULL) {
m_errorText = "airtaudio::api::Jack::probeDeviceOpen: error allocating device buffer memory.";
ATA_ERROR("airtaudio::api::Jack::probeDeviceOpen: error allocating device buffer memory.");
goto error;
}
}
}
// Allocate memory for the Jack ports (channels) identifiers.
handle->ports[mode] = (jack_port_t **) malloc (sizeof (jack_port_t *) * channels);
if (handle->ports[mode] == NULL) {
m_errorText = "airtaudio::api::Jack::probeDeviceOpen: error allocating port memory.";
handle->ports[_mode] = (jack_port_t **) malloc (sizeof (jack_port_t *) * _channels);
if (handle->ports[_mode] == NULL) {
ATA_ERROR("airtaudio::api::Jack::probeDeviceOpen: error allocating port memory.");
goto error;
}
m_stream.device[mode] = device;
m_stream.channelOffset[mode] = firstChannel;
m_stream.device[_mode] = _device;
m_stream.channelOffset[_mode] = _firstChannel;
m_stream.state = STREAM_STOPPED;
m_stream.callbackInfo.object = (void *) this;
if (m_stream.mode == OUTPUT && mode == INPUT)
if ( m_stream.mode == OUTPUT
&& _mode == INPUT) {
// We had already set up the stream for output.
m_stream.mode = DUPLEX;
else {
m_stream.mode = mode;
} else {
m_stream.mode = _mode;
jack_set_process_callback(handle->client, jackCallbackHandler, (void *) &m_stream.callbackInfo);
jack_set_xrun_callback(handle->client, jackXrun, (void *) &handle);
jack_on_shutdown(handle->client, jackShutdown, (void *) &m_stream.callbackInfo);
}
// Register our ports.
char label[64];
if (mode == OUTPUT) {
if (_mode == OUTPUT) {
for (uint32_t i=0; i<m_stream.nUserChannels[0]; i++) {
snprintf(label, 64, "outport %d", i);
handle->ports[0][i] = jack_port_register(handle->client,
@ -482,15 +457,13 @@ bool airtaudio::api::Jack::probeDeviceOpen(uint32_t device,
0);
}
}
// Setup the buffer conversion information structure. We don't use
// buffers to do channel offsets, so we override that parameter
// here.
if (m_stream.doConvertBuffer[mode]) {
setConvertInfo(mode, 0);
if (m_stream.doConvertBuffer[_mode]) {
setConvertInfo(_mode, 0);
}
return SUCCESS;
error:
if (handle) {
jack_client_close(handle->client);
@ -501,42 +474,34 @@ error:
free(handle->ports[1]);
}
delete handle;
m_stream.apiHandle = 0;
m_stream.apiHandle = NULL;
}
for (int32_t iii=0; iii<2; ++iii) {
if (m_stream.userBuffer[iii]) {
free(m_stream.userBuffer[iii]);
m_stream.userBuffer[iii] = 0;
m_stream.userBuffer[iii] = NULL;
}
}
if (m_stream.deviceBuffer) {
free(m_stream.deviceBuffer);
m_stream.deviceBuffer = 0;
m_stream.deviceBuffer = NULL;
}
return FAILURE;
}
void airtaudio::api::Jack::closeStream(void)
{
enum airtaudio::errorType airtaudio::api::Jack::closeStream(void) {
if (m_stream.state == STREAM_CLOSED) {
m_errorText = "airtaudio::api::Jack::closeStream(): no open stream to close!";
error(airtaudio::errorWarning);
return;
ATA_ERROR("airtaudio::api::Jack::closeStream(): no open stream to close!");
return airtaudio::errorWarning;
}
JackHandle *handle = (JackHandle *) m_stream.apiHandle;
if (handle) {
if (m_stream.state == STREAM_RUNNING)
if (handle != NULL) {
if (m_stream.state == STREAM_RUNNING) {
jack_deactivate(handle->client);
}
jack_client_close(handle->client);
}
if (handle) {
if (handle != NULL) {
if (handle->ports[0]) {
free(handle->ports[0]);
}
@ -544,52 +509,47 @@ void airtaudio::api::Jack::closeStream(void)
free(handle->ports[1]);
}
delete handle;
m_stream.apiHandle = 0;
m_stream.apiHandle = NULL;
}
for (int32_t i=0; i<2; i++) {
if (m_stream.userBuffer[i]) {
free(m_stream.userBuffer[i]);
m_stream.userBuffer[i] = 0;
m_stream.userBuffer[i] = NULL;
}
}
if (m_stream.deviceBuffer) {
free(m_stream.deviceBuffer);
m_stream.deviceBuffer = 0;
m_stream.deviceBuffer = NULL;
}
m_stream.mode = UNINITIALIZED;
m_stream.state = STREAM_CLOSED;
return airtaudio::errorNone;
}
void airtaudio::api::Jack::startStream(void)
{
verifyStream();
if (m_stream.state == STREAM_RUNNING) {
m_errorText = "airtaudio::api::Jack::startStream(): the stream is already running!";
error(airtaudio::errorWarning);
return;
enum airtaudio::errorType airtaudio::api::Jack::startStream(void) {
if (verifyStream() != airtaudio::errorNone) {
return airtaudio::errorFail;
}
if (m_stream.state == STREAM_RUNNING) {
ATA_ERROR("airtaudio::api::Jack::startStream(): the stream is already running!");
return airtaudio::errorWarning;
}
JackHandle *handle = (JackHandle *) m_stream.apiHandle;
int32_t result = jack_activate(handle->client);
if (result) {
m_errorText = "airtaudio::api::Jack::startStream(): unable to activate JACK client!";
ATA_ERROR("airtaudio::api::Jack::startStream(): unable to activate JACK client!");
goto unlock;
}
const char **ports;
// Get the list of available ports.
if (m_stream.mode == OUTPUT || m_stream.mode == DUPLEX) {
if ( m_stream.mode == OUTPUT
|| m_stream.mode == DUPLEX) {
result = 1;
ports = jack_get_ports(handle->client, handle->deviceName[0].c_str(), NULL, JackPortIsInput);
if (ports == NULL) {
m_errorText = "airtaudio::api::Jack::startStream(): error determining available JACK input ports!";
ATA_ERROR("airtaudio::api::Jack::startStream(): error determining available JACK input ports!");
goto unlock;
}
// Now make the port connections. Since RtAudio wasn't designed to
// allow the user to select particular channels of a device, we'll
// just open the first "nChannels" ports with offset.
@ -599,50 +559,51 @@ void airtaudio::api::Jack::startStream(void)
result = jack_connect(handle->client, jack_port_name(handle->ports[0][i]), ports[ m_stream.channelOffset[0] + i ]);
if (result) {
free(ports);
m_errorText = "airtaudio::api::Jack::startStream(): error connecting output ports!";
ATA_ERROR("airtaudio::api::Jack::startStream(): error connecting output ports!");
goto unlock;
}
}
free(ports);
}
if (m_stream.mode == INPUT || m_stream.mode == DUPLEX) {
if ( m_stream.mode == INPUT
|| m_stream.mode == DUPLEX) {
result = 1;
ports = jack_get_ports(handle->client, handle->deviceName[1].c_str(), NULL, JackPortIsOutput);
if (ports == NULL) {
m_errorText = "airtaudio::api::Jack::startStream(): error determining available JACK output ports!";
ATA_ERROR("airtaudio::api::Jack::startStream(): error determining available JACK output ports!");
goto unlock;
}
// Now make the port connections. See note above.
// Now make the port connections. See note above.
for (uint32_t i=0; i<m_stream.nUserChannels[1]; i++) {
result = 1;
if (ports[ m_stream.channelOffset[1] + i ])
if (ports[ m_stream.channelOffset[1] + i ]) {
result = jack_connect(handle->client, ports[ m_stream.channelOffset[1] + i ], jack_port_name(handle->ports[1][i]));
}
if (result) {
free(ports);
m_errorText = "airtaudio::api::Jack::startStream(): error connecting input ports!";
ATA_ERROR("airtaudio::api::Jack::startStream(): error connecting input ports!");
goto unlock;
}
}
free(ports);
}
handle->drainCounter = 0;
handle->internalDrain = false;
m_stream.state = STREAM_RUNNING;
unlock:
if (result == 0) return;
error(airtaudio::errorSystemError);
unlock:
if (result == 0) {
return airtaudio::errorNone;
}
return airtaudio::errorSystemError;
}
void airtaudio::api::Jack::stopStream(void) {
verifyStream();
enum airtaudio::errorType airtaudio::api::Jack::stopStream(void) {
if (verifyStream() != airtaudio::errorNone) {
return airtaudio::errorFail;
}
if (m_stream.state == STREAM_STOPPED) {
m_errorText = "airtaudio::api::Jack::stopStream(): the stream is already stopped!";
error(airtaudio::errorWarning);
return;
ATA_ERROR("airtaudio::api::Jack::stopStream(): the stream is already stopped!");
return airtaudio::errorWarning;
}
JackHandle *handle = (JackHandle *) m_stream.apiHandle;
if ( m_stream.mode == OUTPUT
@ -655,21 +616,20 @@ void airtaudio::api::Jack::stopStream(void) {
}
jack_deactivate(handle->client);
m_stream.state = STREAM_STOPPED;
return airtaudio::errorNone;
}
void airtaudio::api::Jack::abortStream(void)
{
verifyStream();
if (m_stream.state == STREAM_STOPPED) {
m_errorText = "airtaudio::api::Jack::abortStream(): the stream is already stopped!";
error(airtaudio::errorWarning);
return;
enum airtaudio::errorType airtaudio::api::Jack::abortStream(void) {
if (verifyStream() != airtaudio::errorNone) {
return airtaudio::errorFail;
}
if (m_stream.state == STREAM_STOPPED) {
ATA_ERROR("airtaudio::api::Jack::abortStream(): the stream is already stopped!");
return airtaudio::errorWarning;
}
JackHandle *handle = (JackHandle *) m_stream.apiHandle;
handle->drainCounter = 2;
stopStream();
return stopStream();
}
// This function will be called by a spawned thread when the user
@ -683,23 +643,21 @@ static void jackStopStream(void *_ptr) {
object->stopStream();
}
bool airtaudio::api::Jack::callbackEvent(uint64_t nframes)
{
if (m_stream.state == STREAM_STOPPED || m_stream.state == STREAM_STOPPING) return SUCCESS;
bool airtaudio::api::Jack::callbackEvent(uint64_t _nframes) {
if ( m_stream.state == STREAM_STOPPED
|| m_stream.state == STREAM_STOPPING) {
return SUCCESS;
}
if (m_stream.state == STREAM_CLOSED) {
m_errorText = "RtApiCore::callbackEvent(): the stream is closed ... this shouldn't happen!";
error(airtaudio::errorWarning);
ATA_ERROR("RtApiCore::callbackEvent(): the stream is closed ... this shouldn't happen!");
return FAILURE;
}
if (m_stream.bufferSize != nframes) {
m_errorText = "RtApiCore::callbackEvent(): the JACK buffer size has changed ... cannot process!";
error(airtaudio::errorWarning);
if (m_stream.bufferSize != _nframes) {
ATA_ERROR("RtApiCore::callbackEvent(): the JACK buffer size has changed ... cannot process!");
return FAILURE;
}
CallbackInfo *info = (CallbackInfo *) &m_stream.callbackInfo;
JackHandle *handle = (JackHandle *) m_stream.apiHandle;
// Check if we were draining the stream and signal is finished.
if (handle->drainCounter > 3) {
m_stream.state = STREAM_STOPPING;
@ -710,7 +668,6 @@ bool airtaudio::api::Jack::callbackEvent(uint64_t nframes)
}
return SUCCESS;
}
// Invoke user callback first, to get fresh output data.
if (handle->drainCounter == 0) {
airtaudio::AirTAudioCallback callback = (airtaudio::AirTAudioCallback) info->callback;
@ -724,8 +681,12 @@ bool airtaudio::api::Jack::callbackEvent(uint64_t nframes)
status |= INPUT_OVERFLOW;
handle->xrun[1] = false;
}
int32_t cbReturnValue = callback(m_stream.userBuffer[0], m_stream.userBuffer[1],
m_stream.bufferSize, streamTime, status, info->userData);
int32_t cbReturnValue = callback(m_stream.userBuffer[0],
m_stream.userBuffer[1],
m_stream.bufferSize,
streamTime,
status,
info->userData);
if (cbReturnValue == 2) {
m_stream.state = STREAM_STOPPING;
handle->drainCounter = 2;
@ -737,61 +698,51 @@ bool airtaudio::api::Jack::callbackEvent(uint64_t nframes)
handle->internalDrain = true;
}
}
jack_default_audio_sample_t *jackbuffer;
uint64_t bufferBytes = nframes * sizeof(jack_default_audio_sample_t);
uint64_t bufferBytes = _nframes * sizeof(jack_default_audio_sample_t);
if (m_stream.mode == OUTPUT || m_stream.mode == DUPLEX) {
if (handle->drainCounter > 1) { // write zeros to the output stream
for (uint32_t i=0; i<m_stream.nDeviceChannels[0]; i++) {
jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer(handle->ports[0][i], (jack_nframes_t) nframes);
jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer(handle->ports[0][i], (jack_nframes_t) _nframes);
memset(jackbuffer, 0, bufferBytes);
}
}
else if (m_stream.doConvertBuffer[0]) {
} else if (m_stream.doConvertBuffer[0]) {
convertBuffer(m_stream.deviceBuffer, m_stream.userBuffer[0], m_stream.convertInfo[0]);
for (uint32_t i=0; i<m_stream.nDeviceChannels[0]; i++) {
jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer(handle->ports[0][i], (jack_nframes_t) nframes);
jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer(handle->ports[0][i], (jack_nframes_t) _nframes);
memcpy(jackbuffer, &m_stream.deviceBuffer[i*bufferBytes], bufferBytes);
}
}
else { // no buffer conversion
} else { // no buffer conversion
for (uint32_t i=0; i<m_stream.nUserChannels[0]; i++) {
jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer(handle->ports[0][i], (jack_nframes_t) nframes);
jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer(handle->ports[0][i], (jack_nframes_t) _nframes);
memcpy(jackbuffer, &m_stream.userBuffer[0][i*bufferBytes], bufferBytes);
}
}
if (handle->drainCounter) {
handle->drainCounter++;
goto unlock;
}
}
if ( m_stream.mode == INPUT
|| m_stream.mode == DUPLEX) {
if (m_stream.doConvertBuffer[1]) {
for (uint32_t i=0; i<m_stream.nDeviceChannels[1]; i++) {
jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer(handle->ports[1][i], (jack_nframes_t) nframes);
jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer(handle->ports[1][i], (jack_nframes_t) _nframes);
memcpy(&m_stream.deviceBuffer[i*bufferBytes], jackbuffer, bufferBytes);
}
convertBuffer(m_stream.userBuffer[1], m_stream.deviceBuffer, m_stream.convertInfo[1]);
} else {
// no buffer conversion
for (uint32_t i=0; i<m_stream.nUserChannels[1]; i++) {
jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer(handle->ports[1][i], (jack_nframes_t) nframes);
jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer(handle->ports[1][i], (jack_nframes_t) _nframes);
memcpy(&m_stream.userBuffer[1][i*bufferBytes], jackbuffer, bufferBytes);
}
}
}
unlock:
airtaudio::Api::tickStreamTime();
return SUCCESS;
}
//******************** End of __UNIX_JACK__ *********************//
#endif

View File

@ -22,10 +22,10 @@ namespace airtaudio {
}
uint32_t getDeviceCount(void);
airtaudio::DeviceInfo getDeviceInfo(uint32_t _device);
void closeStream(void);
void startStream(void);
void stopStream(void);
void abortStream(void);
enum airtaudio::errorType closeStream(void);
enum airtaudio::errorType startStream(void);
enum airtaudio::errorType stopStream(void);
enum airtaudio::errorType abortStream(void);
long getStreamLatency(void);
// This function is intended for internal use only. It must be
// public because it is called by the internal callback handler,

View File

@ -9,6 +9,7 @@
#if defined(__LINUX_OSS__)
#include <airtaudio/Interface.h>
#include <airtaudio/debug.h>
#include <unistd.h>
#include <sys/ioctl.h>
@ -616,8 +617,7 @@ bool airtaudio::api::Oss::probeDeviceOpen(uint32_t device, StreamMode mode, uint
return FAILURE;
}
void airtaudio::api::Oss::closeStream()
{
enum airtaudio::errorType airtaudio::api::Oss::closeStream(void) {
if (m_stream.state == STREAM_CLOSED) {
m_errorText = "airtaudio::api::Oss::closeStream(): no open stream to close!";
error(airtaudio::errorWarning);
@ -664,9 +664,10 @@ void airtaudio::api::Oss::closeStream()
m_stream.state = STREAM_CLOSED;
}
void airtaudio::api::Oss::startStream()
{
verifyStream();
enum airtaudio::errorType airtaudio::api::Oss::startStream(void) {
if (verifyStream() != airtaudio::errorNone) {
return airtaudio::errorFail;
}
if (m_stream.state == STREAM_RUNNING) {
m_errorText = "airtaudio::api::Oss::startStream(): the stream is already running!";
error(airtaudio::errorWarning);
@ -686,9 +687,10 @@ void airtaudio::api::Oss::startStream()
pthread_cond_signal(&handle->runnable);
}
void airtaudio::api::Oss::stopStream()
{
verifyStream();
enum airtaudio::errorType airtaudio::api::Oss::stopStream(void) {
if (verifyStream() != airtaudio::errorNone) {
return airtaudio::errorFail;
}
if (m_stream.state == STREAM_STOPPED) {
m_errorText = "airtaudio::api::Oss::stopStream(): the stream is already stopped!";
error(airtaudio::errorWarning);
@ -758,9 +760,10 @@ void airtaudio::api::Oss::stopStream()
error(airtaudio::errorSystemError);
}
void airtaudio::api::Oss::abortStream()
{
verifyStream();
enum airtaudio::errorType airtaudio::api::Oss::abortStream(void) {
if (verifyStream() != airtaudio::errorNone) {
return airtaudio::errorFail;
}
if (m_stream.state == STREAM_STOPPED) {
m_errorText = "airtaudio::api::Oss::abortStream(): the stream is already stopped!";
error(airtaudio::errorWarning);
@ -804,8 +807,7 @@ void airtaudio::api::Oss::abortStream()
*error(airtaudio::errorSystemError);
}
void airtaudio::api::Oss::callbackEvent()
{
void airtaudio::api::Oss::callbackEvent(void) {
OssHandle *handle = (OssHandle *) m_stream.apiHandle;
if (m_stream.state == STREAM_STOPPED) {
m_stream.mutex.lock();

View File

@ -22,10 +22,10 @@ namespace airtaudio {
}
uint32_t getDeviceCount(void);
airtaudio::DeviceInfo getDeviceInfo(uint32_t _device);
void closeStream(void);
void startStream(void);
void stopStream(void);
void abortStream(void);
enum airtaudio::errorType closeStream(void);
enum airtaudio::errorType startStream(void);
enum airtaudio::errorType stopStream(void);
enum airtaudio::errorType abortStream(void);
// This function is intended for internal use only. It must be
// public because it is called by the internal callback handler,
// which is not a member of RtAudio. External use of this function

View File

@ -12,6 +12,7 @@
#include <unistd.h>
#include <limits.h>
#include <airtaudio/Interface.h>
#include <airtaudio/debug.h>
// Code written by Peter Meerwald, pmeerw@pmeerw.net
// and Tristan Matthews.
@ -60,10 +61,10 @@ struct PulseAudioHandle {
}
};
airtaudio::api::Pulse::~Pulse()
{
if (m_stream.state != STREAM_CLOSED)
airtaudio::api::Pulse::~Pulse(void) {
if (m_stream.state != STREAM_CLOSED) {
closeStream();
}
}
uint32_t airtaudio::api::Pulse::getDeviceCount(void) {
@ -95,7 +96,7 @@ static void pulseaudio_callback(void* _user) {
}
}
void airtaudio::api::Pulse::closeStream(void) {
enum airtaudio::errorType airtaudio::api::Pulse::closeStream(void) {
PulseAudioHandle *pah = static_cast<PulseAudioHandle *>(m_stream.apiHandle);
m_stream.callbackInfo.isRunning = false;
if (pah) {
@ -114,7 +115,7 @@ void airtaudio::api::Pulse::closeStream(void) {
pa_simple_free(pah->s_rec);
}
delete pah;
m_stream.apiHandle = 0;
m_stream.apiHandle = NULL;
}
if (m_stream.userBuffer[0] != NULL) {
free(m_stream.userBuffer[0]);
@ -126,6 +127,7 @@ void airtaudio::api::Pulse::closeStream(void) {
}
m_stream.state = STREAM_CLOSED;
m_stream.mode = UNINITIALIZED;
return airtaudio::errorNone;
}
void airtaudio::api::Pulse::callbackEvent(void) {
@ -141,9 +143,7 @@ void airtaudio::api::Pulse::callbackEvent(void) {
}
}
if (m_stream.state == STREAM_CLOSED) {
m_errorText = "airtaudio::api::Pulse::callbackEvent(): the stream is closed ... "
"this shouldn't happen!";
error(airtaudio::errorWarning);
ATA_ERROR("airtaudio::api::Pulse::callbackEvent(): the stream is closed ... this shouldn't happen!");
return;
}
airtaudio::AirTAudioCallback callback = (airtaudio::AirTAudioCallback) m_stream.callbackInfo.callback;
@ -178,9 +178,8 @@ void airtaudio::api::Pulse::callbackEvent(void) {
bytes = m_stream.nUserChannels[OUTPUT] * m_stream.bufferSize * formatBytes(m_stream.userFormat);
}
if (pa_simple_write(pah->s_play, pulse_out, bytes, &pa_error) < 0) {
m_errorStream << "airtaudio::api::Pulse::callbackEvent: audio write error, " << pa_strerror(pa_error) << ".";
m_errorText = m_errorStream.str();
error(airtaudio::errorWarning);
ATA_ERROR("airtaudio::api::Pulse::callbackEvent: audio write error, " << pa_strerror(pa_error) << ".");
return;
}
}
if (m_stream.mode == INPUT || m_stream.mode == DUPLEX) {
@ -190,9 +189,8 @@ void airtaudio::api::Pulse::callbackEvent(void) {
bytes = m_stream.nUserChannels[INPUT] * m_stream.bufferSize * formatBytes(m_stream.userFormat);
}
if (pa_simple_read(pah->s_rec, pulse_in, bytes, &pa_error) < 0) {
m_errorStream << "airtaudio::api::Pulse::callbackEvent: audio read error, " << pa_strerror(pa_error) << ".";
m_errorText = m_errorStream.str();
error(airtaudio::errorWarning);
ATA_ERROR("airtaudio::api::Pulse::callbackEvent: audio read error, " << pa_strerror(pa_error) << ".");
return;
}
if (m_stream.doConvertBuffer[INPUT]) {
convertBuffer(m_stream.userBuffer[INPUT],
@ -200,135 +198,127 @@ void airtaudio::api::Pulse::callbackEvent(void) {
m_stream.convertInfo[INPUT]);
}
}
unlock:
m_stream.mutex.unlock();
airtaudio::Api::tickStreamTime();
if (doStopStream == 1) {
stopStream();
return;
}
return;
}
void airtaudio::api::Pulse::startStream(void) {
enum airtaudio::errorType airtaudio::api::Pulse::startStream(void) {
PulseAudioHandle *pah = static_cast<PulseAudioHandle *>(m_stream.apiHandle);
if (m_stream.state == STREAM_CLOSED) {
m_errorText = "airtaudio::api::Pulse::startStream(): the stream is not open!";
error(airtaudio::errorInvalidUse);
return;
ATA_ERROR("airtaudio::api::Pulse::startStream(): the stream is not open!");
return airtaudio::errorInvalidUse;
}
if (m_stream.state == STREAM_RUNNING) {
m_errorText = "airtaudio::api::Pulse::startStream(): the stream is already running!";
error(airtaudio::errorWarning);
return;
ATA_ERROR("airtaudio::api::Pulse::startStream(): the stream is already running!");
return airtaudio::errorWarning;
}
m_stream.mutex.lock();
m_stream.state = STREAM_RUNNING;
pah->runnable = true;
pah->runnable_cv.notify_one();
m_stream.mutex.unlock();
return airtaudio::errorNone;
}
void airtaudio::api::Pulse::stopStream(void) {
enum airtaudio::errorType airtaudio::api::Pulse::stopStream(void) {
PulseAudioHandle *pah = static_cast<PulseAudioHandle *>(m_stream.apiHandle);
if (m_stream.state == STREAM_CLOSED) {
m_errorText = "airtaudio::api::Pulse::stopStream(): the stream is not open!";
error(airtaudio::errorInvalidUse);
return;
ATA_ERROR("airtaudio::api::Pulse::stopStream(): the stream is not open!");
return airtaudio::errorInvalidUse;
}
if (m_stream.state == STREAM_STOPPED) {
m_errorText = "airtaudio::api::Pulse::stopStream(): the stream is already stopped!";
error(airtaudio::errorWarning);
return;
ATA_ERROR("airtaudio::api::Pulse::stopStream(): the stream is already stopped!");
return airtaudio::errorWarning;
}
m_stream.state = STREAM_STOPPED;
m_stream.mutex.lock();
if (pah && pah->s_play) {
int32_t pa_error;
if (pa_simple_drain(pah->s_play, &pa_error) < 0) {
m_errorStream << "airtaudio::api::Pulse::stopStream: error draining output device, " <<
pa_strerror(pa_error) << ".";
m_errorText = m_errorStream.str();
ATA_ERROR("airtaudio::api::Pulse::stopStream: error draining output device, " << pa_strerror(pa_error) << ".");
m_stream.mutex.unlock();
error(airtaudio::errorSystemError);
return;
return airtaudio::errorSystemError;
}
}
m_stream.state = STREAM_STOPPED;
m_stream.mutex.unlock();
return airtaudio::errorNone;
}
void airtaudio::api::Pulse::abortStream(void) {
enum airtaudio::errorType airtaudio::api::Pulse::abortStream(void) {
PulseAudioHandle *pah = static_cast<PulseAudioHandle*>(m_stream.apiHandle);
if (m_stream.state == STREAM_CLOSED) {
m_errorText = "airtaudio::api::Pulse::abortStream(): the stream is not open!";
error(airtaudio::errorInvalidUse);
return;
ATA_ERROR("airtaudio::api::Pulse::abortStream(): the stream is not open!");
return airtaudio::errorInvalidUse;
}
if (m_stream.state == STREAM_STOPPED) {
m_errorText = "airtaudio::api::Pulse::abortStream(): the stream is already stopped!";
error(airtaudio::errorWarning);
return;
ATA_ERROR("airtaudio::api::Pulse::abortStream(): the stream is already stopped!");
return airtaudio::errorWarning;
}
m_stream.state = STREAM_STOPPED;
m_stream.mutex.lock();
if (pah && pah->s_play) {
int32_t pa_error;
if (pa_simple_flush(pah->s_play, &pa_error) < 0) {
m_errorStream << "airtaudio::api::Pulse::abortStream: error flushing output device, " <<
pa_strerror(pa_error) << ".";
m_errorText = m_errorStream.str();
ATA_ERROR("airtaudio::api::Pulse::abortStream: error flushing output device, " << pa_strerror(pa_error) << ".");
m_stream.mutex.unlock();
error(airtaudio::errorSystemError);
return;
return airtaudio::errorSystemError;
}
}
m_stream.state = STREAM_STOPPED;
m_stream.mutex.unlock();
return airtaudio::errorNone;
}
bool airtaudio::api::Pulse::probeDeviceOpen(uint32_t device,
airtaudio::api::StreamMode mode,
uint32_t channels,
uint32_t firstChannel,
uint32_t sampleRate,
airtaudio::format format,
uint32_t *bufferSize,
airtaudio::StreamOptions *options) {
bool airtaudio::api::Pulse::probeDeviceOpen(uint32_t _device,
airtaudio::api::StreamMode _mode,
uint32_t _channels,
uint32_t _firstChannel,
uint32_t _sampleRate,
airtaudio::format _format,
uint32_t *_bufferSize,
airtaudio::StreamOptions *_options) {
PulseAudioHandle *pah = 0;
uint64_t bufferBytes = 0;
pa_sample_spec ss;
if (device != 0) {
if (_device != 0) {
return false;
}
if (mode != INPUT && mode != OUTPUT) {
if (_mode != INPUT && _mode != OUTPUT) {
return false;
}
if (channels != 1 && channels != 2) {
m_errorText = "airtaudio::api::Pulse::probeDeviceOpen: unsupported number of channels.";
if (_channels != 1 && _channels != 2) {
ATA_ERROR("airtaudio::api::Pulse::probeDeviceOpen: unsupported number of channels.");
return false;
}
ss.channels = channels;
if (firstChannel != 0) {
ss.channels = _channels;
if (_firstChannel != 0) {
return false;
}
bool sr_found = false;
for (const uint32_t *sr = SUPPORTED_SAMPLERATES; *sr; ++sr) {
if (sampleRate == *sr) {
if (_sampleRate == *sr) {
sr_found = true;
m_stream.sampleRate = sampleRate;
ss.rate = sampleRate;
m_stream.sampleRate = _sampleRate;
ss.rate = _sampleRate;
break;
}
}
if (!sr_found) {
m_errorText = "airtaudio::api::Pulse::probeDeviceOpen: unsupported sample rate.";
ATA_ERROR("airtaudio::api::Pulse::probeDeviceOpen: unsupported sample rate.");
return false;
}
bool sf_found = 0;
for (const rtaudio_pa_format_mapping_t *sf = supported_sampleformats;
sf->airtaudio_format && sf->pa_format != PA_SAMPLE_INVALID;
++sf) {
if (format == sf->airtaudio_format) {
if (_format == sf->airtaudio_format) {
sf_found = true;
m_stream.userFormat = sf->airtaudio_format;
ss.format = sf->pa_format;
@ -336,80 +326,77 @@ bool airtaudio::api::Pulse::probeDeviceOpen(uint32_t device,
}
}
if (!sf_found) {
m_errorText = "airtaudio::api::Pulse::probeDeviceOpen: unsupported sample format.";
ATA_ERROR("airtaudio::api::Pulse::probeDeviceOpen: unsupported sample format.");
return false;
}
// Set interleaving parameters.
if (options && options->flags & NONINTERLEAVED) {
if (_options && _options->flags & NONINTERLEAVED) {
m_stream.userInterleaved = false;
} else {
m_stream.userInterleaved = true;
}
m_stream.deviceInterleaved[mode] = true;
m_stream.deviceInterleaved[_mode] = true;
m_stream.nBuffers = 1;
m_stream.doByteSwap[mode] = false;
m_stream.doConvertBuffer[mode] = channels > 1 && !m_stream.userInterleaved;
m_stream.deviceFormat[mode] = m_stream.userFormat;
m_stream.nUserChannels[mode] = channels;
m_stream.nDeviceChannels[mode] = channels + firstChannel;
m_stream.channelOffset[mode] = 0;
m_stream.doByteSwap[_mode] = false;
m_stream.doConvertBuffer[_mode] = _channels > 1 && !m_stream.userInterleaved;
m_stream.deviceFormat[_mode] = m_stream.userFormat;
m_stream.nUserChannels[_mode] = _channels;
m_stream.nDeviceChannels[_mode] = _channels + _firstChannel;
m_stream.channelOffset[_mode] = 0;
// Allocate necessary internal buffers.
bufferBytes = m_stream.nUserChannels[mode] * *bufferSize * formatBytes(m_stream.userFormat);
m_stream.userBuffer[mode] = (char *) calloc(bufferBytes, 1);
if (m_stream.userBuffer[mode] == NULL) {
m_errorText = "airtaudio::api::Pulse::probeDeviceOpen: error allocating user buffer memory.";
bufferBytes = m_stream.nUserChannels[_mode] * *_bufferSize * formatBytes(m_stream.userFormat);
m_stream.userBuffer[_mode] = (char *) calloc(bufferBytes, 1);
if (m_stream.userBuffer[_mode] == NULL) {
ATA_ERROR("airtaudio::api::Pulse::probeDeviceOpen: error allocating user buffer memory.");
goto error;
}
m_stream.bufferSize = *bufferSize;
if (m_stream.doConvertBuffer[mode]) {
m_stream.bufferSize = *_bufferSize;
if (m_stream.doConvertBuffer[_mode]) {
bool makeBuffer = true;
bufferBytes = m_stream.nDeviceChannels[mode] * formatBytes(m_stream.deviceFormat[mode]);
if (mode == INPUT) {
bufferBytes = m_stream.nDeviceChannels[_mode] * formatBytes(m_stream.deviceFormat[_mode]);
if (_mode == INPUT) {
if (m_stream.mode == OUTPUT && m_stream.deviceBuffer) {
uint64_t bytesOut = m_stream.nDeviceChannels[0] * formatBytes(m_stream.deviceFormat[0]);
if (bufferBytes <= bytesOut) makeBuffer = false;
}
}
if (makeBuffer) {
bufferBytes *= *bufferSize;
bufferBytes *= *_bufferSize;
if (m_stream.deviceBuffer) free(m_stream.deviceBuffer);
m_stream.deviceBuffer = (char *) calloc(bufferBytes, 1);
if (m_stream.deviceBuffer == NULL) {
m_errorText = "airtaudio::api::Pulse::probeDeviceOpen: error allocating device buffer memory.";
ATA_ERROR("airtaudio::api::Pulse::probeDeviceOpen: error allocating device buffer memory.");
goto error;
}
}
}
m_stream.device[mode] = device;
m_stream.device[_mode] = _device;
// Setup the buffer conversion information structure.
if (m_stream.doConvertBuffer[mode]) {
setConvertInfo(mode, firstChannel);
if (m_stream.doConvertBuffer[_mode]) {
setConvertInfo(_mode, _firstChannel);
}
if (!m_stream.apiHandle) {
PulseAudioHandle *pah = new PulseAudioHandle;
if (!pah) {
m_errorText = "airtaudio::api::Pulse::probeDeviceOpen: error allocating memory for handle.";
ATA_ERROR("airtaudio::api::Pulse::probeDeviceOpen: error allocating memory for handle.");
goto error;
}
m_stream.apiHandle = pah;
}
pah = static_cast<PulseAudioHandle *>(m_stream.apiHandle);
int32_t error;
switch (mode) {
switch (_mode) {
case INPUT:
pah->s_rec = pa_simple_new(NULL, "RtAudio", PA_STREAM_RECORD, NULL, "Record", &ss, NULL, NULL, &error);
if (!pah->s_rec) {
m_errorText = "airtaudio::api::Pulse::probeDeviceOpen: error connecting input to PulseAudio server.";
ATA_ERROR("airtaudio::api::Pulse::probeDeviceOpen: error connecting input to PulseAudio server.");
goto error;
}
break;
case OUTPUT:
pah->s_play = pa_simple_new(NULL, "RtAudio", PA_STREAM_PLAYBACK, NULL, "Playback", &ss, NULL, NULL, &error);
if (!pah->s_play) {
m_errorText = "airtaudio::api::Pulse::probeDeviceOpen: error connecting output to PulseAudio server.";
ATA_ERROR("airtaudio::api::Pulse::probeDeviceOpen: error connecting output to PulseAudio server.");
goto error;
}
break;
@ -417,8 +404,8 @@ bool airtaudio::api::Pulse::probeDeviceOpen(uint32_t device,
goto error;
}
if (m_stream.mode == UNINITIALIZED) {
m_stream.mode = mode;
} else if (m_stream.mode == mode) {
m_stream.mode = _mode;
} else if (m_stream.mode == _mode) {
goto error;
}else {
m_stream.mode = DUPLEX;
@ -428,13 +415,12 @@ bool airtaudio::api::Pulse::probeDeviceOpen(uint32_t device,
m_stream.callbackInfo.isRunning = true;
pah->thread = new std::thread(pulseaudio_callback, (void *)&m_stream.callbackInfo);
if (pah->thread == NULL) {
m_errorText = "airtaudio::api::Pulse::probeDeviceOpen: error creating thread.";
ATA_ERROR("airtaudio::api::Pulse::probeDeviceOpen: error creating thread.");
goto error;
}
}
m_stream.state = STREAM_STOPPED;
return true;
error:
if (pah && m_stream.callbackInfo.isRunning) {
delete pah;

View File

@ -21,10 +21,10 @@ namespace airtaudio {
}
uint32_t getDeviceCount(void);
airtaudio::DeviceInfo getDeviceInfo(uint32_t _device);
void closeStream(void);
void startStream(void);
void stopStream(void);
void abortStream(void);
enum airtaudio::errorType closeStream(void);
enum airtaudio::errorType startStream(void);
enum airtaudio::errorType stopStream(void);
enum airtaudio::errorType abortStream(void);
// This function is intended for internal use only. It must be
// public because it is called by the internal callback handler,
// which is not a member of RtAudio. External use of this function

View File

@ -28,6 +28,7 @@ namespace airtaudio {
errorNone, //!< No error
errorFail, //!< An error occure in the operation
errorWarning, //!< A non-critical error.
errorInputNull, //!< null input or internal errror
errorInvalidUse, //!< The function was called incorrectly.
errorSystemError //!< A system error occured.
};
@ -171,14 +172,6 @@ namespace airtaudio {
double _streamTime,
airtaudio::streamStatus _status,
void *_userData);
/**
* @brief RtAudio error callback function prototype.
* @param _type Type of error.
* @param _errorText Error description.
*/
typedef void (*AirTAudioErrorCallback)(airtaudio::errorType _type,
const std::string &_errorText);
}
#include <airtaudio/DeviceInfo.h>

12
airtaudio/debug.cpp Normal file
View File

@ -0,0 +1,12 @@
/**
* @author Edouard DUPIN
*
* @copyright 2011, Edouard DUPIN, all right reserved
*
* @license BSD v3 (see license file)
*/
#include <airtaudio/debug.h>
const char * airtaudioLibName = "airtaudio";

28
airtaudio/debug.h Normal file
View File

@ -0,0 +1,28 @@
/**
* @author Edouard DUPIN
*
* @copyright 2011, Edouard DUPIN, all right reserved
*
* @license BSD v3 (see license file)
*/
#ifndef __EAUDIOFX_DEBUG_H__
#define __EAUDIOFX_DEBUG_H__
#include <etk/types.h>
#include <etk/debugGeneric.h>
extern const char * airtaudioLibName;
#define ATA_CRITICAL(data) ETK_CRITICAL(airtaudioLibName, data)
#define ATA_WARNING(data) ETK_WARNING(airtaudioLibName, data)
#define ATA_ERROR(data) ETK_ERROR(airtaudioLibName, data)
#define ATA_INFO(data) ETK_INFO(airtaudioLibName, data)
#define ATA_DEBUG(data) ETK_DEBUG(airtaudioLibName, data)
#define ATA_VERBOSE(data) ETK_VERBOSE(airtaudioLibName, data)
#define ATA_ASSERT(cond,data) ETK_ASSERT(airtaudioLibName, cond, data)
#define ATA_CHECK_INOUT(cond) ETK_CHECK_INOUT(airtaudioLibName, cond)
#define ATA_TODO(cond) ETK_TODO(airtaudioLibName, cond)
#endif

View File

@ -11,6 +11,7 @@ def create(target):
myModule = module.Module(__file__, 'airtaudio', 'LIBRARY')
myModule.add_src_file([
'airtaudio/debug.cpp',
'airtaudio/Interface.cpp',
'airtaudio/Api.cpp',
'airtaudio/api/Alsa.cpp',
@ -23,6 +24,7 @@ def create(target):
'airtaudio/api/Pulse.cpp'
])
myModule.add_export_flag_CC(['-D__AIRTAUDIO_API_DUMMY_H__'])
if target.name=="Windows":
# ASIO API on Windows
myModule.add_export_flag_CC(['__WINDOWS_ASIO__'])
@ -39,8 +41,6 @@ def create(target):
myModule.add_export_flag_CC(['-D__LINUX_PULSE__'])
myModule.add_export_flag_LD("-lpulse-simple")
myModule.add_export_flag_LD("-lpulse")
#depending libs :
myModule.add_export_flag_LD("-lpthread")
elif target.name=="MacOs":
# MacOsX core
myModule.add_export_flag_CC(['__MACOSX_CORE__'])
@ -53,6 +53,10 @@ def create(target):
myModule.add_path(tools.get_current_path(__file__)+"/rtaudio/")
myModule.add_path(tools.get_current_path(__file__)+"/rtaudio/include/")
# TODO : Remove this when debug will be unified ...
# name of the dependency
myModule.add_module_depend(['ewol'])
# add the currrent module at the
return myModule