[DEV] remove many exception
This commit is contained in:
parent
fca89ede03
commit
366d9a7049
@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <airtaudio/Interface.h>
|
#include <airtaudio/Interface.h>
|
||||||
|
#include <airtaudio/debug.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
@ -16,8 +17,20 @@
|
|||||||
// Static variable definitions.
|
// Static variable definitions.
|
||||||
const uint32_t airtaudio::api::MAX_SAMPLE_RATES = 14;
|
const uint32_t airtaudio::api::MAX_SAMPLE_RATES = 14;
|
||||||
const uint32_t airtaudio::api::SAMPLE_RATES[] = {
|
const uint32_t airtaudio::api::SAMPLE_RATES[] = {
|
||||||
4000, 5512, 8000, 9600, 11025, 16000, 22050,
|
4000,
|
||||||
32000, 44100, 48000, 88200, 96000, 176400, 192000
|
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.apiHandle = 0;
|
||||||
m_stream.userBuffer[0] = 0;
|
m_stream.userBuffer[0] = 0;
|
||||||
m_stream.userBuffer[1] = 0;
|
m_stream.userBuffer[1] = 0;
|
||||||
m_showWarnings = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
airtaudio::Api::~Api(void) {
|
airtaudio::Api::~Api(void) {
|
||||||
@ -41,50 +53,42 @@ enum airtaudio::errorType airtaudio::Api::openStream(airtaudio::StreamParameters
|
|||||||
uint32_t *bufferFrames,
|
uint32_t *bufferFrames,
|
||||||
airtaudio::AirTAudioCallback callback,
|
airtaudio::AirTAudioCallback callback,
|
||||||
void *userData,
|
void *userData,
|
||||||
airtaudio::StreamOptions *options,
|
airtaudio::StreamOptions *options) {
|
||||||
airtaudio::AirTAudioErrorCallback errorCallback) {
|
|
||||||
if (m_stream.state != airtaudio::api::STREAM_CLOSED) {
|
if (m_stream.state != airtaudio::api::STREAM_CLOSED) {
|
||||||
m_errorText = "airtaudio::Api::openStream: a stream is already open!";
|
ATA_ERROR("airtaudio::Api::openStream: a stream is already open!");
|
||||||
error(airtaudio::errorInvalidUse);
|
return airtaudio::errorInvalidUse;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
if (oParams && oParams->nChannels < 1) {
|
if (oParams && oParams->nChannels < 1) {
|
||||||
m_errorText = "airtaudio::Api::openStream: a non-NULL output StreamParameters structure cannot have an nChannels value less than one.";
|
ATA_ERROR("airtaudio::Api::openStream: a non-NULL output StreamParameters structure cannot have an nChannels value less than one.");
|
||||||
error(airtaudio::errorInvalidUse);
|
return airtaudio::errorInvalidUse;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
if (iParams && iParams->nChannels < 1) {
|
if (iParams && iParams->nChannels < 1) {
|
||||||
m_errorText = "airtaudio::Api::openStream: a non-NULL input StreamParameters structure cannot have an nChannels value less than one.";
|
ATA_ERROR("airtaudio::Api::openStream: a non-NULL input StreamParameters structure cannot have an nChannels value less than one.");
|
||||||
error(airtaudio::errorInvalidUse);
|
return airtaudio::errorInvalidUse;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
if (oParams == NULL && iParams == NULL) {
|
if (oParams == NULL && iParams == NULL) {
|
||||||
m_errorText = "airtaudio::Api::openStream: input and output StreamParameters structures are both NULL!";
|
ATA_ERROR("airtaudio::Api::openStream: input and output StreamParameters structures are both NULL!");
|
||||||
error(airtaudio::errorInvalidUse);
|
return airtaudio::errorInvalidUse;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
if (formatBytes(format) == 0) {
|
if (formatBytes(format) == 0) {
|
||||||
m_errorText = "airtaudio::Api::openStream: 'format' parameter value is undefined.";
|
ATA_ERROR("airtaudio::Api::openStream: 'format' parameter value is undefined.");
|
||||||
error(airtaudio::errorInvalidUse);
|
return airtaudio::errorInvalidUse;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
uint32_t nDevices = getDeviceCount();
|
uint32_t nDevices = getDeviceCount();
|
||||||
uint32_t oChannels = 0;
|
uint32_t oChannels = 0;
|
||||||
if (oParams) {
|
if (oParams) {
|
||||||
oChannels = oParams->nChannels;
|
oChannels = oParams->nChannels;
|
||||||
if (oParams->deviceId >= nDevices) {
|
if (oParams->deviceId >= nDevices) {
|
||||||
m_errorText = "airtaudio::Api::openStream: output device parameter value is invalid.";
|
ATA_ERROR("airtaudio::Api::openStream: output device parameter value is invalid.");
|
||||||
error(airtaudio::errorInvalidUse);
|
return airtaudio::errorInvalidUse;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
uint32_t iChannels = 0;
|
uint32_t iChannels = 0;
|
||||||
if (iParams) {
|
if (iParams) {
|
||||||
iChannels = iParams->nChannels;
|
iChannels = iParams->nChannels;
|
||||||
if (iParams->deviceId >= nDevices) {
|
if (iParams->deviceId >= nDevices) {
|
||||||
m_errorText = "airtaudio::Api::openStream: input device parameter value is invalid.";
|
ATA_ERROR("airtaudio::Api::openStream: input device parameter value is invalid.");
|
||||||
error(airtaudio::errorInvalidUse);
|
return airtaudio::errorInvalidUse;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
clearStreamInfo();
|
clearStreamInfo();
|
||||||
@ -99,8 +103,8 @@ enum airtaudio::errorType airtaudio::Api::openStream(airtaudio::StreamParameters
|
|||||||
bufferFrames,
|
bufferFrames,
|
||||||
options);
|
options);
|
||||||
if (result == false) {
|
if (result == false) {
|
||||||
error(airtaudio::errorSystemError);
|
ATA_ERROR("system ERROR");
|
||||||
return;
|
return airtaudio::errorSystemError;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (iChannels > 0) {
|
if (iChannels > 0) {
|
||||||
@ -116,17 +120,17 @@ enum airtaudio::errorType airtaudio::Api::openStream(airtaudio::StreamParameters
|
|||||||
if (oChannels > 0) {
|
if (oChannels > 0) {
|
||||||
closeStream();
|
closeStream();
|
||||||
}
|
}
|
||||||
error(airtaudio::errorSystemError);
|
ATA_ERROR("system error");
|
||||||
return;
|
return airtaudio::errorSystemError;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_stream.callbackInfo.callback = (void *) callback;
|
m_stream.callbackInfo.callback = (void *) callback;
|
||||||
m_stream.callbackInfo.userData = userData;
|
m_stream.callbackInfo.userData = userData;
|
||||||
m_stream.callbackInfo.errorCallback = (void *) errorCallback;
|
|
||||||
if (options != NULL) {
|
if (options != NULL) {
|
||||||
options->numberOfBuffers = m_stream.nBuffers;
|
options->numberOfBuffers = m_stream.nBuffers;
|
||||||
}
|
}
|
||||||
m_stream.state = airtaudio::api::STREAM_STOPPED;
|
m_stream.state = airtaudio::api::STREAM_STOPPED;
|
||||||
|
return airtaudio::errorNone;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t airtaudio::Api::getDefaultInputDevice(void) {
|
uint32_t airtaudio::Api::getDefaultInputDevice(void) {
|
||||||
@ -167,19 +171,25 @@ void airtaudio::Api::tickStreamTime(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
long airtaudio::Api::getStreamLatency(void) {
|
long airtaudio::Api::getStreamLatency(void) {
|
||||||
verifyStream();
|
if (verifyStream() != airtaudio::errorNone) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
long totalLatency = 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];
|
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];
|
totalLatency += m_stream.latency[1];
|
||||||
}
|
}
|
||||||
return totalLatency;
|
return totalLatency;
|
||||||
}
|
}
|
||||||
|
|
||||||
double airtaudio::Api::getStreamTime(void) {
|
double airtaudio::Api::getStreamTime(void) {
|
||||||
verifyStream();
|
if (verifyStream() != airtaudio::errorNone) {
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
#if defined(HAVE_GETTIMEOFDAY)
|
#if defined(HAVE_GETTIMEOFDAY)
|
||||||
// Return a very accurate estimate of the stream time by
|
// Return a very accurate estimate of the stream time by
|
||||||
// adding in the elapsed time since the last tick.
|
// adding in the elapsed time since the last tick.
|
||||||
@ -199,49 +209,18 @@ double airtaudio::Api::getStreamTime(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint32_t airtaudio::Api::getStreamSampleRate(void) {
|
uint32_t airtaudio::Api::getStreamSampleRate(void) {
|
||||||
verifyStream();
|
if (verifyStream() != airtaudio::errorNone) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
return m_stream.sampleRate;
|
return m_stream.sampleRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
// *************************************************** //
|
enum airtaudio::errorType airtaudio::Api::verifyStream(void) {
|
||||||
//
|
|
||||||
// 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) {
|
|
||||||
if (m_stream.state == airtaudio::api::STREAM_CLOSED) {
|
if (m_stream.state == airtaudio::api::STREAM_CLOSED) {
|
||||||
m_errorText = "airtaudio::Api:: a stream is not open!";
|
ATA_ERROR("airtaudio::Api:: a stream is not open!");
|
||||||
error(airtaudio::errorInvalidUse);
|
return airtaudio::errorInvalidUse;
|
||||||
}
|
}
|
||||||
|
return airtaudio::errorNone;
|
||||||
}
|
}
|
||||||
|
|
||||||
void airtaudio::Api::clearStreamInfo(void) {
|
void airtaudio::Api::clearStreamInfo(void) {
|
||||||
@ -258,7 +237,6 @@ void airtaudio::Api::clearStreamInfo(void) {
|
|||||||
m_stream.callbackInfo.callback = 0;
|
m_stream.callbackInfo.callback = 0;
|
||||||
m_stream.callbackInfo.userData = 0;
|
m_stream.callbackInfo.userData = 0;
|
||||||
m_stream.callbackInfo.isRunning = false;
|
m_stream.callbackInfo.isRunning = false;
|
||||||
m_stream.callbackInfo.errorCallback = 0;
|
|
||||||
for (int32_t iii=0; iii<2; ++iii) {
|
for (int32_t iii=0; iii<2; ++iii) {
|
||||||
m_stream.device[iii] = 11111;
|
m_stream.device[iii] = 11111;
|
||||||
m_stream.doConvertBuffer[iii] = false;
|
m_stream.doConvertBuffer[iii] = false;
|
||||||
@ -294,8 +272,8 @@ uint32_t airtaudio::Api::formatBytes(airtaudio::format _format)
|
|||||||
} else if (_format == airtaudio::SINT8) {
|
} else if (_format == airtaudio::SINT8) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
m_errorText = "airtaudio::Api::formatBytes: undefined format.";
|
ATA_ERROR("airtaudio::Api::formatBytes: undefined format.");
|
||||||
error(airtaudio::errorWarning);
|
// TODO : airtaudio::errorWarning;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,8 +130,7 @@ namespace airtaudio {
|
|||||||
uint32_t *_bufferFrames,
|
uint32_t *_bufferFrames,
|
||||||
airtaudio::AirTAudioCallback _callback,
|
airtaudio::AirTAudioCallback _callback,
|
||||||
void *_userData,
|
void *_userData,
|
||||||
airtaudio::StreamOptions *_options,
|
airtaudio::StreamOptions *_options);
|
||||||
airtaudio::AirTAudioErrorCallback _errorCallback);
|
|
||||||
virtual enum airtaudio::errorType closeStream(void);
|
virtual enum airtaudio::errorType closeStream(void);
|
||||||
virtual enum airtaudio::errorType startStream(void) = 0;
|
virtual enum airtaudio::errorType startStream(void) = 0;
|
||||||
virtual enum airtaudio::errorType stopStream(void) = 0;
|
virtual enum airtaudio::errorType stopStream(void) = 0;
|
||||||
@ -145,14 +144,8 @@ namespace airtaudio {
|
|||||||
bool isStreamRunning(void) const {
|
bool isStreamRunning(void) const {
|
||||||
return m_stream.state == airtaudio::api::STREAM_RUNNING;
|
return m_stream.state == airtaudio::api::STREAM_RUNNING;
|
||||||
}
|
}
|
||||||
void showWarnings(bool _value) {
|
|
||||||
m_showWarnings = _value;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::ostringstream m_errorStream;
|
|
||||||
std::string m_errorText;
|
|
||||||
bool m_showWarnings;
|
|
||||||
airtaudio::api::Stream m_stream;
|
airtaudio::api::Stream m_stream;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -175,17 +168,13 @@ namespace airtaudio {
|
|||||||
void tickStreamTime(void);
|
void tickStreamTime(void);
|
||||||
|
|
||||||
//! Protected common method to clear an RtApiStream structure.
|
//! Protected common method to clear an RtApiStream structure.
|
||||||
void clearStreamInfo();
|
void clearStreamInfo(void);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Protected common method that throws an RtError (type =
|
Protected common method that throws an RtError (type =
|
||||||
INVALID_USE) if a stream is not open.
|
INVALID_USE) if a stream is not open.
|
||||||
*/
|
*/
|
||||||
void verifyStream(void);
|
enum airtaudio::errorType verifyStream(void);
|
||||||
|
|
||||||
//! Protected common error method to allow global control over error handling.
|
|
||||||
void error(airtaudio::errorType _type);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Protected method used to perform format, channel number, and/or interleaving
|
* @brief Protected method used to perform format, channel number, and/or interleaving
|
||||||
* conversions between the user and device buffers.
|
* conversions between the user and device buffers.
|
||||||
|
@ -21,7 +21,6 @@ namespace airtaudio {
|
|||||||
std::thread* thread;
|
std::thread* thread;
|
||||||
void* callback;
|
void* callback;
|
||||||
void* userData;
|
void* userData;
|
||||||
void* errorCallback;
|
|
||||||
void* apiInfo; // void pointer for API specific callback information
|
void* apiInfo; // void pointer for API specific callback information
|
||||||
bool isRunning;
|
bool isRunning;
|
||||||
bool doRealtime;
|
bool doRealtime;
|
||||||
@ -32,7 +31,6 @@ namespace airtaudio {
|
|||||||
object(0),
|
object(0),
|
||||||
callback(0),
|
callback(0),
|
||||||
userData(0),
|
userData(0),
|
||||||
errorCallback(0),
|
|
||||||
apiInfo(0),
|
apiInfo(0),
|
||||||
isRunning(false),
|
isRunning(false),
|
||||||
doRealtime(false) {
|
doRealtime(false) {
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <airtaudio/Interface.h>
|
#include <airtaudio/Interface.h>
|
||||||
|
#include <airtaudio/debug.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
std::vector<airtaudio::api::type> airtaudio::Interface::getCompiledApi(void) {
|
std::vector<airtaudio::api::type> airtaudio::Interface::getCompiledApi(void) {
|
||||||
@ -117,10 +118,9 @@ enum airtaudio::errorType airtaudio::Interface::openStream(
|
|||||||
uint32_t* _bufferFrames,
|
uint32_t* _bufferFrames,
|
||||||
airtaudio::AirTAudioCallback _callback,
|
airtaudio::AirTAudioCallback _callback,
|
||||||
void* _userData,
|
void* _userData,
|
||||||
airtaudio::StreamOptions* _options,
|
airtaudio::StreamOptions* _options) {
|
||||||
airtaudio::AirTAudioErrorCallback _errorCallback) {
|
|
||||||
if (m_rtapi == NULL) {
|
if (m_rtapi == NULL) {
|
||||||
return;
|
return airtaudio::errorInputNull;
|
||||||
}
|
}
|
||||||
return m_rtapi->openStream(_outputParameters,
|
return m_rtapi->openStream(_outputParameters,
|
||||||
_inputParameters,
|
_inputParameters,
|
||||||
@ -129,8 +129,7 @@ enum airtaudio::errorType airtaudio::Interface::openStream(
|
|||||||
_bufferFrames,
|
_bufferFrames,
|
||||||
_callback,
|
_callback,
|
||||||
_userData,
|
_userData,
|
||||||
_options,
|
_options);
|
||||||
_errorCallback);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -192,8 +192,7 @@ namespace airtaudio {
|
|||||||
uint32_t *_bufferFrames,
|
uint32_t *_bufferFrames,
|
||||||
airtaudio::AirTAudioCallback _callback,
|
airtaudio::AirTAudioCallback _callback,
|
||||||
void *_userData = NULL,
|
void *_userData = NULL,
|
||||||
airtaudio::StreamOptions *_options = NULL,
|
airtaudio::StreamOptions *_options = NULL);
|
||||||
airtaudio::AirTAudioErrorCallback _errorCallback = NULL);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A function that closes a stream and frees any associated stream memory.
|
* @brief A function that closes a stream and frees any associated stream memory.
|
||||||
@ -203,7 +202,7 @@ namespace airtaudio {
|
|||||||
*/
|
*/
|
||||||
enum airtaudio::errorType closeStream(void) {
|
enum airtaudio::errorType closeStream(void) {
|
||||||
if (m_rtapi == NULL) {
|
if (m_rtapi == NULL) {
|
||||||
return;
|
return airtaudio::errorInputNull;
|
||||||
}
|
}
|
||||||
return m_rtapi->closeStream();
|
return m_rtapi->closeStream();
|
||||||
}
|
}
|
||||||
@ -217,7 +216,7 @@ namespace airtaudio {
|
|||||||
*/
|
*/
|
||||||
enum airtaudio::errorType startStream(void) {
|
enum airtaudio::errorType startStream(void) {
|
||||||
if (m_rtapi == NULL) {
|
if (m_rtapi == NULL) {
|
||||||
return;
|
return airtaudio::errorInputNull;
|
||||||
}
|
}
|
||||||
return m_rtapi->startStream();
|
return m_rtapi->startStream();
|
||||||
}
|
}
|
||||||
@ -231,7 +230,7 @@ namespace airtaudio {
|
|||||||
*/
|
*/
|
||||||
enum airtaudio::errorType stopStream(void) {
|
enum airtaudio::errorType stopStream(void) {
|
||||||
if (m_rtapi == NULL) {
|
if (m_rtapi == NULL) {
|
||||||
return;
|
return airtaudio::errorInputNull;
|
||||||
}
|
}
|
||||||
return m_rtapi->stopStream();
|
return m_rtapi->stopStream();
|
||||||
}
|
}
|
||||||
@ -244,7 +243,7 @@ namespace airtaudio {
|
|||||||
*/
|
*/
|
||||||
enum airtaudio::errorType abortStream(void) {
|
enum airtaudio::errorType abortStream(void) {
|
||||||
if (m_rtapi == NULL) {
|
if (m_rtapi == NULL) {
|
||||||
return;
|
return airtaudio::errorInputNull;
|
||||||
}
|
}
|
||||||
return m_rtapi->abortStream();
|
return m_rtapi->abortStream();
|
||||||
}
|
}
|
||||||
@ -303,15 +302,6 @@ namespace airtaudio {
|
|||||||
}
|
}
|
||||||
return m_rtapi->getStreamSampleRate();
|
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:
|
protected:
|
||||||
void openRtApi(airtaudio::api::type _api);
|
void openRtApi(airtaudio::api::type _api);
|
||||||
};
|
};
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include <alsa/asoundlib.h>
|
#include <alsa/asoundlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <airtaudio/Interface.h>
|
#include <airtaudio/Interface.h>
|
||||||
|
#include <airtaudio/debug.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
|
||||||
airtaudio::Api* airtaudio::api::Alsa::Create(void) {
|
airtaudio::Api* airtaudio::api::Alsa::Create(void) {
|
||||||
@ -60,18 +61,16 @@ uint32_t airtaudio::api::Alsa::getDeviceCount(void) {
|
|||||||
sprintf(name, "hw:%d", card);
|
sprintf(name, "hw:%d", card);
|
||||||
result = snd_ctl_open(&handle, name, 0);
|
result = snd_ctl_open(&handle, name, 0);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
m_errorStream << "airtaudio::api::Alsa::getDeviceCount: control open, card = " << card << ", " << snd_strerror(result) << ".";
|
ATA_ERROR("airtaudio::api::Alsa::getDeviceCount: control open, card = " << card << ", " << snd_strerror(result) << ".");
|
||||||
m_errorText = m_errorStream.str();
|
// TODO : Return error airtaudio::errorWarning;
|
||||||
error(airtaudio::errorWarning);
|
|
||||||
goto nextcard;
|
goto nextcard;
|
||||||
}
|
}
|
||||||
subdevice = -1;
|
subdevice = -1;
|
||||||
while(1) {
|
while(1) {
|
||||||
result = snd_ctl_pcm_next_device(handle, &subdevice);
|
result = snd_ctl_pcm_next_device(handle, &subdevice);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
m_errorStream << "airtaudio::api::Alsa::getDeviceCount: control next device, card = " << card << ", " << snd_strerror(result) << ".";
|
ATA_ERROR("airtaudio::api::Alsa::getDeviceCount: control next device, card = " << card << ", " << snd_strerror(result) << ".");
|
||||||
m_errorText = m_errorStream.str();
|
// TODO : Return error airtaudio::errorWarning;
|
||||||
error(airtaudio::errorWarning);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (subdevice < 0) {
|
if (subdevice < 0) {
|
||||||
@ -79,7 +78,6 @@ uint32_t airtaudio::api::Alsa::getDeviceCount(void) {
|
|||||||
}
|
}
|
||||||
nDevices++;
|
nDevices++;
|
||||||
}
|
}
|
||||||
|
|
||||||
nextcard:
|
nextcard:
|
||||||
snd_ctl_close(handle);
|
snd_ctl_close(handle);
|
||||||
snd_card_next(&card);
|
snd_card_next(&card);
|
||||||
@ -106,18 +104,14 @@ airtaudio::DeviceInfo airtaudio::api::Alsa::getDeviceInfo(uint32_t _device) {
|
|||||||
sprintf(name, "hw:%d", card);
|
sprintf(name, "hw:%d", card);
|
||||||
result = snd_ctl_open(&chandle, name, SND_CTL_NONBLOCK);
|
result = snd_ctl_open(&chandle, name, SND_CTL_NONBLOCK);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
m_errorStream << "airtaudio::api::Alsa::getDeviceInfo: control open, card = " << card << ", " << snd_strerror(result) << ".";
|
ATA_WARNING("airtaudio::api::Alsa::getDeviceInfo: control open, card = " << card << ", " << snd_strerror(result) << ".");
|
||||||
m_errorText = m_errorStream.str();
|
|
||||||
error(airtaudio::errorWarning);
|
|
||||||
goto nextcard;
|
goto nextcard;
|
||||||
}
|
}
|
||||||
subdevice = -1;
|
subdevice = -1;
|
||||||
while(1) {
|
while(1) {
|
||||||
result = snd_ctl_pcm_next_device(chandle, &subdevice);
|
result = snd_ctl_pcm_next_device(chandle, &subdevice);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
m_errorStream << "airtaudio::api::Alsa::getDeviceInfo: control next device, card = " << card << ", " << snd_strerror(result) << ".";
|
ATA_WARNING("airtaudio::api::Alsa::getDeviceInfo: control next device, card = " << card << ", " << snd_strerror(result) << ".");
|
||||||
m_errorText = m_errorStream.str();
|
|
||||||
error(airtaudio::errorWarning);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (subdevice < 0) {
|
if (subdevice < 0) {
|
||||||
@ -142,13 +136,13 @@ airtaudio::DeviceInfo airtaudio::api::Alsa::getDeviceInfo(uint32_t _device) {
|
|||||||
nDevices++;
|
nDevices++;
|
||||||
}
|
}
|
||||||
if (nDevices == 0) {
|
if (nDevices == 0) {
|
||||||
m_errorText = "airtaudio::api::Alsa::getDeviceInfo: no devices found!";
|
ATA_ERROR("airtaudio::api::Alsa::getDeviceInfo: no devices found!");
|
||||||
error(airtaudio::errorInvalidUse);
|
// TODO : airtaudio::errorInvalidUse;
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
if (_device >= nDevices) {
|
if (_device >= nDevices) {
|
||||||
m_errorText = "airtaudio::api::Alsa::getDeviceInfo: device ID is invalid!";
|
ATA_ERROR("airtaudio::api::Alsa::getDeviceInfo: device ID is invalid!");
|
||||||
error(airtaudio::errorInvalidUse);
|
// TODO : airtaudio::errorInvalidUse;
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,8 +154,8 @@ foundDevice:
|
|||||||
|| m_stream.device[1] == _device)) {
|
|| m_stream.device[1] == _device)) {
|
||||||
snd_ctl_close(chandle);
|
snd_ctl_close(chandle);
|
||||||
if (_device >= m_devices.size()) {
|
if (_device >= m_devices.size()) {
|
||||||
m_errorText = "airtaudio::api::Alsa::getDeviceInfo: device ID was not present before stream was opened.";
|
ATA_ERROR("airtaudio::api::Alsa::getDeviceInfo: device ID was not present before stream was opened.");
|
||||||
error(airtaudio::errorWarning);
|
// TODO : return airtaudio::errorWarning;
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
return m_devices[ _device ];
|
return m_devices[ _device ];
|
||||||
@ -187,18 +181,16 @@ foundDevice:
|
|||||||
}
|
}
|
||||||
result = snd_pcm_open(&phandle, name, stream, openMode | SND_PCM_NONBLOCK);
|
result = snd_pcm_open(&phandle, name, stream, openMode | SND_PCM_NONBLOCK);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
m_errorStream << "airtaudio::api::Alsa::getDeviceInfo: snd_pcm_open error for device (" << name << "), " << snd_strerror(result) << ".";
|
ATA_ERROR("airtaudio::api::Alsa::getDeviceInfo: snd_pcm_open error for device (" << name << "), " << snd_strerror(result) << ".");
|
||||||
m_errorText = m_errorStream.str();
|
// TODO : Return airtaudio::errorWarning;
|
||||||
error(airtaudio::errorWarning);
|
|
||||||
goto captureProbe;
|
goto captureProbe;
|
||||||
}
|
}
|
||||||
// The device is open ... fill the parameter structure.
|
// The device is open ... fill the parameter structure.
|
||||||
result = snd_pcm_hw_params_any(phandle, params);
|
result = snd_pcm_hw_params_any(phandle, params);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
snd_pcm_close(phandle);
|
snd_pcm_close(phandle);
|
||||||
m_errorStream << "airtaudio::api::Alsa::getDeviceInfo: snd_pcm_hw_params error for device (" << name << "), " << snd_strerror(result) << ".";
|
ATA_ERROR("airtaudio::api::Alsa::getDeviceInfo: snd_pcm_hw_params error for device (" << name << "), " << snd_strerror(result) << ".");
|
||||||
m_errorText = m_errorStream.str();
|
// TODO : Return airtaudio::errorWarning;
|
||||||
error(airtaudio::errorWarning);
|
|
||||||
goto captureProbe;
|
goto captureProbe;
|
||||||
}
|
}
|
||||||
// Get output channel information.
|
// Get output channel information.
|
||||||
@ -206,9 +198,8 @@ foundDevice:
|
|||||||
result = snd_pcm_hw_params_get_channels_max(params, &value);
|
result = snd_pcm_hw_params_get_channels_max(params, &value);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
snd_pcm_close(phandle);
|
snd_pcm_close(phandle);
|
||||||
m_errorStream << "airtaudio::api::Alsa::getDeviceInfo: error getting device (" << name << ") output channels, " << snd_strerror(result) << ".";
|
ATA_ERROR("airtaudio::api::Alsa::getDeviceInfo: error getting device (" << name << ") output channels, " << snd_strerror(result) << ".");
|
||||||
m_errorText = m_errorStream.str();
|
// TODO : Return airtaudio::errorWarning;
|
||||||
error(airtaudio::errorWarning);
|
|
||||||
goto captureProbe;
|
goto captureProbe;
|
||||||
}
|
}
|
||||||
info.outputChannels = value;
|
info.outputChannels = value;
|
||||||
@ -231,9 +222,8 @@ captureProbe:
|
|||||||
}
|
}
|
||||||
result = snd_pcm_open(&phandle, name, stream, openMode | SND_PCM_NONBLOCK);
|
result = snd_pcm_open(&phandle, name, stream, openMode | SND_PCM_NONBLOCK);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
m_errorStream << "airtaudio::api::Alsa::getDeviceInfo: snd_pcm_open error for device (" << name << "), " << snd_strerror(result) << ".";
|
ATA_ERROR("airtaudio::api::Alsa::getDeviceInfo: snd_pcm_open error for device (" << name << "), " << snd_strerror(result) << ".");
|
||||||
m_errorText = m_errorStream.str();
|
// TODO : Return airtaudio::errorWarning;
|
||||||
error(airtaudio::errorWarning);
|
|
||||||
if (info.outputChannels == 0) {
|
if (info.outputChannels == 0) {
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
@ -243,9 +233,8 @@ captureProbe:
|
|||||||
result = snd_pcm_hw_params_any(phandle, params);
|
result = snd_pcm_hw_params_any(phandle, params);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
snd_pcm_close(phandle);
|
snd_pcm_close(phandle);
|
||||||
m_errorStream << "airtaudio::api::Alsa::getDeviceInfo: snd_pcm_hw_params error for device (" << name << "), " << snd_strerror(result) << ".";
|
ATA_ERROR("airtaudio::api::Alsa::getDeviceInfo: snd_pcm_hw_params error for device (" << name << "), " << snd_strerror(result) << ".");
|
||||||
m_errorText = m_errorStream.str();
|
// TODO : Return airtaudio::errorWarning;
|
||||||
error(airtaudio::errorWarning);
|
|
||||||
if (info.outputChannels == 0) {
|
if (info.outputChannels == 0) {
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
@ -254,9 +243,8 @@ captureProbe:
|
|||||||
result = snd_pcm_hw_params_get_channels_max(params, &value);
|
result = snd_pcm_hw_params_get_channels_max(params, &value);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
snd_pcm_close(phandle);
|
snd_pcm_close(phandle);
|
||||||
m_errorStream << "airtaudio::api::Alsa::getDeviceInfo: error getting device (" << name << ") input channels, " << snd_strerror(result) << ".";
|
ATA_ERROR("airtaudio::api::Alsa::getDeviceInfo: error getting device (" << name << ") input channels, " << snd_strerror(result) << ".");
|
||||||
m_errorText = m_errorStream.str();
|
// TODO : Return airtaudio::errorWarning;
|
||||||
error(airtaudio::errorWarning);
|
|
||||||
if (info.outputChannels == 0) {
|
if (info.outputChannels == 0) {
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
@ -290,18 +278,16 @@ probeParameters:
|
|||||||
snd_pcm_info_set_stream(pcminfo, stream);
|
snd_pcm_info_set_stream(pcminfo, stream);
|
||||||
result = snd_pcm_open(&phandle, name, stream, openMode | SND_PCM_NONBLOCK);
|
result = snd_pcm_open(&phandle, name, stream, openMode | SND_PCM_NONBLOCK);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
m_errorStream << "airtaudio::api::Alsa::getDeviceInfo: snd_pcm_open error for device (" << name << "), " << snd_strerror(result) << ".";
|
ATA_ERROR("airtaudio::api::Alsa::getDeviceInfo: snd_pcm_open error for device (" << name << "), " << snd_strerror(result) << ".");
|
||||||
m_errorText = m_errorStream.str();
|
// TODO : Return airtaudio::errorWarning;
|
||||||
error(airtaudio::errorWarning);
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
// The device is open ... fill the parameter structure.
|
// The device is open ... fill the parameter structure.
|
||||||
result = snd_pcm_hw_params_any(phandle, params);
|
result = snd_pcm_hw_params_any(phandle, params);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
snd_pcm_close(phandle);
|
snd_pcm_close(phandle);
|
||||||
m_errorStream << "airtaudio::api::Alsa::getDeviceInfo: snd_pcm_hw_params error for device (" << name << "), " << snd_strerror(result) << ".";
|
ATA_ERROR("airtaudio::api::Alsa::getDeviceInfo: snd_pcm_hw_params error for device (" << name << "), " << snd_strerror(result) << ".");
|
||||||
m_errorText = m_errorStream.str();
|
// TODO : Return airtaudio::errorWarning;
|
||||||
error(airtaudio::errorWarning);
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
// Test our discrete set of sample rate values.
|
// Test our discrete set of sample rate values.
|
||||||
@ -313,9 +299,8 @@ probeParameters:
|
|||||||
}
|
}
|
||||||
if (info.sampleRates.size() == 0) {
|
if (info.sampleRates.size() == 0) {
|
||||||
snd_pcm_close(phandle);
|
snd_pcm_close(phandle);
|
||||||
m_errorStream << "airtaudio::api::Alsa::getDeviceInfo: no supported sample rates found for device (" << name << ").";
|
ATA_ERROR("airtaudio::api::Alsa::getDeviceInfo: no supported sample rates found for device (" << name << ").");
|
||||||
m_errorText = m_errorStream.str();
|
// TODO : Return airtaudio::errorWarning;
|
||||||
error(airtaudio::errorWarning);
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
// Probe the supported data formats ... we don't care about endian-ness just yet
|
// 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
|
// Check that we have at least one supported format
|
||||||
if (info.nativeFormats == 0) {
|
if (info.nativeFormats == 0) {
|
||||||
m_errorStream << "airtaudio::api::Alsa::getDeviceInfo: pcm device (" << name << ") data format not supported by RtAudio.";
|
ATA_ERROR("airtaudio::api::Alsa::getDeviceInfo: pcm device (" << name << ") data format not supported by RtAudio.");
|
||||||
m_errorText = m_errorStream.str();
|
// TODO : Return airtaudio::errorWarning;
|
||||||
error(airtaudio::errorWarning);
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
// Get the device name
|
// Get the device name
|
||||||
@ -382,10 +366,6 @@ bool airtaudio::api::Alsa::probeDeviceOpen(uint32_t _device,
|
|||||||
airtaudio::format _format,
|
airtaudio::format _format,
|
||||||
uint32_t *_bufferSize,
|
uint32_t *_bufferSize,
|
||||||
airtaudio::StreamOptions *_options) {
|
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.
|
// I'm not using the "plug" interface ... too much inconsistent behavior.
|
||||||
unsigned nDevices = 0;
|
unsigned nDevices = 0;
|
||||||
int32_t result, subdevice, card;
|
int32_t result, subdevice, card;
|
||||||
@ -401,8 +381,7 @@ bool airtaudio::api::Alsa::probeDeviceOpen(uint32_t _device,
|
|||||||
sprintf(name, "hw:%d", card);
|
sprintf(name, "hw:%d", card);
|
||||||
result = snd_ctl_open(&chandle, name, SND_CTL_NONBLOCK);
|
result = snd_ctl_open(&chandle, name, SND_CTL_NONBLOCK);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
m_errorStream << "airtaudio::api::Alsa::probeDeviceOpen: control open, card = " << card << ", " << snd_strerror(result) << ".";
|
ATA_ERROR("airtaudio::api::Alsa::probeDeviceOpen: control open, card = " << card << ", " << snd_strerror(result) << ".");
|
||||||
m_errorText = m_errorStream.str();
|
|
||||||
return FAILURE;
|
return FAILURE;
|
||||||
}
|
}
|
||||||
subdevice = -1;
|
subdevice = -1;
|
||||||
@ -430,12 +409,12 @@ bool airtaudio::api::Alsa::probeDeviceOpen(uint32_t _device,
|
|||||||
}
|
}
|
||||||
if (nDevices == 0) {
|
if (nDevices == 0) {
|
||||||
// This should not happen because a check is made before this function is called.
|
// 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;
|
return FAILURE;
|
||||||
}
|
}
|
||||||
if (_device >= nDevices) {
|
if (_device >= nDevices) {
|
||||||
// This should not happen because a check is made before this function is called.
|
// 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;
|
return FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -461,11 +440,10 @@ foundDevice:
|
|||||||
result = snd_pcm_open(&phandle, name, stream, openMode);
|
result = snd_pcm_open(&phandle, name, stream, openMode);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
if (_mode == OUTPUT) {
|
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 {
|
} 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;
|
return FAILURE;
|
||||||
}
|
}
|
||||||
// Fill the parameter structure.
|
// Fill the parameter structure.
|
||||||
@ -474,14 +452,9 @@ foundDevice:
|
|||||||
result = snd_pcm_hw_params_any(phandle, hw_params);
|
result = snd_pcm_hw_params_any(phandle, hw_params);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
snd_pcm_close(phandle);
|
snd_pcm_close(phandle);
|
||||||
m_errorStream << "airtaudio::api::Alsa::probeDeviceOpen: error getting pcm device (" << name << ") parameters, " << snd_strerror(result) << ".";
|
ATA_ERROR("airtaudio::api::Alsa::probeDeviceOpen: error getting pcm device (" << name << ") parameters, " << snd_strerror(result) << ".");
|
||||||
m_errorText = m_errorStream.str();
|
|
||||||
return FAILURE;
|
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.
|
// Set access ... check user preference.
|
||||||
if ( _options != NULL
|
if ( _options != NULL
|
||||||
&& _options->flags & airtaudio::NONINTERLEAVED) {
|
&& _options->flags & airtaudio::NONINTERLEAVED) {
|
||||||
@ -505,8 +478,7 @@ foundDevice:
|
|||||||
}
|
}
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
snd_pcm_close(phandle);
|
snd_pcm_close(phandle);
|
||||||
m_errorStream << "airtaudio::api::Alsa::probeDeviceOpen: error setting pcm device (" << name << ") access, " << snd_strerror(result) << ".";
|
ATA_ERROR("airtaudio::api::Alsa::probeDeviceOpen: error setting pcm device (" << name << ") access, " << snd_strerror(result) << ".");
|
||||||
m_errorText = m_errorStream.str();
|
|
||||||
return FAILURE;
|
return FAILURE;
|
||||||
}
|
}
|
||||||
// Determine how to set the device format.
|
// Determine how to set the device format.
|
||||||
@ -562,16 +534,14 @@ foundDevice:
|
|||||||
}
|
}
|
||||||
// If we get here, no supported format was found.
|
// If we get here, no supported format was found.
|
||||||
snd_pcm_close(phandle);
|
snd_pcm_close(phandle);
|
||||||
m_errorStream << "airtaudio::api::Alsa::probeDeviceOpen: pcm device " << _device << " data format not supported by RtAudio.";
|
ATA_ERROR("airtaudio::api::Alsa::probeDeviceOpen: pcm device " << _device << " data format not supported by RtAudio.");
|
||||||
m_errorText = m_errorStream.str();
|
|
||||||
return FAILURE;
|
return FAILURE;
|
||||||
|
|
||||||
setFormat:
|
setFormat:
|
||||||
result = snd_pcm_hw_params_set_format(phandle, hw_params, deviceFormat);
|
result = snd_pcm_hw_params_set_format(phandle, hw_params, deviceFormat);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
snd_pcm_close(phandle);
|
snd_pcm_close(phandle);
|
||||||
m_errorStream << "airtaudio::api::Alsa::probeDeviceOpen: error setting pcm device (" << name << ") data format, " << snd_strerror(result) << ".";
|
ATA_ERROR("airtaudio::api::Alsa::probeDeviceOpen: error setting pcm device (" << name << ") data format, " << snd_strerror(result) << ".");
|
||||||
m_errorText = m_errorStream.str();
|
|
||||||
return FAILURE;
|
return FAILURE;
|
||||||
}
|
}
|
||||||
// Determine whether byte-swaping is necessary.
|
// Determine whether byte-swaping is necessary.
|
||||||
@ -582,8 +552,7 @@ setFormat:
|
|||||||
m_stream.doByteSwap[_mode] = true;
|
m_stream.doByteSwap[_mode] = true;
|
||||||
} else if (result < 0) {
|
} else if (result < 0) {
|
||||||
snd_pcm_close(phandle);
|
snd_pcm_close(phandle);
|
||||||
m_errorStream << "airtaudio::api::Alsa::probeDeviceOpen: error getting pcm device (" << name << ") endian-ness, " << snd_strerror(result) << ".";
|
ATA_ERROR("airtaudio::api::Alsa::probeDeviceOpen: error getting pcm device (" << name << ") endian-ness, " << snd_strerror(result) << ".");
|
||||||
m_errorText = m_errorStream.str();
|
|
||||||
return FAILURE;
|
return FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -591,8 +560,7 @@ setFormat:
|
|||||||
result = snd_pcm_hw_params_set_rate_near(phandle, hw_params, (uint32_t*) &_sampleRate, 0);
|
result = snd_pcm_hw_params_set_rate_near(phandle, hw_params, (uint32_t*) &_sampleRate, 0);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
snd_pcm_close(phandle);
|
snd_pcm_close(phandle);
|
||||||
m_errorStream << "airtaudio::api::Alsa::probeDeviceOpen: error setting sample rate on device (" << name << "), " << snd_strerror(result) << ".";
|
ATA_ERROR("airtaudio::api::Alsa::probeDeviceOpen: error setting sample rate on device (" << name << "), " << snd_strerror(result) << ".");
|
||||||
m_errorText = m_errorStream.str();
|
|
||||||
return FAILURE;
|
return FAILURE;
|
||||||
}
|
}
|
||||||
// Determine the number of channels for this device. We support a possible
|
// Determine the number of channels for this device. We support a possible
|
||||||
@ -604,15 +572,13 @@ setFormat:
|
|||||||
if ( result < 0
|
if ( result < 0
|
||||||
|| deviceChannels < _channels + _firstChannel) {
|
|| deviceChannels < _channels + _firstChannel) {
|
||||||
snd_pcm_close(phandle);
|
snd_pcm_close(phandle);
|
||||||
m_errorStream << "airtaudio::api::Alsa::probeDeviceOpen: requested channel parameters not supported by device (" << name << "), " << snd_strerror(result) << ".";
|
ATA_ERROR("airtaudio::api::Alsa::probeDeviceOpen: requested channel parameters not supported by device (" << name << "), " << snd_strerror(result) << ".");
|
||||||
m_errorText = m_errorStream.str();
|
|
||||||
return FAILURE;
|
return FAILURE;
|
||||||
}
|
}
|
||||||
result = snd_pcm_hw_params_get_channels_min(hw_params, &value);
|
result = snd_pcm_hw_params_get_channels_min(hw_params, &value);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
snd_pcm_close(phandle);
|
snd_pcm_close(phandle);
|
||||||
m_errorStream << "airtaudio::api::Alsa::probeDeviceOpen: error getting minimum channels for device (" << name << "), " << snd_strerror(result) << ".";
|
ATA_ERROR("airtaudio::api::Alsa::probeDeviceOpen: error getting minimum channels for device (" << name << "), " << snd_strerror(result) << ".");
|
||||||
m_errorText = m_errorStream.str();
|
|
||||||
return FAILURE;
|
return FAILURE;
|
||||||
}
|
}
|
||||||
deviceChannels = value;
|
deviceChannels = value;
|
||||||
@ -624,8 +590,7 @@ setFormat:
|
|||||||
result = snd_pcm_hw_params_set_channels(phandle, hw_params, deviceChannels);
|
result = snd_pcm_hw_params_set_channels(phandle, hw_params, deviceChannels);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
snd_pcm_close(phandle);
|
snd_pcm_close(phandle);
|
||||||
m_errorStream << "airtaudio::api::Alsa::probeDeviceOpen: error setting channels for device (" << name << "), " << snd_strerror(result) << ".";
|
ATA_ERROR("airtaudio::api::Alsa::probeDeviceOpen: error setting channels for device (" << name << "), " << snd_strerror(result) << ".");
|
||||||
m_errorText = m_errorStream.str();
|
|
||||||
return FAILURE;
|
return FAILURE;
|
||||||
}
|
}
|
||||||
// Set the buffer (or period) size.
|
// 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);
|
result = snd_pcm_hw_params_set_period_size_near(phandle, hw_params, &periodSize, &dir);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
snd_pcm_close(phandle);
|
snd_pcm_close(phandle);
|
||||||
m_errorStream << "airtaudio::api::Alsa::probeDeviceOpen: error setting period size for device (" << name << "), " << snd_strerror(result) << ".";
|
ATA_ERROR("airtaudio::api::Alsa::probeDeviceOpen: error setting period size for device (" << name << "), " << snd_strerror(result) << ".");
|
||||||
m_errorText = m_errorStream.str();
|
|
||||||
return FAILURE;
|
return FAILURE;
|
||||||
}
|
}
|
||||||
*_bufferSize = periodSize;
|
*_bufferSize = periodSize;
|
||||||
@ -647,16 +611,14 @@ setFormat:
|
|||||||
result = snd_pcm_hw_params_set_periods_near(phandle, hw_params, &periods, &dir);
|
result = snd_pcm_hw_params_set_periods_near(phandle, hw_params, &periods, &dir);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
snd_pcm_close(phandle);
|
snd_pcm_close(phandle);
|
||||||
m_errorStream << "airtaudio::api::Alsa::probeDeviceOpen: error setting periods for device (" << name << "), " << snd_strerror(result) << ".";
|
ATA_ERROR("airtaudio::api::Alsa::probeDeviceOpen: error setting periods for device (" << name << "), " << snd_strerror(result) << ".");
|
||||||
m_errorText = m_errorStream.str();
|
|
||||||
return FAILURE;
|
return FAILURE;
|
||||||
}
|
}
|
||||||
// If attempting to setup a duplex stream, the bufferSize parameter
|
// If attempting to setup a duplex stream, the bufferSize parameter
|
||||||
// MUST be the same in both directions!
|
// MUST be the same in both directions!
|
||||||
if (m_stream.mode == OUTPUT && _mode == INPUT && *_bufferSize != m_stream.bufferSize) {
|
if (m_stream.mode == OUTPUT && _mode == INPUT && *_bufferSize != m_stream.bufferSize) {
|
||||||
snd_pcm_close(phandle);
|
snd_pcm_close(phandle);
|
||||||
m_errorStream << "airtaudio::api::Alsa::probeDeviceOpen: system error setting buffer size for duplex stream on device (" << name << ").";
|
ATA_ERROR("airtaudio::api::Alsa::probeDeviceOpen: system error setting buffer size for duplex stream on device (" << name << ").");
|
||||||
m_errorText = m_errorStream.str();
|
|
||||||
return FAILURE;
|
return FAILURE;
|
||||||
}
|
}
|
||||||
m_stream.bufferSize = *_bufferSize;
|
m_stream.bufferSize = *_bufferSize;
|
||||||
@ -664,14 +626,9 @@ setFormat:
|
|||||||
result = snd_pcm_hw_params(phandle, hw_params);
|
result = snd_pcm_hw_params(phandle, hw_params);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
snd_pcm_close(phandle);
|
snd_pcm_close(phandle);
|
||||||
m_errorStream << "airtaudio::api::Alsa::probeDeviceOpen: error installing hardware configuration on device (" << name << "), " << snd_strerror(result) << ".";
|
ATA_ERROR("airtaudio::api::Alsa::probeDeviceOpen: error installing hardware configuration on device (" << name << "), " << snd_strerror(result) << ".");
|
||||||
m_errorText = m_errorStream.str();
|
|
||||||
return FAILURE;
|
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.
|
// 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_t *sw_params = NULL;
|
||||||
snd_pcm_sw_params_alloca(&sw_params);
|
snd_pcm_sw_params_alloca(&sw_params);
|
||||||
@ -690,14 +647,9 @@ setFormat:
|
|||||||
result = snd_pcm_sw_params(phandle, sw_params);
|
result = snd_pcm_sw_params(phandle, sw_params);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
snd_pcm_close(phandle);
|
snd_pcm_close(phandle);
|
||||||
m_errorStream << "airtaudio::api::Alsa::probeDeviceOpen: error installing software configuration on device (" << name << "), " << snd_strerror(result) << ".";
|
ATA_ERROR("airtaudio::api::Alsa::probeDeviceOpen: error installing software configuration on device (" << name << "), " << snd_strerror(result) << ".");
|
||||||
m_errorText = m_errorStream.str();
|
|
||||||
return FAILURE;
|
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
|
// Set flags for buffer conversion
|
||||||
m_stream.doConvertBuffer[_mode] = false;
|
m_stream.doConvertBuffer[_mode] = false;
|
||||||
if (m_stream.userFormat != m_stream.deviceFormat[_mode]) {
|
if (m_stream.userFormat != m_stream.deviceFormat[_mode]) {
|
||||||
@ -713,11 +665,9 @@ setFormat:
|
|||||||
// Allocate the ApiHandle if necessary and then save.
|
// Allocate the ApiHandle if necessary and then save.
|
||||||
AlsaHandle *apiInfo = 0;
|
AlsaHandle *apiInfo = 0;
|
||||||
if (m_stream.apiHandle == 0) {
|
if (m_stream.apiHandle == 0) {
|
||||||
try {
|
|
||||||
apiInfo = (AlsaHandle *) new AlsaHandle;
|
apiInfo = (AlsaHandle *) new AlsaHandle;
|
||||||
}
|
if (apiInfo == NULL) {
|
||||||
catch (std::bad_alloc&) {
|
ATA_ERROR("airtaudio::api::Alsa::probeDeviceOpen: error allocating AlsaHandle memory.");
|
||||||
m_errorText = "airtaudio::api::Alsa::probeDeviceOpen: error allocating AlsaHandle memory.";
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
m_stream.apiHandle = (void *) apiInfo;
|
m_stream.apiHandle = (void *) apiInfo;
|
||||||
@ -733,7 +683,7 @@ setFormat:
|
|||||||
bufferBytes = m_stream.nUserChannels[_mode] * *_bufferSize * formatBytes(m_stream.userFormat);
|
bufferBytes = m_stream.nUserChannels[_mode] * *_bufferSize * formatBytes(m_stream.userFormat);
|
||||||
m_stream.userBuffer[_mode] = (char *) calloc(bufferBytes, 1);
|
m_stream.userBuffer[_mode] = (char *) calloc(bufferBytes, 1);
|
||||||
if (m_stream.userBuffer[_mode] == NULL) {
|
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;
|
goto error;
|
||||||
}
|
}
|
||||||
if (m_stream.doConvertBuffer[_mode]) {
|
if (m_stream.doConvertBuffer[_mode]) {
|
||||||
@ -755,7 +705,7 @@ setFormat:
|
|||||||
}
|
}
|
||||||
m_stream.deviceBuffer = (char *) calloc(bufferBytes, 1);
|
m_stream.deviceBuffer = (char *) calloc(bufferBytes, 1);
|
||||||
if (m_stream.deviceBuffer == NULL) {
|
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;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -778,8 +728,8 @@ setFormat:
|
|||||||
if (snd_pcm_link(apiInfo->handles[0], apiInfo->handles[1]) == 0) {
|
if (snd_pcm_link(apiInfo->handles[0], apiInfo->handles[1]) == 0) {
|
||||||
apiInfo->synchronized = true;
|
apiInfo->synchronized = true;
|
||||||
} else {
|
} else {
|
||||||
m_errorText = "airtaudio::api::Alsa::probeDeviceOpen: unable to synchronize input and output devices.";
|
ATA_ERROR("airtaudio::api::Alsa::probeDeviceOpen: unable to synchronize input and output devices.");
|
||||||
error(airtaudio::errorWarning);
|
// TODO : airtaudio::errorWarning;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
m_stream.mode = _mode;
|
m_stream.mode = _mode;
|
||||||
@ -789,7 +739,7 @@ setFormat:
|
|||||||
m_stream.callbackInfo.thread = new std::thread(alsaCallbackHandler, &m_stream.callbackInfo);
|
m_stream.callbackInfo.thread = new std::thread(alsaCallbackHandler, &m_stream.callbackInfo);
|
||||||
if (m_stream.callbackInfo.thread == NULL) {
|
if (m_stream.callbackInfo.thread == NULL) {
|
||||||
m_stream.callbackInfo.isRunning = false;
|
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;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -825,9 +775,8 @@ error:
|
|||||||
|
|
||||||
enum airtaudio::errorType airtaudio::api::Alsa::closeStream(void) {
|
enum airtaudio::errorType airtaudio::api::Alsa::closeStream(void) {
|
||||||
if (m_stream.state == STREAM_CLOSED) {
|
if (m_stream.state == STREAM_CLOSED) {
|
||||||
m_errorText = "airtaudio::api::Alsa::closeStream(): no open stream to close!";
|
ATA_ERROR("airtaudio::api::Alsa::closeStream(): no open stream to close!");
|
||||||
error(airtaudio::errorWarning);
|
return airtaudio::errorWarning;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
AlsaHandle *apiInfo = (AlsaHandle *) m_stream.apiHandle;
|
AlsaHandle *apiInfo = (AlsaHandle *) m_stream.apiHandle;
|
||||||
m_stream.callbackInfo.isRunning = false;
|
m_stream.callbackInfo.isRunning = false;
|
||||||
@ -874,15 +823,17 @@ enum airtaudio::errorType airtaudio::api::Alsa::closeStream(void) {
|
|||||||
}
|
}
|
||||||
m_stream.mode = UNINITIALIZED;
|
m_stream.mode = UNINITIALIZED;
|
||||||
m_stream.state = STREAM_CLOSED;
|
m_stream.state = STREAM_CLOSED;
|
||||||
|
return airtaudio::errorNone;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum airtaudio::errorType airtaudio::api::Alsa::startStream(void) {
|
enum airtaudio::errorType airtaudio::api::Alsa::startStream(void) {
|
||||||
// This method calls snd_pcm_prepare if the device isn't already in that state.
|
// 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) {
|
if (m_stream.state == STREAM_RUNNING) {
|
||||||
m_errorText = "airtaudio::api::Alsa::startStream(): the stream is already running!";
|
ATA_ERROR("airtaudio::api::Alsa::startStream(): the stream is already running!");
|
||||||
error(airtaudio::errorWarning);
|
return airtaudio::errorWarning;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
std::unique_lock<std::mutex> lck(m_stream.mutex);
|
std::unique_lock<std::mutex> lck(m_stream.mutex);
|
||||||
int32_t result = 0;
|
int32_t result = 0;
|
||||||
@ -894,8 +845,7 @@ enum airtaudio::errorType airtaudio::api::Alsa::startStream(void) {
|
|||||||
if (state != SND_PCM_STATE_PREPARED) {
|
if (state != SND_PCM_STATE_PREPARED) {
|
||||||
result = snd_pcm_prepare(handle[0]);
|
result = snd_pcm_prepare(handle[0]);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
m_errorStream << "airtaudio::api::Alsa::startStream: error preparing output pcm device, " << snd_strerror(result) << ".";
|
ATA_ERROR("airtaudio::api::Alsa::startStream: error preparing output pcm device, " << snd_strerror(result) << ".");
|
||||||
m_errorText = m_errorStream.str();
|
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -907,8 +857,7 @@ enum airtaudio::errorType airtaudio::api::Alsa::startStream(void) {
|
|||||||
if (state != SND_PCM_STATE_PREPARED) {
|
if (state != SND_PCM_STATE_PREPARED) {
|
||||||
result = snd_pcm_prepare(handle[1]);
|
result = snd_pcm_prepare(handle[1]);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
m_errorStream << "airtaudio::api::Alsa::startStream: error preparing input pcm device, " << snd_strerror(result) << ".";
|
ATA_ERROR("airtaudio::api::Alsa::startStream: error preparing input pcm device, " << snd_strerror(result) << ".");
|
||||||
m_errorText = m_errorStream.str();
|
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -918,17 +867,18 @@ unlock:
|
|||||||
apiInfo->runnable = true;
|
apiInfo->runnable = true;
|
||||||
apiInfo->runnable_cv.notify_one();
|
apiInfo->runnable_cv.notify_one();
|
||||||
if (result >= 0) {
|
if (result >= 0) {
|
||||||
return;
|
return airtaudio::errorNone;
|
||||||
}
|
}
|
||||||
error(airtaudio::errorSystemError);
|
return airtaudio::errorSystemError;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum airtaudio::errorType airtaudio::api::Alsa::stopStream(void) {
|
enum airtaudio::errorType airtaudio::api::Alsa::stopStream(void) {
|
||||||
verifyStream();
|
if (verifyStream() != airtaudio::errorNone) {
|
||||||
|
return airtaudio::errorFail;
|
||||||
|
}
|
||||||
if (m_stream.state == STREAM_STOPPED) {
|
if (m_stream.state == STREAM_STOPPED) {
|
||||||
m_errorText = "airtaudio::api::Alsa::stopStream(): the stream is already stopped!";
|
ATA_ERROR("airtaudio::api::Alsa::stopStream(): the stream is already stopped!");
|
||||||
error(airtaudio::errorWarning);
|
return airtaudio::errorWarning;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
m_stream.state = STREAM_STOPPED;
|
m_stream.state = STREAM_STOPPED;
|
||||||
std::unique_lock<std::mutex> lck(m_stream.mutex);
|
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]);
|
result = snd_pcm_drain(handle[0]);
|
||||||
}
|
}
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
m_errorStream << "airtaudio::api::Alsa::stopStream: error draining output pcm device, " << snd_strerror(result) << ".";
|
ATA_ERROR("airtaudio::api::Alsa::stopStream: error draining output pcm device, " << snd_strerror(result) << ".");
|
||||||
m_errorText = m_errorStream.str();
|
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -953,24 +902,24 @@ enum airtaudio::errorType airtaudio::api::Alsa::stopStream(void) {
|
|||||||
&& !apiInfo->synchronized) {
|
&& !apiInfo->synchronized) {
|
||||||
result = snd_pcm_drop(handle[1]);
|
result = snd_pcm_drop(handle[1]);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
m_errorStream << "airtaudio::api::Alsa::stopStream: error stopping input pcm device, " << snd_strerror(result) << ".";
|
ATA_ERROR("airtaudio::api::Alsa::stopStream: error stopping input pcm device, " << snd_strerror(result) << ".");
|
||||||
m_errorText = m_errorStream.str();
|
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unlock:
|
unlock:
|
||||||
if (result >= 0) {
|
if (result >= 0) {
|
||||||
return;
|
return airtaudio::errorNone;
|
||||||
}
|
}
|
||||||
error(airtaudio::errorSystemError);
|
return airtaudio::errorSystemError;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum airtaudio::errorType airtaudio::api::Alsa::abortStream(void) {
|
enum airtaudio::errorType airtaudio::api::Alsa::abortStream(void) {
|
||||||
verifyStream();
|
if (verifyStream() != airtaudio::errorNone) {
|
||||||
|
return airtaudio::errorFail;
|
||||||
|
}
|
||||||
if (m_stream.state == STREAM_STOPPED) {
|
if (m_stream.state == STREAM_STOPPED) {
|
||||||
m_errorText = "airtaudio::api::Alsa::abortStream(): the stream is already stopped!";
|
ATA_ERROR("airtaudio::api::Alsa::abortStream(): the stream is already stopped!");
|
||||||
error(airtaudio::errorWarning);
|
return airtaudio::errorWarning;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
m_stream.state = STREAM_STOPPED;
|
m_stream.state = STREAM_STOPPED;
|
||||||
std::unique_lock<std::mutex> lck(m_stream.mutex);
|
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) {
|
|| m_stream.mode == DUPLEX) {
|
||||||
result = snd_pcm_drop(handle[0]);
|
result = snd_pcm_drop(handle[0]);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
m_errorStream << "airtaudio::api::Alsa::abortStream: error aborting output pcm device, " << snd_strerror(result) << ".";
|
ATA_ERROR("airtaudio::api::Alsa::abortStream: error aborting output pcm device, " << snd_strerror(result) << ".");
|
||||||
m_errorText = m_errorStream.str();
|
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -991,16 +939,15 @@ enum airtaudio::errorType airtaudio::api::Alsa::abortStream(void) {
|
|||||||
&& !apiInfo->synchronized) {
|
&& !apiInfo->synchronized) {
|
||||||
result = snd_pcm_drop(handle[1]);
|
result = snd_pcm_drop(handle[1]);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
m_errorStream << "airtaudio::api::Alsa::abortStream: error aborting input pcm device, " << snd_strerror(result) << ".";
|
ATA_ERROR("airtaudio::api::Alsa::abortStream: error aborting input pcm device, " << snd_strerror(result) << ".");
|
||||||
m_errorText = m_errorStream.str();
|
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unlock:
|
unlock:
|
||||||
if (result >= 0) {
|
if (result >= 0) {
|
||||||
return;
|
return airtaudio::errorNone;
|
||||||
}
|
}
|
||||||
error(airtaudio::errorSystemError);
|
return airtaudio::errorSystemError;
|
||||||
}
|
}
|
||||||
|
|
||||||
void airtaudio::api::Alsa::callbackEvent(void) {
|
void airtaudio::api::Alsa::callbackEvent(void) {
|
||||||
@ -1018,9 +965,8 @@ void airtaudio::api::Alsa::callbackEvent(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (m_stream.state == STREAM_CLOSED) {
|
if (m_stream.state == STREAM_CLOSED) {
|
||||||
m_errorText = "airtaudio::api::Alsa::callbackEvent(): the stream is closed ... this shouldn't happen!";
|
ATA_CRITICAL("airtaudio::api::Alsa::callbackEvent(): the stream is closed ... this shouldn't happen!");
|
||||||
error(airtaudio::errorWarning);
|
return; // TODO : notify appl: airtaudio::errorWarning;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
int32_t doStopStream = 0;
|
int32_t doStopStream = 0;
|
||||||
airtaudio::AirTAudioCallback callback = (airtaudio::AirTAudioCallback) m_stream.callbackInfo.callback;
|
airtaudio::AirTAudioCallback callback = (airtaudio::AirTAudioCallback) m_stream.callbackInfo.callback;
|
||||||
@ -1086,18 +1032,15 @@ void airtaudio::api::Alsa::callbackEvent(void) {
|
|||||||
apiInfo->xrun[1] = true;
|
apiInfo->xrun[1] = true;
|
||||||
result = snd_pcm_prepare(handle[1]);
|
result = snd_pcm_prepare(handle[1]);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
m_errorStream << "airtaudio::api::Alsa::callbackEvent: error preparing device after overrun, " << snd_strerror(result) << ".";
|
ATA_ERROR("airtaudio::api::Alsa::callbackEvent: error preparing device after overrun, " << snd_strerror(result) << ".");
|
||||||
m_errorText = m_errorStream.str();
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
m_errorStream << "airtaudio::api::Alsa::callbackEvent: error, current state is " << snd_pcm_state_name(state) << ", " << snd_strerror(result) << ".";
|
ATA_ERROR("airtaudio::api::Alsa::callbackEvent: error, current state is " << snd_pcm_state_name(state) << ", " << snd_strerror(result) << ".");
|
||||||
m_errorText = m_errorStream.str();
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
m_errorStream << "airtaudio::api::Alsa::callbackEvent: audio read error, " << snd_strerror(result) << ".";
|
ATA_ERROR("airtaudio::api::Alsa::callbackEvent: audio read error, " << snd_strerror(result) << ".");
|
||||||
m_errorText = m_errorStream.str();
|
|
||||||
}
|
}
|
||||||
error(airtaudio::errorWarning);
|
// TODO : Notify application ... airtaudio::errorWarning;
|
||||||
goto tryOutput;
|
goto tryOutput;
|
||||||
}
|
}
|
||||||
// Do byte swapping if necessary.
|
// Do byte swapping if necessary.
|
||||||
@ -1110,7 +1053,9 @@ void airtaudio::api::Alsa::callbackEvent(void) {
|
|||||||
}
|
}
|
||||||
// Check stream latency
|
// Check stream latency
|
||||||
result = snd_pcm_delay(handle[1], &frames);
|
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:
|
tryOutput:
|
||||||
@ -1150,23 +1095,22 @@ tryOutput:
|
|||||||
apiInfo->xrun[0] = true;
|
apiInfo->xrun[0] = true;
|
||||||
result = snd_pcm_prepare(handle[0]);
|
result = snd_pcm_prepare(handle[0]);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
m_errorStream << "airtaudio::api::Alsa::callbackEvent: error preparing device after underrun, " << snd_strerror(result) << ".";
|
ATA_ERROR("airtaudio::api::Alsa::callbackEvent: error preparing device after underrun, " << snd_strerror(result) << ".");
|
||||||
m_errorText = m_errorStream.str();
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
m_errorStream << "airtaudio::api::Alsa::callbackEvent: error, current state is " << snd_pcm_state_name(state) << ", " << snd_strerror(result) << ".";
|
ATA_ERROR("airtaudio::api::Alsa::callbackEvent: error, current state is " << snd_pcm_state_name(state) << ", " << snd_strerror(result) << ".");
|
||||||
m_errorText = m_errorStream.str();
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
m_errorStream << "airtaudio::api::Alsa::callbackEvent: audio write error, " << snd_strerror(result) << ".";
|
ATA_ERROR("airtaudio::api::Alsa::callbackEvent: audio write error, " << snd_strerror(result) << ".");
|
||||||
m_errorText = m_errorStream.str();
|
|
||||||
}
|
}
|
||||||
error(airtaudio::errorWarning);
|
// TODO : Notuify application airtaudio::errorWarning;
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
// Check stream latency
|
// Check stream latency
|
||||||
result = snd_pcm_delay(handle[0], &frames);
|
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:
|
unlock:
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#if defined(__WINDOWS_ASIO__) // ASIO API on Windows
|
#if defined(__WINDOWS_ASIO__) // ASIO API on Windows
|
||||||
|
|
||||||
#include <airtaudio/Interface.h>
|
#include <airtaudio/Interface.h>
|
||||||
|
#include <airtaudio/debug.h>
|
||||||
|
|
||||||
airtaudio::Api* airtaudio::api::Asio::Create(void) {
|
airtaudio::Api* airtaudio::api::Asio::Create(void) {
|
||||||
return new airtaudio::api::Asio();
|
return new airtaudio::api::Asio();
|
||||||
@ -183,15 +184,15 @@ rtaudio::DeviceInfo airtaudio::api::Asio::getDeviceInfo(uint32_t device)
|
|||||||
|
|
||||||
info.nativeFormats = 0;
|
info.nativeFormats = 0;
|
||||||
if (channelInfo.type == ASIOSTInt16MSB || channelInfo.type == ASIOSTInt16LSB)
|
if (channelInfo.type == ASIOSTInt16MSB || channelInfo.type == ASIOSTInt16LSB)
|
||||||
info.nativeFormats |= RTAUDIO_SINT16;
|
info.nativeFormats |= SINT16;
|
||||||
else if (channelInfo.type == ASIOSTInt32MSB || channelInfo.type == ASIOSTInt32LSB)
|
else if (channelInfo.type == ASIOSTInt32MSB || channelInfo.type == ASIOSTInt32LSB)
|
||||||
info.nativeFormats |= RTAUDIO_SINT32;
|
info.nativeFormats |= SINT32;
|
||||||
else if (channelInfo.type == ASIOSTFloat32MSB || channelInfo.type == ASIOSTFloat32LSB)
|
else if (channelInfo.type == ASIOSTFloat32MSB || channelInfo.type == ASIOSTFloat32LSB)
|
||||||
info.nativeFormats |= RTAUDIO_FLOAT32;
|
info.nativeFormats |= FLOAT32;
|
||||||
else if (channelInfo.type == ASIOSTFloat64MSB || channelInfo.type == ASIOSTFloat64LSB)
|
else if (channelInfo.type == ASIOSTFloat64MSB || channelInfo.type == ASIOSTFloat64LSB)
|
||||||
info.nativeFormats |= RTAUDIO_FLOAT64;
|
info.nativeFormats |= FLOAT64;
|
||||||
else if (channelInfo.type == ASIOSTInt24MSB || channelInfo.type == ASIOSTInt24LSB)
|
else if (channelInfo.type == ASIOSTInt24MSB || channelInfo.type == ASIOSTInt24LSB)
|
||||||
info.nativeFormats |= RTAUDIO_SINT24;
|
info.nativeFormats |= SINT24;
|
||||||
|
|
||||||
if (info.outputChannels > 0)
|
if (info.outputChannels > 0)
|
||||||
if (getDefaultOutputDevice() == device) info.isDefaultOutput = true;
|
if (getDefaultOutputDevice() == device) info.isDefaultOutput = true;
|
||||||
@ -579,7 +580,7 @@ bool airtaudio::api::Asio::probeDeviceOpen(uint32_t device, StreamMode mode, uin
|
|||||||
return FAILURE;
|
return FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void airtaudio::api::Asio::closeStream()
|
enum airtaudio::errorType airtaudio::api::Asio::closeStream()
|
||||||
{
|
{
|
||||||
if (m_stream.state == STREAM_CLOSED) {
|
if (m_stream.state == STREAM_CLOSED) {
|
||||||
m_errorText = "airtaudio::api::Asio::closeStream(): no open stream to close!";
|
m_errorText = "airtaudio::api::Asio::closeStream(): no open stream to close!";
|
||||||
@ -621,9 +622,11 @@ void airtaudio::api::Asio::closeStream()
|
|||||||
|
|
||||||
bool stopThreadCalled = false;
|
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) {
|
if (m_stream.state == STREAM_RUNNING) {
|
||||||
m_errorText = "airtaudio::api::Asio::startStream(): the stream is already running!";
|
m_errorText = "airtaudio::api::Asio::startStream(): the stream is already running!";
|
||||||
error(airtaudio::errorWarning);
|
error(airtaudio::errorWarning);
|
||||||
@ -651,9 +654,11 @@ void airtaudio::api::Asio::startStream()
|
|||||||
error(airtaudio::errorSystemError);
|
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) {
|
if (m_stream.state == STREAM_STOPPED) {
|
||||||
m_errorText = "airtaudio::api::Asio::stopStream(): the stream is already stopped!";
|
m_errorText = "airtaudio::api::Asio::stopStream(): the stream is already stopped!";
|
||||||
error(airtaudio::errorWarning);
|
error(airtaudio::errorWarning);
|
||||||
@ -680,9 +685,11 @@ void airtaudio::api::Asio::stopStream()
|
|||||||
error(airtaudio::errorSystemError);
|
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) {
|
if (m_stream.state == STREAM_STOPPED) {
|
||||||
m_errorText = "airtaudio::api::Asio::abortStream(): the stream is already stopped!";
|
m_errorText = "airtaudio::api::Asio::abortStream(): the stream is already stopped!";
|
||||||
error(airtaudio::errorWarning);
|
error(airtaudio::errorWarning);
|
||||||
|
@ -22,10 +22,10 @@ namespace airtaudio {
|
|||||||
}
|
}
|
||||||
uint32_t getDeviceCount(void);
|
uint32_t getDeviceCount(void);
|
||||||
airtaudio::DeviceInfo getDeviceInfo(uint32_t _device);
|
airtaudio::DeviceInfo getDeviceInfo(uint32_t _device);
|
||||||
void closeStream(void);
|
enum airtaudio::errorType closeStream(void);
|
||||||
void startStream(void);
|
enum airtaudio::errorType startStream(void);
|
||||||
void stopStream(void);
|
enum airtaudio::errorType stopStream(void);
|
||||||
void abortStream(void);
|
enum airtaudio::errorType abortStream(void);
|
||||||
long getStreamLatency(void);
|
long getStreamLatency(void);
|
||||||
// This function is intended for internal use only. It must be
|
// This function is intended for internal use only. It must be
|
||||||
// public because it is called by the internal callback handler,
|
// public because it is called by the internal callback handler,
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -26,10 +26,10 @@ namespace airtaudio {
|
|||||||
airtaudio::DeviceInfo getDeviceInfo(uint32_t _device);
|
airtaudio::DeviceInfo getDeviceInfo(uint32_t _device);
|
||||||
uint32_t getDefaultOutputDevice(void);
|
uint32_t getDefaultOutputDevice(void);
|
||||||
uint32_t getDefaultInputDevice(void);
|
uint32_t getDefaultInputDevice(void);
|
||||||
void closeStream(void);
|
enum airtaudio::errorType closeStream(void);
|
||||||
void startStream(void);
|
enum airtaudio::errorType startStream(void);
|
||||||
void stopStream(void);
|
enum airtaudio::errorType stopStream(void);
|
||||||
void abortStream(void);
|
enum airtaudio::errorType abortStream(void);
|
||||||
long getStreamLatency(void);
|
long getStreamLatency(void);
|
||||||
// This function is intended for internal use only. It must be
|
// This function is intended for internal use only. It must be
|
||||||
// public because it is called by the internal callback handler,
|
// public because it is called by the internal callback handler,
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
// Windows DirectSound API
|
// Windows DirectSound API
|
||||||
#if defined(__WINDOWS_DS__)
|
#if defined(__WINDOWS_DS__)
|
||||||
#include <airtaudio/Interface.h>
|
#include <airtaudio/Interface.h>
|
||||||
|
#include <airtaudio/debug.h>
|
||||||
|
|
||||||
airtaudio::Api* airtaudio::api::Ds::Create(void) {
|
airtaudio::Api* airtaudio::api::Ds::Create(void) {
|
||||||
return new airtaudio::api::Ds();
|
return new airtaudio::api::Ds();
|
||||||
@ -843,7 +844,7 @@ bool airtaudio::api::Ds::probeDeviceOpen(uint32_t device, StreamMode mode, uint3
|
|||||||
return FAILURE;
|
return FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void airtaudio::api::Ds::closeStream()
|
enum airtaudio::errorType airtaudio::api::Ds::closeStream()
|
||||||
{
|
{
|
||||||
if (m_stream.state == STREAM_CLOSED) {
|
if (m_stream.state == STREAM_CLOSED) {
|
||||||
m_errorText = "airtaudio::api::Ds::closeStream(): no open stream to close!";
|
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;
|
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) {
|
if (m_stream.state == STREAM_RUNNING) {
|
||||||
m_errorText = "airtaudio::api::Ds::startStream(): the stream is already running!";
|
m_errorText = "airtaudio::api::Ds::startStream(): the stream is already running!";
|
||||||
error(airtaudio::errorWarning);
|
error(airtaudio::errorWarning);
|
||||||
@ -953,9 +956,11 @@ void airtaudio::api::Ds::startStream()
|
|||||||
if (FAILED(result)) error(airtaudio::errorSystemError);
|
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) {
|
if (m_stream.state == STREAM_STOPPED) {
|
||||||
m_errorText = "airtaudio::api::Ds::stopStream(): the stream is already stopped!";
|
m_errorText = "airtaudio::api::Ds::stopStream(): the stream is already stopped!";
|
||||||
error(airtaudio::errorWarning);
|
error(airtaudio::errorWarning);
|
||||||
@ -1050,9 +1055,11 @@ void airtaudio::api::Ds::stopStream()
|
|||||||
if (FAILED(result)) error(airtaudio::errorSystemError);
|
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) {
|
if (m_stream.state == STREAM_STOPPED) {
|
||||||
m_errorText = "airtaudio::api::Ds::abortStream(): the stream is already stopped!";
|
m_errorText = "airtaudio::api::Ds::abortStream(): the stream is already stopped!";
|
||||||
error(airtaudio::errorWarning);
|
error(airtaudio::errorWarning);
|
||||||
@ -1572,55 +1579,39 @@ static BOOL CALLBACK deviceQueryCallback(LPGUID lpguid,
|
|||||||
static const char* getErrorString(int32_t code)
|
static const char* getErrorString(int32_t code)
|
||||||
{
|
{
|
||||||
switch (code) {
|
switch (code) {
|
||||||
|
|
||||||
case DSERR_ALLOCATED:
|
case DSERR_ALLOCATED:
|
||||||
return "Already allocated";
|
return "Already allocated";
|
||||||
|
|
||||||
case DSERR_CONTROLUNAVAIL:
|
case DSERR_CONTROLUNAVAIL:
|
||||||
return "Control unavailable";
|
return "Control unavailable";
|
||||||
|
|
||||||
case DSERR_INVALIDPARAM:
|
case DSERR_INVALIDPARAM:
|
||||||
return "Invalid parameter";
|
return "Invalid parameter";
|
||||||
|
|
||||||
case DSERR_INVALIDCALL:
|
case DSERR_INVALIDCALL:
|
||||||
return "Invalid call";
|
return "Invalid call";
|
||||||
|
|
||||||
case DSERR_GENERIC:
|
case DSERR_GENERIC:
|
||||||
return "Generic error";
|
return "Generic error";
|
||||||
|
|
||||||
case DSERR_PRIOLEVELNEEDED:
|
case DSERR_PRIOLEVELNEEDED:
|
||||||
return "Priority level needed";
|
return "Priority level needed";
|
||||||
|
|
||||||
case DSERR_OUTOFMEMORY:
|
case DSERR_OUTOFMEMORY:
|
||||||
return "Out of memory";
|
return "Out of memory";
|
||||||
|
|
||||||
case DSERR_BADFORMAT:
|
case DSERR_BADFORMAT:
|
||||||
return "The sample rate or the channel format is not supported";
|
return "The sample rate or the channel format is not supported";
|
||||||
|
|
||||||
case DSERR_UNSUPPORTED:
|
case DSERR_UNSUPPORTED:
|
||||||
return "Not supported";
|
return "Not supported";
|
||||||
|
|
||||||
case DSERR_NODRIVER:
|
case DSERR_NODRIVER:
|
||||||
return "No driver";
|
return "No driver";
|
||||||
|
|
||||||
case DSERR_ALREADYINITIALIZED:
|
case DSERR_ALREADYINITIALIZED:
|
||||||
return "Already initialized";
|
return "Already initialized";
|
||||||
|
|
||||||
case DSERR_NOAGGREGATION:
|
case DSERR_NOAGGREGATION:
|
||||||
return "No aggregation";
|
return "No aggregation";
|
||||||
|
|
||||||
case DSERR_BUFFERLOST:
|
case DSERR_BUFFERLOST:
|
||||||
return "Buffer lost";
|
return "Buffer lost";
|
||||||
|
|
||||||
case DSERR_OTHERAPPHASPRIO:
|
case DSERR_OTHERAPPHASPRIO:
|
||||||
return "Another application already has priority";
|
return "Another application already has priority";
|
||||||
|
|
||||||
case DSERR_UNINITIALIZED:
|
case DSERR_UNINITIALIZED:
|
||||||
return "Uninitialized";
|
return "Uninitialized";
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return "DirectSound unknown error";
|
return "DirectSound unknown error";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//******************** End of __WINDOWS_DS__ *********************//
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -24,10 +24,10 @@ namespace airtaudio {
|
|||||||
uint32_t getDefaultOutputDevice(void);
|
uint32_t getDefaultOutputDevice(void);
|
||||||
uint32_t getDefaultInputDevice(void);
|
uint32_t getDefaultInputDevice(void);
|
||||||
airtaudio::DeviceInfo getDeviceInfo(uint32_t _device);
|
airtaudio::DeviceInfo getDeviceInfo(uint32_t _device);
|
||||||
void closeStream(void);
|
enum airtaudio::errorType closeStream(void);
|
||||||
void startStream(void);
|
enum airtaudio::errorType startStream(void);
|
||||||
void stopStream(void);
|
enum airtaudio::errorType stopStream(void);
|
||||||
void abortStream(void);
|
enum airtaudio::errorType abortStream(void);
|
||||||
long getStreamLatency(void);
|
long getStreamLatency(void);
|
||||||
// This function is intended for internal use only. It must be
|
// This function is intended for internal use only. It must be
|
||||||
// public because it is called by the internal callback handler,
|
// public because it is called by the internal callback handler,
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#if defined(__AIRTAUDIO_DUMMY__)
|
#if defined(__AIRTAUDIO_DUMMY__)
|
||||||
|
#include <airtaudio/api/Dummy.h>
|
||||||
|
#include <airtaudio/debug.h>
|
||||||
|
|
||||||
airtaudio::Api* airtaudio::api::Dummy::Create(void) {
|
airtaudio::Api* airtaudio::api::Dummy::Create(void) {
|
||||||
return new airtaudio::api::Dummy();
|
return new airtaudio::api::Dummy();
|
||||||
@ -28,20 +30,20 @@ rtaudio::DeviceInfo airtaudio::api::Dummy::getDeviceInfo(uint32_t _device) {
|
|||||||
return info;
|
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,
|
bool airtaudio::api::Dummy::probeDeviceOpen(uint32_t _device,
|
||||||
|
@ -23,10 +23,10 @@ namespace airtaudio {
|
|||||||
}
|
}
|
||||||
uint32_t getDeviceCount(void);
|
uint32_t getDeviceCount(void);
|
||||||
airtaudio::DeviceInfo getDeviceInfo(uint32_t _device);
|
airtaudio::DeviceInfo getDeviceInfo(uint32_t _device);
|
||||||
void closeStream(void);
|
enum airtaudio::errorType closeStream(void);
|
||||||
void startStream(void);
|
enum airtaudio::errorType startStream(void);
|
||||||
void stopStream(void);
|
enum airtaudio::errorType stopStream(void);
|
||||||
void abortStream(void);
|
enum airtaudio::errorType abortStream(void);
|
||||||
private:
|
private:
|
||||||
bool probeDeviceOpen(uint32_t _device,
|
bool probeDeviceOpen(uint32_t _device,
|
||||||
airtaudio::api::StreamMode _mode,
|
airtaudio::api::StreamMode _mode,
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <airtaudio/Interface.h>
|
#include <airtaudio/Interface.h>
|
||||||
|
#include <airtaudio/debug.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
airtaudio::Api* airtaudio::api::Jack::Create(void) {
|
airtaudio::Api* airtaudio::api::Jack::Create(void) {
|
||||||
@ -74,14 +75,8 @@ struct JackHandle {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static void jackSilentError(const char *) {};
|
|
||||||
|
|
||||||
airtaudio::api::Jack::Jack(void) {
|
airtaudio::api::Jack::Jack(void) {
|
||||||
// Nothing to do here.
|
// 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) {
|
airtaudio::api::Jack::~Jack(void) {
|
||||||
@ -122,16 +117,15 @@ uint32_t airtaudio::api::Jack::getDeviceCount(void) {
|
|||||||
return nDevices;
|
return nDevices;
|
||||||
}
|
}
|
||||||
|
|
||||||
airtaudio::DeviceInfo airtaudio::api::Jack::getDeviceInfo(uint32_t _device)
|
airtaudio::DeviceInfo airtaudio::api::Jack::getDeviceInfo(uint32_t _device) {
|
||||||
{
|
|
||||||
airtaudio::DeviceInfo info;
|
airtaudio::DeviceInfo info;
|
||||||
info.probed = false;
|
info.probed = false;
|
||||||
jack_options_t options = (jack_options_t) (JackNoStartServer); //JackNullOption
|
jack_options_t options = (jack_options_t) (JackNoStartServer); //JackNullOption
|
||||||
jack_status_t *status = NULL;
|
jack_status_t *status = NULL;
|
||||||
jack_client_t *client = jack_client_open("RtApiJackInfo", options, status);
|
jack_client_t *client = jack_client_open("RtApiJackInfo", options, status);
|
||||||
if (client == NULL) {
|
if (client == NULL) {
|
||||||
m_errorText = "airtaudio::api::Jack::getDeviceInfo: Jack server not found or connection error!";
|
ATA_ERROR("airtaudio::api::Jack::getDeviceInfo: Jack server not found or connection error!");
|
||||||
error(airtaudio::errorWarning);
|
// TODO : airtaudio::errorWarning;
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
const char **ports;
|
const char **ports;
|
||||||
@ -157,18 +151,15 @@ airtaudio::DeviceInfo airtaudio::api::Jack::getDeviceInfo(uint32_t _device)
|
|||||||
} while (ports[++nPorts]);
|
} while (ports[++nPorts]);
|
||||||
free(ports);
|
free(ports);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_device >= nDevices) {
|
if (_device >= nDevices) {
|
||||||
jack_client_close(client);
|
jack_client_close(client);
|
||||||
m_errorText = "airtaudio::api::Jack::getDeviceInfo: device ID is invalid!";
|
ATA_ERROR("airtaudio::api::Jack::getDeviceInfo: device ID is invalid!");
|
||||||
error(airtaudio::errorInvalidUse);
|
// TODO : airtaudio::errorInvalidUse;
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the current jack server sample rate.
|
// Get the current jack server sample rate.
|
||||||
info.sampleRates.clear();
|
info.sampleRates.clear();
|
||||||
info.sampleRates.push_back(jack_get_sample_rate(client));
|
info.sampleRates.push_back(jack_get_sample_rate(client));
|
||||||
|
|
||||||
// Count the available ports containing the client name as device
|
// Count the available ports containing the client name as device
|
||||||
// channels. Jack "input ports" equal RtAudio output channels.
|
// channels. Jack "input ports" equal RtAudio output channels.
|
||||||
uint32_t nChannels = 0;
|
uint32_t nChannels = 0;
|
||||||
@ -192,8 +183,8 @@ airtaudio::DeviceInfo airtaudio::api::Jack::getDeviceInfo(uint32_t _device)
|
|||||||
}
|
}
|
||||||
if (info.outputChannels == 0 && info.inputChannels == 0) {
|
if (info.outputChannels == 0 && info.inputChannels == 0) {
|
||||||
jack_client_close(client);
|
jack_client_close(client);
|
||||||
m_errorText = "airtaudio::api::Jack::getDeviceInfo: error determining Jack input/output channels!";
|
ATA_ERROR("airtaudio::api::Jack::getDeviceInfo: error determining Jack input/output channels!");
|
||||||
error(airtaudio::errorWarning);
|
// TODO : airtaudio::errorWarning;
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
// If device opens for both playback and capture, we determine the channels.
|
// 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
|
// server signals that it is shutting down. It is necessary to handle
|
||||||
// it this way because the jackShutdown() function must return before
|
// it this way because the jackShutdown() function must return before
|
||||||
// the jack_deactivate() function (in closeStream()) will return.
|
// 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::CallbackInfo* info = (airtaudio::CallbackInfo*)_ptr;
|
||||||
airtaudio::api::Jack* object = (airtaudio::api::Jack*)info->object;
|
airtaudio::api::Jack* object = (airtaudio::api::Jack*)info->object;
|
||||||
object->closeStream();
|
object->closeStream();
|
||||||
pthread_exit(NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void jackShutdown(void* _infoPointer) {
|
static void jackShutdown(void* _infoPointer) {
|
||||||
@ -247,9 +237,8 @@ static void jackShutdown(void* _infoPointer) {
|
|||||||
if (object->isStreamRunning() == false) {
|
if (object->isStreamRunning() == false) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pthread_t threadId;
|
new std::thread(jackCloseStream, info);
|
||||||
pthread_create(&threadId, NULL, jackCloseStream, info);
|
ATA_ERROR("RtApiJack: the Jack server is shutting down this client ... stream stopped and closed!!");
|
||||||
std::cerr << "\nRtApiJack: the Jack server is shutting down this client ... stream stopped and closed!!\n" << std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t jackXrun(void* _infoPointer) {
|
static int32_t jackXrun(void* _infoPointer) {
|
||||||
@ -263,36 +252,35 @@ static int32_t jackXrun(void* _infoPointer) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool airtaudio::api::Jack::probeDeviceOpen(uint32_t device,
|
bool airtaudio::api::Jack::probeDeviceOpen(uint32_t _device,
|
||||||
airtaudio::api::StreamMode mode,
|
airtaudio::api::StreamMode _mode,
|
||||||
uint32_t channels,
|
uint32_t _channels,
|
||||||
uint32_t firstChannel,
|
uint32_t _firstChannel,
|
||||||
uint32_t sampleRate,
|
uint32_t _sampleRate,
|
||||||
airtaudio::format format,
|
airtaudio::format _format,
|
||||||
uint32_t *bufferSize,
|
uint32_t* _bufferSize,
|
||||||
airtaudio::StreamOptions *options) {
|
airtaudio::StreamOptions* _options) {
|
||||||
JackHandle *handle = (JackHandle *) m_stream.apiHandle;
|
JackHandle *handle = (JackHandle *) m_stream.apiHandle;
|
||||||
// Look for jack server and try to become a client (only do once per stream).
|
// Look for jack server and try to become a client (only do once per stream).
|
||||||
jack_client_t *client = 0;
|
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_options_t jackoptions = (jack_options_t) (JackNoStartServer); //JackNullOption;
|
||||||
jack_status_t *status = NULL;
|
jack_status_t *status = NULL;
|
||||||
if (options && !options->streamName.empty()) {
|
if (_options && !_options->streamName.empty()) {
|
||||||
client = jack_client_open(options->streamName.c_str(), jackoptions, status);
|
client = jack_client_open(_options->streamName.c_str(), jackoptions, status);
|
||||||
} else {
|
} else {
|
||||||
client = jack_client_open("RtApiJack", jackoptions, status);
|
client = jack_client_open("RtApiJack", jackoptions, status);
|
||||||
}
|
}
|
||||||
if (client == 0) {
|
if (client == 0) {
|
||||||
m_errorText = "airtaudio::api::Jack::probeDeviceOpen: Jack server not found or connection error!";
|
ATA_ERROR("airtaudio::api::Jack::probeDeviceOpen: Jack server not found or connection error!");
|
||||||
error(airtaudio::errorWarning);
|
|
||||||
return FAILURE;
|
return FAILURE;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// The handle must have been created on an earlier pass.
|
// The handle must have been created on an earlier pass.
|
||||||
client = handle->client;
|
client = handle->client;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char **ports;
|
const char **ports;
|
||||||
std::string port, previousPort, deviceName;
|
std::string port, previousPort, deviceName;
|
||||||
uint32_t nPorts = 0, nDevices = 0;
|
uint32_t nPorts = 0, nDevices = 0;
|
||||||
@ -306,7 +294,9 @@ bool airtaudio::api::Jack::probeDeviceOpen(uint32_t device,
|
|||||||
if (iColon != std::string::npos) {
|
if (iColon != std::string::npos) {
|
||||||
port = port.substr(0, iColon);
|
port = port.substr(0, iColon);
|
||||||
if (port != previousPort) {
|
if (port != previousPort) {
|
||||||
if (nDevices == device) deviceName = port;
|
if (nDevices == _device) {
|
||||||
|
deviceName = port;
|
||||||
|
}
|
||||||
nDevices++;
|
nDevices++;
|
||||||
previousPort = port;
|
previousPort = port;
|
||||||
}
|
}
|
||||||
@ -314,156 +304,141 @@ bool airtaudio::api::Jack::probeDeviceOpen(uint32_t device,
|
|||||||
} while (ports[++nPorts]);
|
} while (ports[++nPorts]);
|
||||||
free(ports);
|
free(ports);
|
||||||
}
|
}
|
||||||
|
if (_device >= nDevices) {
|
||||||
if (device >= nDevices) {
|
ATA_ERROR("airtaudio::api::Jack::probeDeviceOpen: device ID is invalid!");
|
||||||
m_errorText = "airtaudio::api::Jack::probeDeviceOpen: device ID is invalid!";
|
|
||||||
return FAILURE;
|
return FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Count the available ports containing the client name as device
|
// Count the available ports containing the client name as device
|
||||||
// channels. Jack "input ports" equal RtAudio output channels.
|
// channels. Jack "input ports" equal RtAudio output channels.
|
||||||
uint32_t nChannels = 0;
|
uint32_t nChannels = 0;
|
||||||
uint64_t flag = JackPortIsInput;
|
uint64_t flag = JackPortIsInput;
|
||||||
if (mode == INPUT) flag = JackPortIsOutput;
|
if (_mode == INPUT) flag = JackPortIsOutput;
|
||||||
ports = jack_get_ports(client, deviceName.c_str(), NULL, flag);
|
ports = jack_get_ports(client, deviceName.c_str(), NULL, flag);
|
||||||
if (ports) {
|
if (ports) {
|
||||||
while (ports[ nChannels ]) nChannels++;
|
while (ports[ nChannels ]) {
|
||||||
|
nChannels++;
|
||||||
|
}
|
||||||
free(ports);
|
free(ports);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compare the jack ports for specified client to the requested number of channels.
|
// Compare the jack ports for specified client to the requested number of channels.
|
||||||
if (nChannels < (channels + firstChannel)) {
|
if (nChannels < (_channels + _firstChannel)) {
|
||||||
m_errorStream << "airtaudio::api::Jack::probeDeviceOpen: requested number of channels (" << channels << ") + offset (" << firstChannel << ") not found for specified device (" << device << ":" << deviceName << ").";
|
ATA_ERROR("airtaudio::api::Jack::probeDeviceOpen: requested number of channels (" << _channels << ") + offset (" << _firstChannel << ") not found for specified device (" << _device << ":" << deviceName << ").");
|
||||||
m_errorText = m_errorStream.str();
|
|
||||||
return FAILURE;
|
return FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the jack server sample rate.
|
// Check the jack server sample rate.
|
||||||
uint32_t jackRate = jack_get_sample_rate(client);
|
uint32_t jackRate = jack_get_sample_rate(client);
|
||||||
if (sampleRate != jackRate) {
|
if (_sampleRate != jackRate) {
|
||||||
jack_client_close(client);
|
jack_client_close(client);
|
||||||
m_errorStream << "airtaudio::api::Jack::probeDeviceOpen: the requested sample rate (" << sampleRate << ") is different than the JACK server rate (" << jackRate << ").";
|
ATA_ERROR("airtaudio::api::Jack::probeDeviceOpen: the requested sample rate (" << _sampleRate << ") is different than the JACK server rate (" << jackRate << ").");
|
||||||
m_errorText = m_errorStream.str();
|
|
||||||
return FAILURE;
|
return FAILURE;
|
||||||
}
|
}
|
||||||
m_stream.sampleRate = jackRate;
|
m_stream.sampleRate = jackRate;
|
||||||
|
|
||||||
// Get the latency of the JACK port.
|
// Get the latency of the JACK port.
|
||||||
ports = jack_get_ports(client, deviceName.c_str(), NULL, flag);
|
ports = jack_get_ports(client, deviceName.c_str(), NULL, flag);
|
||||||
if (ports[ firstChannel ]) {
|
if (ports[ _firstChannel ]) {
|
||||||
// Added by Ge Wang
|
// 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)
|
// the range (usually the min and max are equal)
|
||||||
jack_latency_range_t latrange; latrange.min = latrange.max = 0;
|
jack_latency_range_t latrange; latrange.min = latrange.max = 0;
|
||||||
// get the latency range
|
// 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!
|
// be optimistic, use the min!
|
||||||
m_stream.latency[mode] = latrange.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] = jack_port_get_latency(jack_port_by_name(client, ports[ _firstChannel ]));
|
||||||
}
|
}
|
||||||
free(ports);
|
free(ports);
|
||||||
|
|
||||||
// The jack server always uses 32-bit floating-point data.
|
// The jack server always uses 32-bit floating-point data.
|
||||||
m_stream.deviceFormat[mode] = FLOAT32;
|
m_stream.deviceFormat[_mode] = FLOAT32;
|
||||||
m_stream.userFormat = format;
|
m_stream.userFormat = _format;
|
||||||
|
if (_options && _options->flags & NONINTERLEAVED) {
|
||||||
if (options && options->flags & NONINTERLEAVED) m_stream.userInterleaved = false;
|
m_stream.userInterleaved = false;
|
||||||
else m_stream.userInterleaved = true;
|
} else {
|
||||||
|
m_stream.userInterleaved = true;
|
||||||
|
}
|
||||||
// Jack always uses non-interleaved buffers.
|
// Jack always uses non-interleaved buffers.
|
||||||
m_stream.deviceInterleaved[mode] = false;
|
m_stream.deviceInterleaved[_mode] = false;
|
||||||
|
|
||||||
// Jack always provides host byte-ordered data.
|
// 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
|
// Get the buffer size. The buffer size and number of buffers
|
||||||
// (periods) is set when the jack server is started.
|
// (periods) is set when the jack server is started.
|
||||||
m_stream.bufferSize = (int) jack_get_buffer_size(client);
|
m_stream.bufferSize = (int) jack_get_buffer_size(client);
|
||||||
*bufferSize = m_stream.bufferSize;
|
*_bufferSize = m_stream.bufferSize;
|
||||||
|
m_stream.nDeviceChannels[_mode] = _channels;
|
||||||
m_stream.nDeviceChannels[mode] = channels;
|
m_stream.nUserChannels[_mode] = _channels;
|
||||||
m_stream.nUserChannels[mode] = channels;
|
|
||||||
|
|
||||||
// Set flags for buffer conversion.
|
// Set flags for buffer conversion.
|
||||||
m_stream.doConvertBuffer[mode] = false;
|
m_stream.doConvertBuffer[_mode] = false;
|
||||||
if (m_stream.userFormat != m_stream.deviceFormat[mode])
|
if (m_stream.userFormat != m_stream.deviceFormat[_mode]) {
|
||||||
m_stream.doConvertBuffer[mode] = true;
|
m_stream.doConvertBuffer[_mode] = true;
|
||||||
if (m_stream.userInterleaved != m_stream.deviceInterleaved[mode] &&
|
}
|
||||||
m_stream.nUserChannels[mode] > 1)
|
if ( m_stream.userInterleaved != m_stream.deviceInterleaved[_mode]
|
||||||
m_stream.doConvertBuffer[mode] = true;
|
&& m_stream.nUserChannels[_mode] > 1) {
|
||||||
|
m_stream.doConvertBuffer[_mode] = true;
|
||||||
|
}
|
||||||
// Allocate our JackHandle structure for the stream.
|
// Allocate our JackHandle structure for the stream.
|
||||||
if (handle == 0) {
|
if (handle == 0) {
|
||||||
try {
|
|
||||||
handle = new JackHandle;
|
handle = new JackHandle;
|
||||||
}
|
if (handle == NULL) {
|
||||||
catch (std::bad_alloc&) {
|
ATA_ERROR("airtaudio::api::Jack::probeDeviceOpen: error allocating JackHandle memory.");
|
||||||
m_errorText = "airtaudio::api::Jack::probeDeviceOpen: error allocating JackHandle memory.";
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
m_stream.apiHandle = (void *) handle;
|
m_stream.apiHandle = (void *) handle;
|
||||||
handle->client = client;
|
handle->client = client;
|
||||||
}
|
}
|
||||||
handle->deviceName[mode] = deviceName;
|
handle->deviceName[_mode] = deviceName;
|
||||||
|
|
||||||
// Allocate necessary internal buffers.
|
// Allocate necessary internal buffers.
|
||||||
uint64_t bufferBytes;
|
uint64_t bufferBytes;
|
||||||
bufferBytes = m_stream.nUserChannels[mode] * *bufferSize * formatBytes(m_stream.userFormat);
|
bufferBytes = m_stream.nUserChannels[_mode] * *_bufferSize * formatBytes(m_stream.userFormat);
|
||||||
m_stream.userBuffer[mode] = (char *) calloc(bufferBytes, 1);
|
m_stream.userBuffer[_mode] = (char *) calloc(bufferBytes, 1);
|
||||||
if (m_stream.userBuffer[mode] == NULL) {
|
if (m_stream.userBuffer[_mode] == NULL) {
|
||||||
m_errorText = "airtaudio::api::Jack::probeDeviceOpen: error allocating user buffer memory.";
|
ATA_ERROR("airtaudio::api::Jack::probeDeviceOpen: error allocating user buffer memory.");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
if (m_stream.doConvertBuffer[_mode]) {
|
||||||
if (m_stream.doConvertBuffer[mode]) {
|
|
||||||
|
|
||||||
bool makeBuffer = true;
|
bool makeBuffer = true;
|
||||||
if (mode == OUTPUT)
|
if (_mode == OUTPUT) {
|
||||||
bufferBytes = m_stream.nDeviceChannels[0] * formatBytes(m_stream.deviceFormat[0]);
|
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]);
|
bufferBytes = m_stream.nDeviceChannels[1] * formatBytes(m_stream.deviceFormat[1]);
|
||||||
if (m_stream.mode == OUTPUT && m_stream.deviceBuffer) {
|
if (m_stream.mode == OUTPUT && m_stream.deviceBuffer) {
|
||||||
uint64_t bytesOut = m_stream.nDeviceChannels[0] * formatBytes(m_stream.deviceFormat[0]);
|
uint64_t bytesOut = m_stream.nDeviceChannels[0] * formatBytes(m_stream.deviceFormat[0]);
|
||||||
if (bufferBytes < bytesOut) makeBuffer = false;
|
if (bufferBytes < bytesOut) {
|
||||||
|
makeBuffer = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (makeBuffer) {
|
if (makeBuffer) {
|
||||||
bufferBytes *= *bufferSize;
|
bufferBytes *= *_bufferSize;
|
||||||
if (m_stream.deviceBuffer) free(m_stream.deviceBuffer);
|
if (m_stream.deviceBuffer) free(m_stream.deviceBuffer);
|
||||||
m_stream.deviceBuffer = (char *) calloc(bufferBytes, 1);
|
m_stream.deviceBuffer = (char *) calloc(bufferBytes, 1);
|
||||||
if (m_stream.deviceBuffer == NULL) {
|
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;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate memory for the Jack ports (channels) identifiers.
|
// Allocate memory for the Jack ports (channels) identifiers.
|
||||||
handle->ports[mode] = (jack_port_t **) malloc (sizeof (jack_port_t *) * channels);
|
handle->ports[_mode] = (jack_port_t **) malloc (sizeof (jack_port_t *) * _channels);
|
||||||
if (handle->ports[mode] == NULL) {
|
if (handle->ports[_mode] == NULL) {
|
||||||
m_errorText = "airtaudio::api::Jack::probeDeviceOpen: error allocating port memory.";
|
ATA_ERROR("airtaudio::api::Jack::probeDeviceOpen: error allocating port memory.");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
m_stream.device[_mode] = _device;
|
||||||
m_stream.device[mode] = device;
|
m_stream.channelOffset[_mode] = _firstChannel;
|
||||||
m_stream.channelOffset[mode] = firstChannel;
|
|
||||||
m_stream.state = STREAM_STOPPED;
|
m_stream.state = STREAM_STOPPED;
|
||||||
m_stream.callbackInfo.object = (void *) this;
|
m_stream.callbackInfo.object = (void *) this;
|
||||||
|
if ( m_stream.mode == OUTPUT
|
||||||
if (m_stream.mode == OUTPUT && mode == INPUT)
|
&& _mode == INPUT) {
|
||||||
// We had already set up the stream for output.
|
// We had already set up the stream for output.
|
||||||
m_stream.mode = DUPLEX;
|
m_stream.mode = DUPLEX;
|
||||||
else {
|
} else {
|
||||||
m_stream.mode = mode;
|
m_stream.mode = _mode;
|
||||||
jack_set_process_callback(handle->client, jackCallbackHandler, (void *) &m_stream.callbackInfo);
|
jack_set_process_callback(handle->client, jackCallbackHandler, (void *) &m_stream.callbackInfo);
|
||||||
jack_set_xrun_callback(handle->client, jackXrun, (void *) &handle);
|
jack_set_xrun_callback(handle->client, jackXrun, (void *) &handle);
|
||||||
jack_on_shutdown(handle->client, jackShutdown, (void *) &m_stream.callbackInfo);
|
jack_on_shutdown(handle->client, jackShutdown, (void *) &m_stream.callbackInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register our ports.
|
// Register our ports.
|
||||||
char label[64];
|
char label[64];
|
||||||
if (mode == OUTPUT) {
|
if (_mode == OUTPUT) {
|
||||||
for (uint32_t i=0; i<m_stream.nUserChannels[0]; i++) {
|
for (uint32_t i=0; i<m_stream.nUserChannels[0]; i++) {
|
||||||
snprintf(label, 64, "outport %d", i);
|
snprintf(label, 64, "outport %d", i);
|
||||||
handle->ports[0][i] = jack_port_register(handle->client,
|
handle->ports[0][i] = jack_port_register(handle->client,
|
||||||
@ -482,15 +457,13 @@ bool airtaudio::api::Jack::probeDeviceOpen(uint32_t device,
|
|||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup the buffer conversion information structure. We don't use
|
// Setup the buffer conversion information structure. We don't use
|
||||||
// buffers to do channel offsets, so we override that parameter
|
// buffers to do channel offsets, so we override that parameter
|
||||||
// here.
|
// here.
|
||||||
if (m_stream.doConvertBuffer[mode]) {
|
if (m_stream.doConvertBuffer[_mode]) {
|
||||||
setConvertInfo(mode, 0);
|
setConvertInfo(_mode, 0);
|
||||||
}
|
}
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
if (handle) {
|
if (handle) {
|
||||||
jack_client_close(handle->client);
|
jack_client_close(handle->client);
|
||||||
@ -501,42 +474,34 @@ error:
|
|||||||
free(handle->ports[1]);
|
free(handle->ports[1]);
|
||||||
}
|
}
|
||||||
delete handle;
|
delete handle;
|
||||||
m_stream.apiHandle = 0;
|
m_stream.apiHandle = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int32_t iii=0; iii<2; ++iii) {
|
for (int32_t iii=0; iii<2; ++iii) {
|
||||||
if (m_stream.userBuffer[iii]) {
|
if (m_stream.userBuffer[iii]) {
|
||||||
free(m_stream.userBuffer[iii]);
|
free(m_stream.userBuffer[iii]);
|
||||||
m_stream.userBuffer[iii] = 0;
|
m_stream.userBuffer[iii] = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_stream.deviceBuffer) {
|
if (m_stream.deviceBuffer) {
|
||||||
free(m_stream.deviceBuffer);
|
free(m_stream.deviceBuffer);
|
||||||
m_stream.deviceBuffer = 0;
|
m_stream.deviceBuffer = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return FAILURE;
|
return FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void airtaudio::api::Jack::closeStream(void)
|
enum airtaudio::errorType airtaudio::api::Jack::closeStream(void) {
|
||||||
{
|
|
||||||
if (m_stream.state == STREAM_CLOSED) {
|
if (m_stream.state == STREAM_CLOSED) {
|
||||||
m_errorText = "airtaudio::api::Jack::closeStream(): no open stream to close!";
|
ATA_ERROR("airtaudio::api::Jack::closeStream(): no open stream to close!");
|
||||||
error(airtaudio::errorWarning);
|
return airtaudio::errorWarning;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JackHandle *handle = (JackHandle *) m_stream.apiHandle;
|
JackHandle *handle = (JackHandle *) m_stream.apiHandle;
|
||||||
if (handle) {
|
if (handle != NULL) {
|
||||||
|
if (m_stream.state == STREAM_RUNNING) {
|
||||||
if (m_stream.state == STREAM_RUNNING)
|
|
||||||
jack_deactivate(handle->client);
|
jack_deactivate(handle->client);
|
||||||
|
}
|
||||||
jack_client_close(handle->client);
|
jack_client_close(handle->client);
|
||||||
}
|
}
|
||||||
|
if (handle != NULL) {
|
||||||
if (handle) {
|
|
||||||
if (handle->ports[0]) {
|
if (handle->ports[0]) {
|
||||||
free(handle->ports[0]);
|
free(handle->ports[0]);
|
||||||
}
|
}
|
||||||
@ -544,52 +509,47 @@ void airtaudio::api::Jack::closeStream(void)
|
|||||||
free(handle->ports[1]);
|
free(handle->ports[1]);
|
||||||
}
|
}
|
||||||
delete handle;
|
delete handle;
|
||||||
m_stream.apiHandle = 0;
|
m_stream.apiHandle = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int32_t i=0; i<2; i++) {
|
for (int32_t i=0; i<2; i++) {
|
||||||
if (m_stream.userBuffer[i]) {
|
if (m_stream.userBuffer[i]) {
|
||||||
free(m_stream.userBuffer[i]);
|
free(m_stream.userBuffer[i]);
|
||||||
m_stream.userBuffer[i] = 0;
|
m_stream.userBuffer[i] = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_stream.deviceBuffer) {
|
if (m_stream.deviceBuffer) {
|
||||||
free(m_stream.deviceBuffer);
|
free(m_stream.deviceBuffer);
|
||||||
m_stream.deviceBuffer = 0;
|
m_stream.deviceBuffer = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_stream.mode = UNINITIALIZED;
|
m_stream.mode = UNINITIALIZED;
|
||||||
m_stream.state = STREAM_CLOSED;
|
m_stream.state = STREAM_CLOSED;
|
||||||
|
return airtaudio::errorNone;
|
||||||
}
|
}
|
||||||
|
|
||||||
void airtaudio::api::Jack::startStream(void)
|
enum airtaudio::errorType airtaudio::api::Jack::startStream(void) {
|
||||||
{
|
if (verifyStream() != airtaudio::errorNone) {
|
||||||
verifyStream();
|
return airtaudio::errorFail;
|
||||||
|
}
|
||||||
if (m_stream.state == STREAM_RUNNING) {
|
if (m_stream.state == STREAM_RUNNING) {
|
||||||
m_errorText = "airtaudio::api::Jack::startStream(): the stream is already running!";
|
ATA_ERROR("airtaudio::api::Jack::startStream(): the stream is already running!");
|
||||||
error(airtaudio::errorWarning);
|
return airtaudio::errorWarning;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JackHandle *handle = (JackHandle *) m_stream.apiHandle;
|
JackHandle *handle = (JackHandle *) m_stream.apiHandle;
|
||||||
int32_t result = jack_activate(handle->client);
|
int32_t result = jack_activate(handle->client);
|
||||||
if (result) {
|
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;
|
goto unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char **ports;
|
const char **ports;
|
||||||
|
|
||||||
// Get the list of available 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;
|
result = 1;
|
||||||
ports = jack_get_ports(handle->client, handle->deviceName[0].c_str(), NULL, JackPortIsInput);
|
ports = jack_get_ports(handle->client, handle->deviceName[0].c_str(), NULL, JackPortIsInput);
|
||||||
if (ports == NULL) {
|
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;
|
goto unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now make the port connections. Since RtAudio wasn't designed to
|
// Now make the port connections. Since RtAudio wasn't designed to
|
||||||
// allow the user to select particular channels of a device, we'll
|
// allow the user to select particular channels of a device, we'll
|
||||||
// just open the first "nChannels" ports with offset.
|
// 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 ]);
|
result = jack_connect(handle->client, jack_port_name(handle->ports[0][i]), ports[ m_stream.channelOffset[0] + i ]);
|
||||||
if (result) {
|
if (result) {
|
||||||
free(ports);
|
free(ports);
|
||||||
m_errorText = "airtaudio::api::Jack::startStream(): error connecting output ports!";
|
ATA_ERROR("airtaudio::api::Jack::startStream(): error connecting output ports!");
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(ports);
|
free(ports);
|
||||||
}
|
}
|
||||||
|
if ( m_stream.mode == INPUT
|
||||||
if (m_stream.mode == INPUT || m_stream.mode == DUPLEX) {
|
|| m_stream.mode == DUPLEX) {
|
||||||
result = 1;
|
result = 1;
|
||||||
ports = jack_get_ports(handle->client, handle->deviceName[1].c_str(), NULL, JackPortIsOutput);
|
ports = jack_get_ports(handle->client, handle->deviceName[1].c_str(), NULL, JackPortIsOutput);
|
||||||
if (ports == NULL) {
|
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;
|
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++) {
|
for (uint32_t i=0; i<m_stream.nUserChannels[1]; i++) {
|
||||||
result = 1;
|
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]));
|
result = jack_connect(handle->client, ports[ m_stream.channelOffset[1] + i ], jack_port_name(handle->ports[1][i]));
|
||||||
|
}
|
||||||
if (result) {
|
if (result) {
|
||||||
free(ports);
|
free(ports);
|
||||||
m_errorText = "airtaudio::api::Jack::startStream(): error connecting input ports!";
|
ATA_ERROR("airtaudio::api::Jack::startStream(): error connecting input ports!");
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(ports);
|
free(ports);
|
||||||
}
|
}
|
||||||
|
|
||||||
handle->drainCounter = 0;
|
handle->drainCounter = 0;
|
||||||
handle->internalDrain = false;
|
handle->internalDrain = false;
|
||||||
m_stream.state = STREAM_RUNNING;
|
m_stream.state = STREAM_RUNNING;
|
||||||
|
|
||||||
unlock:
|
unlock:
|
||||||
if (result == 0) return;
|
if (result == 0) {
|
||||||
error(airtaudio::errorSystemError);
|
return airtaudio::errorNone;
|
||||||
|
}
|
||||||
|
return airtaudio::errorSystemError;
|
||||||
}
|
}
|
||||||
|
|
||||||
void airtaudio::api::Jack::stopStream(void) {
|
enum airtaudio::errorType airtaudio::api::Jack::stopStream(void) {
|
||||||
verifyStream();
|
if (verifyStream() != airtaudio::errorNone) {
|
||||||
|
return airtaudio::errorFail;
|
||||||
|
}
|
||||||
if (m_stream.state == STREAM_STOPPED) {
|
if (m_stream.state == STREAM_STOPPED) {
|
||||||
m_errorText = "airtaudio::api::Jack::stopStream(): the stream is already stopped!";
|
ATA_ERROR("airtaudio::api::Jack::stopStream(): the stream is already stopped!");
|
||||||
error(airtaudio::errorWarning);
|
return airtaudio::errorWarning;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
JackHandle *handle = (JackHandle *) m_stream.apiHandle;
|
JackHandle *handle = (JackHandle *) m_stream.apiHandle;
|
||||||
if ( m_stream.mode == OUTPUT
|
if ( m_stream.mode == OUTPUT
|
||||||
@ -655,21 +616,20 @@ void airtaudio::api::Jack::stopStream(void) {
|
|||||||
}
|
}
|
||||||
jack_deactivate(handle->client);
|
jack_deactivate(handle->client);
|
||||||
m_stream.state = STREAM_STOPPED;
|
m_stream.state = STREAM_STOPPED;
|
||||||
|
return airtaudio::errorNone;
|
||||||
}
|
}
|
||||||
|
|
||||||
void airtaudio::api::Jack::abortStream(void)
|
enum airtaudio::errorType airtaudio::api::Jack::abortStream(void) {
|
||||||
{
|
if (verifyStream() != airtaudio::errorNone) {
|
||||||
verifyStream();
|
return airtaudio::errorFail;
|
||||||
|
}
|
||||||
if (m_stream.state == STREAM_STOPPED) {
|
if (m_stream.state == STREAM_STOPPED) {
|
||||||
m_errorText = "airtaudio::api::Jack::abortStream(): the stream is already stopped!";
|
ATA_ERROR("airtaudio::api::Jack::abortStream(): the stream is already stopped!");
|
||||||
error(airtaudio::errorWarning);
|
return airtaudio::errorWarning;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JackHandle *handle = (JackHandle *) m_stream.apiHandle;
|
JackHandle *handle = (JackHandle *) m_stream.apiHandle;
|
||||||
handle->drainCounter = 2;
|
handle->drainCounter = 2;
|
||||||
|
return stopStream();
|
||||||
stopStream();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function will be called by a spawned thread when the user
|
// This function will be called by a spawned thread when the user
|
||||||
@ -683,23 +643,21 @@ static void jackStopStream(void *_ptr) {
|
|||||||
object->stopStream();
|
object->stopStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool airtaudio::api::Jack::callbackEvent(uint64_t nframes)
|
bool airtaudio::api::Jack::callbackEvent(uint64_t _nframes) {
|
||||||
{
|
if ( m_stream.state == STREAM_STOPPED
|
||||||
if (m_stream.state == STREAM_STOPPED || m_stream.state == STREAM_STOPPING) return SUCCESS;
|
|| m_stream.state == STREAM_STOPPING) {
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
if (m_stream.state == STREAM_CLOSED) {
|
if (m_stream.state == STREAM_CLOSED) {
|
||||||
m_errorText = "RtApiCore::callbackEvent(): the stream is closed ... this shouldn't happen!";
|
ATA_ERROR("RtApiCore::callbackEvent(): the stream is closed ... this shouldn't happen!");
|
||||||
error(airtaudio::errorWarning);
|
|
||||||
return FAILURE;
|
return FAILURE;
|
||||||
}
|
}
|
||||||
if (m_stream.bufferSize != nframes) {
|
if (m_stream.bufferSize != _nframes) {
|
||||||
m_errorText = "RtApiCore::callbackEvent(): the JACK buffer size has changed ... cannot process!";
|
ATA_ERROR("RtApiCore::callbackEvent(): the JACK buffer size has changed ... cannot process!");
|
||||||
error(airtaudio::errorWarning);
|
|
||||||
return FAILURE;
|
return FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
CallbackInfo *info = (CallbackInfo *) &m_stream.callbackInfo;
|
CallbackInfo *info = (CallbackInfo *) &m_stream.callbackInfo;
|
||||||
JackHandle *handle = (JackHandle *) m_stream.apiHandle;
|
JackHandle *handle = (JackHandle *) m_stream.apiHandle;
|
||||||
|
|
||||||
// Check if we were draining the stream and signal is finished.
|
// Check if we were draining the stream and signal is finished.
|
||||||
if (handle->drainCounter > 3) {
|
if (handle->drainCounter > 3) {
|
||||||
m_stream.state = STREAM_STOPPING;
|
m_stream.state = STREAM_STOPPING;
|
||||||
@ -710,7 +668,6 @@ bool airtaudio::api::Jack::callbackEvent(uint64_t nframes)
|
|||||||
}
|
}
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invoke user callback first, to get fresh output data.
|
// Invoke user callback first, to get fresh output data.
|
||||||
if (handle->drainCounter == 0) {
|
if (handle->drainCounter == 0) {
|
||||||
airtaudio::AirTAudioCallback callback = (airtaudio::AirTAudioCallback) info->callback;
|
airtaudio::AirTAudioCallback callback = (airtaudio::AirTAudioCallback) info->callback;
|
||||||
@ -724,8 +681,12 @@ bool airtaudio::api::Jack::callbackEvent(uint64_t nframes)
|
|||||||
status |= INPUT_OVERFLOW;
|
status |= INPUT_OVERFLOW;
|
||||||
handle->xrun[1] = false;
|
handle->xrun[1] = false;
|
||||||
}
|
}
|
||||||
int32_t cbReturnValue = callback(m_stream.userBuffer[0], m_stream.userBuffer[1],
|
int32_t cbReturnValue = callback(m_stream.userBuffer[0],
|
||||||
m_stream.bufferSize, streamTime, status, info->userData);
|
m_stream.userBuffer[1],
|
||||||
|
m_stream.bufferSize,
|
||||||
|
streamTime,
|
||||||
|
status,
|
||||||
|
info->userData);
|
||||||
if (cbReturnValue == 2) {
|
if (cbReturnValue == 2) {
|
||||||
m_stream.state = STREAM_STOPPING;
|
m_stream.state = STREAM_STOPPING;
|
||||||
handle->drainCounter = 2;
|
handle->drainCounter = 2;
|
||||||
@ -737,61 +698,51 @@ bool airtaudio::api::Jack::callbackEvent(uint64_t nframes)
|
|||||||
handle->internalDrain = true;
|
handle->internalDrain = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
jack_default_audio_sample_t *jackbuffer;
|
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 (m_stream.mode == OUTPUT || m_stream.mode == DUPLEX) {
|
||||||
|
|
||||||
if (handle->drainCounter > 1) { // write zeros to the output stream
|
if (handle->drainCounter > 1) { // write zeros to the output stream
|
||||||
|
|
||||||
for (uint32_t i=0; i<m_stream.nDeviceChannels[0]; i++) {
|
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);
|
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]);
|
convertBuffer(m_stream.deviceBuffer, m_stream.userBuffer[0], m_stream.convertInfo[0]);
|
||||||
|
|
||||||
for (uint32_t i=0; i<m_stream.nDeviceChannels[0]; i++) {
|
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);
|
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++) {
|
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);
|
memcpy(jackbuffer, &m_stream.userBuffer[0][i*bufferBytes], bufferBytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (handle->drainCounter) {
|
if (handle->drainCounter) {
|
||||||
handle->drainCounter++;
|
handle->drainCounter++;
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( m_stream.mode == INPUT
|
if ( m_stream.mode == INPUT
|
||||||
|| m_stream.mode == DUPLEX) {
|
|| m_stream.mode == DUPLEX) {
|
||||||
if (m_stream.doConvertBuffer[1]) {
|
if (m_stream.doConvertBuffer[1]) {
|
||||||
for (uint32_t i=0; i<m_stream.nDeviceChannels[1]; i++) {
|
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);
|
memcpy(&m_stream.deviceBuffer[i*bufferBytes], jackbuffer, bufferBytes);
|
||||||
}
|
}
|
||||||
convertBuffer(m_stream.userBuffer[1], m_stream.deviceBuffer, m_stream.convertInfo[1]);
|
convertBuffer(m_stream.userBuffer[1], m_stream.deviceBuffer, m_stream.convertInfo[1]);
|
||||||
} else {
|
} else {
|
||||||
// no buffer conversion
|
// no buffer conversion
|
||||||
for (uint32_t i=0; i<m_stream.nUserChannels[1]; i++) {
|
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);
|
memcpy(&m_stream.userBuffer[1][i*bufferBytes], jackbuffer, bufferBytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unlock:
|
unlock:
|
||||||
airtaudio::Api::tickStreamTime();
|
airtaudio::Api::tickStreamTime();
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
//******************** End of __UNIX_JACK__ *********************//
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -22,10 +22,10 @@ namespace airtaudio {
|
|||||||
}
|
}
|
||||||
uint32_t getDeviceCount(void);
|
uint32_t getDeviceCount(void);
|
||||||
airtaudio::DeviceInfo getDeviceInfo(uint32_t _device);
|
airtaudio::DeviceInfo getDeviceInfo(uint32_t _device);
|
||||||
void closeStream(void);
|
enum airtaudio::errorType closeStream(void);
|
||||||
void startStream(void);
|
enum airtaudio::errorType startStream(void);
|
||||||
void stopStream(void);
|
enum airtaudio::errorType stopStream(void);
|
||||||
void abortStream(void);
|
enum airtaudio::errorType abortStream(void);
|
||||||
long getStreamLatency(void);
|
long getStreamLatency(void);
|
||||||
// This function is intended for internal use only. It must be
|
// This function is intended for internal use only. It must be
|
||||||
// public because it is called by the internal callback handler,
|
// public because it is called by the internal callback handler,
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#if defined(__LINUX_OSS__)
|
#if defined(__LINUX_OSS__)
|
||||||
#include <airtaudio/Interface.h>
|
#include <airtaudio/Interface.h>
|
||||||
|
#include <airtaudio/debug.h>
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
@ -616,8 +617,7 @@ bool airtaudio::api::Oss::probeDeviceOpen(uint32_t device, StreamMode mode, uint
|
|||||||
return FAILURE;
|
return FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void airtaudio::api::Oss::closeStream()
|
enum airtaudio::errorType airtaudio::api::Oss::closeStream(void) {
|
||||||
{
|
|
||||||
if (m_stream.state == STREAM_CLOSED) {
|
if (m_stream.state == STREAM_CLOSED) {
|
||||||
m_errorText = "airtaudio::api::Oss::closeStream(): no open stream to close!";
|
m_errorText = "airtaudio::api::Oss::closeStream(): no open stream to close!";
|
||||||
error(airtaudio::errorWarning);
|
error(airtaudio::errorWarning);
|
||||||
@ -664,9 +664,10 @@ void airtaudio::api::Oss::closeStream()
|
|||||||
m_stream.state = STREAM_CLOSED;
|
m_stream.state = STREAM_CLOSED;
|
||||||
}
|
}
|
||||||
|
|
||||||
void airtaudio::api::Oss::startStream()
|
enum airtaudio::errorType airtaudio::api::Oss::startStream(void) {
|
||||||
{
|
if (verifyStream() != airtaudio::errorNone) {
|
||||||
verifyStream();
|
return airtaudio::errorFail;
|
||||||
|
}
|
||||||
if (m_stream.state == STREAM_RUNNING) {
|
if (m_stream.state == STREAM_RUNNING) {
|
||||||
m_errorText = "airtaudio::api::Oss::startStream(): the stream is already running!";
|
m_errorText = "airtaudio::api::Oss::startStream(): the stream is already running!";
|
||||||
error(airtaudio::errorWarning);
|
error(airtaudio::errorWarning);
|
||||||
@ -686,9 +687,10 @@ void airtaudio::api::Oss::startStream()
|
|||||||
pthread_cond_signal(&handle->runnable);
|
pthread_cond_signal(&handle->runnable);
|
||||||
}
|
}
|
||||||
|
|
||||||
void airtaudio::api::Oss::stopStream()
|
enum airtaudio::errorType airtaudio::api::Oss::stopStream(void) {
|
||||||
{
|
if (verifyStream() != airtaudio::errorNone) {
|
||||||
verifyStream();
|
return airtaudio::errorFail;
|
||||||
|
}
|
||||||
if (m_stream.state == STREAM_STOPPED) {
|
if (m_stream.state == STREAM_STOPPED) {
|
||||||
m_errorText = "airtaudio::api::Oss::stopStream(): the stream is already stopped!";
|
m_errorText = "airtaudio::api::Oss::stopStream(): the stream is already stopped!";
|
||||||
error(airtaudio::errorWarning);
|
error(airtaudio::errorWarning);
|
||||||
@ -758,9 +760,10 @@ void airtaudio::api::Oss::stopStream()
|
|||||||
error(airtaudio::errorSystemError);
|
error(airtaudio::errorSystemError);
|
||||||
}
|
}
|
||||||
|
|
||||||
void airtaudio::api::Oss::abortStream()
|
enum airtaudio::errorType airtaudio::api::Oss::abortStream(void) {
|
||||||
{
|
if (verifyStream() != airtaudio::errorNone) {
|
||||||
verifyStream();
|
return airtaudio::errorFail;
|
||||||
|
}
|
||||||
if (m_stream.state == STREAM_STOPPED) {
|
if (m_stream.state == STREAM_STOPPED) {
|
||||||
m_errorText = "airtaudio::api::Oss::abortStream(): the stream is already stopped!";
|
m_errorText = "airtaudio::api::Oss::abortStream(): the stream is already stopped!";
|
||||||
error(airtaudio::errorWarning);
|
error(airtaudio::errorWarning);
|
||||||
@ -804,8 +807,7 @@ void airtaudio::api::Oss::abortStream()
|
|||||||
*error(airtaudio::errorSystemError);
|
*error(airtaudio::errorSystemError);
|
||||||
}
|
}
|
||||||
|
|
||||||
void airtaudio::api::Oss::callbackEvent()
|
void airtaudio::api::Oss::callbackEvent(void) {
|
||||||
{
|
|
||||||
OssHandle *handle = (OssHandle *) m_stream.apiHandle;
|
OssHandle *handle = (OssHandle *) m_stream.apiHandle;
|
||||||
if (m_stream.state == STREAM_STOPPED) {
|
if (m_stream.state == STREAM_STOPPED) {
|
||||||
m_stream.mutex.lock();
|
m_stream.mutex.lock();
|
||||||
|
@ -22,10 +22,10 @@ namespace airtaudio {
|
|||||||
}
|
}
|
||||||
uint32_t getDeviceCount(void);
|
uint32_t getDeviceCount(void);
|
||||||
airtaudio::DeviceInfo getDeviceInfo(uint32_t _device);
|
airtaudio::DeviceInfo getDeviceInfo(uint32_t _device);
|
||||||
void closeStream(void);
|
enum airtaudio::errorType closeStream(void);
|
||||||
void startStream(void);
|
enum airtaudio::errorType startStream(void);
|
||||||
void stopStream(void);
|
enum airtaudio::errorType stopStream(void);
|
||||||
void abortStream(void);
|
enum airtaudio::errorType abortStream(void);
|
||||||
// This function is intended for internal use only. It must be
|
// This function is intended for internal use only. It must be
|
||||||
// public because it is called by the internal callback handler,
|
// public because it is called by the internal callback handler,
|
||||||
// which is not a member of RtAudio. External use of this function
|
// which is not a member of RtAudio. External use of this function
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <airtaudio/Interface.h>
|
#include <airtaudio/Interface.h>
|
||||||
|
#include <airtaudio/debug.h>
|
||||||
// Code written by Peter Meerwald, pmeerw@pmeerw.net
|
// Code written by Peter Meerwald, pmeerw@pmeerw.net
|
||||||
// and Tristan Matthews.
|
// and Tristan Matthews.
|
||||||
|
|
||||||
@ -60,11 +61,11 @@ struct PulseAudioHandle {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
airtaudio::api::Pulse::~Pulse()
|
airtaudio::api::Pulse::~Pulse(void) {
|
||||||
{
|
if (m_stream.state != STREAM_CLOSED) {
|
||||||
if (m_stream.state != STREAM_CLOSED)
|
|
||||||
closeStream();
|
closeStream();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t airtaudio::api::Pulse::getDeviceCount(void) {
|
uint32_t airtaudio::api::Pulse::getDeviceCount(void) {
|
||||||
return 1;
|
return 1;
|
||||||
@ -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);
|
PulseAudioHandle *pah = static_cast<PulseAudioHandle *>(m_stream.apiHandle);
|
||||||
m_stream.callbackInfo.isRunning = false;
|
m_stream.callbackInfo.isRunning = false;
|
||||||
if (pah) {
|
if (pah) {
|
||||||
@ -114,7 +115,7 @@ void airtaudio::api::Pulse::closeStream(void) {
|
|||||||
pa_simple_free(pah->s_rec);
|
pa_simple_free(pah->s_rec);
|
||||||
}
|
}
|
||||||
delete pah;
|
delete pah;
|
||||||
m_stream.apiHandle = 0;
|
m_stream.apiHandle = NULL;
|
||||||
}
|
}
|
||||||
if (m_stream.userBuffer[0] != NULL) {
|
if (m_stream.userBuffer[0] != NULL) {
|
||||||
free(m_stream.userBuffer[0]);
|
free(m_stream.userBuffer[0]);
|
||||||
@ -126,6 +127,7 @@ void airtaudio::api::Pulse::closeStream(void) {
|
|||||||
}
|
}
|
||||||
m_stream.state = STREAM_CLOSED;
|
m_stream.state = STREAM_CLOSED;
|
||||||
m_stream.mode = UNINITIALIZED;
|
m_stream.mode = UNINITIALIZED;
|
||||||
|
return airtaudio::errorNone;
|
||||||
}
|
}
|
||||||
|
|
||||||
void airtaudio::api::Pulse::callbackEvent(void) {
|
void airtaudio::api::Pulse::callbackEvent(void) {
|
||||||
@ -141,9 +143,7 @@ void airtaudio::api::Pulse::callbackEvent(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (m_stream.state == STREAM_CLOSED) {
|
if (m_stream.state == STREAM_CLOSED) {
|
||||||
m_errorText = "airtaudio::api::Pulse::callbackEvent(): the stream is closed ... "
|
ATA_ERROR("airtaudio::api::Pulse::callbackEvent(): the stream is closed ... this shouldn't happen!");
|
||||||
"this shouldn't happen!";
|
|
||||||
error(airtaudio::errorWarning);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
airtaudio::AirTAudioCallback callback = (airtaudio::AirTAudioCallback) m_stream.callbackInfo.callback;
|
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);
|
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) {
|
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) << ".";
|
ATA_ERROR("airtaudio::api::Pulse::callbackEvent: audio write error, " << pa_strerror(pa_error) << ".");
|
||||||
m_errorText = m_errorStream.str();
|
return;
|
||||||
error(airtaudio::errorWarning);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (m_stream.mode == INPUT || m_stream.mode == DUPLEX) {
|
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);
|
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) {
|
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) << ".";
|
ATA_ERROR("airtaudio::api::Pulse::callbackEvent: audio read error, " << pa_strerror(pa_error) << ".");
|
||||||
m_errorText = m_errorStream.str();
|
return;
|
||||||
error(airtaudio::errorWarning);
|
|
||||||
}
|
}
|
||||||
if (m_stream.doConvertBuffer[INPUT]) {
|
if (m_stream.doConvertBuffer[INPUT]) {
|
||||||
convertBuffer(m_stream.userBuffer[INPUT],
|
convertBuffer(m_stream.userBuffer[INPUT],
|
||||||
@ -200,135 +198,127 @@ void airtaudio::api::Pulse::callbackEvent(void) {
|
|||||||
m_stream.convertInfo[INPUT]);
|
m_stream.convertInfo[INPUT]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unlock:
|
unlock:
|
||||||
m_stream.mutex.unlock();
|
m_stream.mutex.unlock();
|
||||||
airtaudio::Api::tickStreamTime();
|
airtaudio::Api::tickStreamTime();
|
||||||
if (doStopStream == 1) {
|
if (doStopStream == 1) {
|
||||||
stopStream();
|
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);
|
PulseAudioHandle *pah = static_cast<PulseAudioHandle *>(m_stream.apiHandle);
|
||||||
if (m_stream.state == STREAM_CLOSED) {
|
if (m_stream.state == STREAM_CLOSED) {
|
||||||
m_errorText = "airtaudio::api::Pulse::startStream(): the stream is not open!";
|
ATA_ERROR("airtaudio::api::Pulse::startStream(): the stream is not open!");
|
||||||
error(airtaudio::errorInvalidUse);
|
return airtaudio::errorInvalidUse;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
if (m_stream.state == STREAM_RUNNING) {
|
if (m_stream.state == STREAM_RUNNING) {
|
||||||
m_errorText = "airtaudio::api::Pulse::startStream(): the stream is already running!";
|
ATA_ERROR("airtaudio::api::Pulse::startStream(): the stream is already running!");
|
||||||
error(airtaudio::errorWarning);
|
return airtaudio::errorWarning;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
m_stream.mutex.lock();
|
m_stream.mutex.lock();
|
||||||
m_stream.state = STREAM_RUNNING;
|
m_stream.state = STREAM_RUNNING;
|
||||||
pah->runnable = true;
|
pah->runnable = true;
|
||||||
pah->runnable_cv.notify_one();
|
pah->runnable_cv.notify_one();
|
||||||
m_stream.mutex.unlock();
|
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);
|
PulseAudioHandle *pah = static_cast<PulseAudioHandle *>(m_stream.apiHandle);
|
||||||
if (m_stream.state == STREAM_CLOSED) {
|
if (m_stream.state == STREAM_CLOSED) {
|
||||||
m_errorText = "airtaudio::api::Pulse::stopStream(): the stream is not open!";
|
ATA_ERROR("airtaudio::api::Pulse::stopStream(): the stream is not open!");
|
||||||
error(airtaudio::errorInvalidUse);
|
return airtaudio::errorInvalidUse;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
if (m_stream.state == STREAM_STOPPED) {
|
if (m_stream.state == STREAM_STOPPED) {
|
||||||
m_errorText = "airtaudio::api::Pulse::stopStream(): the stream is already stopped!";
|
ATA_ERROR("airtaudio::api::Pulse::stopStream(): the stream is already stopped!");
|
||||||
error(airtaudio::errorWarning);
|
return airtaudio::errorWarning;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
m_stream.state = STREAM_STOPPED;
|
m_stream.state = STREAM_STOPPED;
|
||||||
m_stream.mutex.lock();
|
m_stream.mutex.lock();
|
||||||
if (pah && pah->s_play) {
|
if (pah && pah->s_play) {
|
||||||
int32_t pa_error;
|
int32_t pa_error;
|
||||||
if (pa_simple_drain(pah->s_play, &pa_error) < 0) {
|
if (pa_simple_drain(pah->s_play, &pa_error) < 0) {
|
||||||
m_errorStream << "airtaudio::api::Pulse::stopStream: error draining output device, " <<
|
ATA_ERROR("airtaudio::api::Pulse::stopStream: error draining output device, " << pa_strerror(pa_error) << ".");
|
||||||
pa_strerror(pa_error) << ".";
|
|
||||||
m_errorText = m_errorStream.str();
|
|
||||||
m_stream.mutex.unlock();
|
m_stream.mutex.unlock();
|
||||||
error(airtaudio::errorSystemError);
|
return airtaudio::errorSystemError;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_stream.state = STREAM_STOPPED;
|
m_stream.state = STREAM_STOPPED;
|
||||||
m_stream.mutex.unlock();
|
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);
|
PulseAudioHandle *pah = static_cast<PulseAudioHandle*>(m_stream.apiHandle);
|
||||||
if (m_stream.state == STREAM_CLOSED) {
|
if (m_stream.state == STREAM_CLOSED) {
|
||||||
m_errorText = "airtaudio::api::Pulse::abortStream(): the stream is not open!";
|
ATA_ERROR("airtaudio::api::Pulse::abortStream(): the stream is not open!");
|
||||||
error(airtaudio::errorInvalidUse);
|
return airtaudio::errorInvalidUse;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
if (m_stream.state == STREAM_STOPPED) {
|
if (m_stream.state == STREAM_STOPPED) {
|
||||||
m_errorText = "airtaudio::api::Pulse::abortStream(): the stream is already stopped!";
|
ATA_ERROR("airtaudio::api::Pulse::abortStream(): the stream is already stopped!");
|
||||||
error(airtaudio::errorWarning);
|
return airtaudio::errorWarning;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
m_stream.state = STREAM_STOPPED;
|
m_stream.state = STREAM_STOPPED;
|
||||||
m_stream.mutex.lock();
|
m_stream.mutex.lock();
|
||||||
if (pah && pah->s_play) {
|
if (pah && pah->s_play) {
|
||||||
int32_t pa_error;
|
int32_t pa_error;
|
||||||
if (pa_simple_flush(pah->s_play, &pa_error) < 0) {
|
if (pa_simple_flush(pah->s_play, &pa_error) < 0) {
|
||||||
m_errorStream << "airtaudio::api::Pulse::abortStream: error flushing output device, " <<
|
ATA_ERROR("airtaudio::api::Pulse::abortStream: error flushing output device, " << pa_strerror(pa_error) << ".");
|
||||||
pa_strerror(pa_error) << ".";
|
|
||||||
m_errorText = m_errorStream.str();
|
|
||||||
m_stream.mutex.unlock();
|
m_stream.mutex.unlock();
|
||||||
error(airtaudio::errorSystemError);
|
return airtaudio::errorSystemError;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_stream.state = STREAM_STOPPED;
|
m_stream.state = STREAM_STOPPED;
|
||||||
m_stream.mutex.unlock();
|
m_stream.mutex.unlock();
|
||||||
|
return airtaudio::errorNone;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool airtaudio::api::Pulse::probeDeviceOpen(uint32_t device,
|
bool airtaudio::api::Pulse::probeDeviceOpen(uint32_t _device,
|
||||||
airtaudio::api::StreamMode mode,
|
airtaudio::api::StreamMode _mode,
|
||||||
uint32_t channels,
|
uint32_t _channels,
|
||||||
uint32_t firstChannel,
|
uint32_t _firstChannel,
|
||||||
uint32_t sampleRate,
|
uint32_t _sampleRate,
|
||||||
airtaudio::format format,
|
airtaudio::format _format,
|
||||||
uint32_t *bufferSize,
|
uint32_t *_bufferSize,
|
||||||
airtaudio::StreamOptions *options) {
|
airtaudio::StreamOptions *_options) {
|
||||||
PulseAudioHandle *pah = 0;
|
PulseAudioHandle *pah = 0;
|
||||||
uint64_t bufferBytes = 0;
|
uint64_t bufferBytes = 0;
|
||||||
pa_sample_spec ss;
|
pa_sample_spec ss;
|
||||||
if (device != 0) {
|
if (_device != 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (mode != INPUT && mode != OUTPUT) {
|
if (_mode != INPUT && _mode != OUTPUT) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (channels != 1 && channels != 2) {
|
if (_channels != 1 && _channels != 2) {
|
||||||
m_errorText = "airtaudio::api::Pulse::probeDeviceOpen: unsupported number of channels.";
|
ATA_ERROR("airtaudio::api::Pulse::probeDeviceOpen: unsupported number of channels.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ss.channels = channels;
|
ss.channels = _channels;
|
||||||
if (firstChannel != 0) {
|
if (_firstChannel != 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool sr_found = false;
|
bool sr_found = false;
|
||||||
for (const uint32_t *sr = SUPPORTED_SAMPLERATES; *sr; ++sr) {
|
for (const uint32_t *sr = SUPPORTED_SAMPLERATES; *sr; ++sr) {
|
||||||
if (sampleRate == *sr) {
|
if (_sampleRate == *sr) {
|
||||||
sr_found = true;
|
sr_found = true;
|
||||||
m_stream.sampleRate = sampleRate;
|
m_stream.sampleRate = _sampleRate;
|
||||||
ss.rate = sampleRate;
|
ss.rate = _sampleRate;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!sr_found) {
|
if (!sr_found) {
|
||||||
m_errorText = "airtaudio::api::Pulse::probeDeviceOpen: unsupported sample rate.";
|
ATA_ERROR("airtaudio::api::Pulse::probeDeviceOpen: unsupported sample rate.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool sf_found = 0;
|
bool sf_found = 0;
|
||||||
for (const rtaudio_pa_format_mapping_t *sf = supported_sampleformats;
|
for (const rtaudio_pa_format_mapping_t *sf = supported_sampleformats;
|
||||||
sf->airtaudio_format && sf->pa_format != PA_SAMPLE_INVALID;
|
sf->airtaudio_format && sf->pa_format != PA_SAMPLE_INVALID;
|
||||||
++sf) {
|
++sf) {
|
||||||
if (format == sf->airtaudio_format) {
|
if (_format == sf->airtaudio_format) {
|
||||||
sf_found = true;
|
sf_found = true;
|
||||||
m_stream.userFormat = sf->airtaudio_format;
|
m_stream.userFormat = sf->airtaudio_format;
|
||||||
ss.format = sf->pa_format;
|
ss.format = sf->pa_format;
|
||||||
@ -336,80 +326,77 @@ bool airtaudio::api::Pulse::probeDeviceOpen(uint32_t device,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!sf_found) {
|
if (!sf_found) {
|
||||||
m_errorText = "airtaudio::api::Pulse::probeDeviceOpen: unsupported sample format.";
|
ATA_ERROR("airtaudio::api::Pulse::probeDeviceOpen: unsupported sample format.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set interleaving parameters.
|
// Set interleaving parameters.
|
||||||
if (options && options->flags & NONINTERLEAVED) {
|
if (_options && _options->flags & NONINTERLEAVED) {
|
||||||
m_stream.userInterleaved = false;
|
m_stream.userInterleaved = false;
|
||||||
} else {
|
} else {
|
||||||
m_stream.userInterleaved = true;
|
m_stream.userInterleaved = true;
|
||||||
}
|
}
|
||||||
m_stream.deviceInterleaved[mode] = true;
|
m_stream.deviceInterleaved[_mode] = true;
|
||||||
m_stream.nBuffers = 1;
|
m_stream.nBuffers = 1;
|
||||||
m_stream.doByteSwap[mode] = false;
|
m_stream.doByteSwap[_mode] = false;
|
||||||
m_stream.doConvertBuffer[mode] = channels > 1 && !m_stream.userInterleaved;
|
m_stream.doConvertBuffer[_mode] = _channels > 1 && !m_stream.userInterleaved;
|
||||||
m_stream.deviceFormat[mode] = m_stream.userFormat;
|
m_stream.deviceFormat[_mode] = m_stream.userFormat;
|
||||||
m_stream.nUserChannels[mode] = channels;
|
m_stream.nUserChannels[_mode] = _channels;
|
||||||
m_stream.nDeviceChannels[mode] = channels + firstChannel;
|
m_stream.nDeviceChannels[_mode] = _channels + _firstChannel;
|
||||||
m_stream.channelOffset[mode] = 0;
|
m_stream.channelOffset[_mode] = 0;
|
||||||
|
|
||||||
// Allocate necessary internal buffers.
|
// Allocate necessary internal buffers.
|
||||||
bufferBytes = m_stream.nUserChannels[mode] * *bufferSize * formatBytes(m_stream.userFormat);
|
bufferBytes = m_stream.nUserChannels[_mode] * *_bufferSize * formatBytes(m_stream.userFormat);
|
||||||
m_stream.userBuffer[mode] = (char *) calloc(bufferBytes, 1);
|
m_stream.userBuffer[_mode] = (char *) calloc(bufferBytes, 1);
|
||||||
if (m_stream.userBuffer[mode] == NULL) {
|
if (m_stream.userBuffer[_mode] == NULL) {
|
||||||
m_errorText = "airtaudio::api::Pulse::probeDeviceOpen: error allocating user buffer memory.";
|
ATA_ERROR("airtaudio::api::Pulse::probeDeviceOpen: error allocating user buffer memory.");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
m_stream.bufferSize = *bufferSize;
|
m_stream.bufferSize = *_bufferSize;
|
||||||
|
if (m_stream.doConvertBuffer[_mode]) {
|
||||||
if (m_stream.doConvertBuffer[mode]) {
|
|
||||||
bool makeBuffer = true;
|
bool makeBuffer = true;
|
||||||
bufferBytes = m_stream.nDeviceChannels[mode] * formatBytes(m_stream.deviceFormat[mode]);
|
bufferBytes = m_stream.nDeviceChannels[_mode] * formatBytes(m_stream.deviceFormat[_mode]);
|
||||||
if (mode == INPUT) {
|
if (_mode == INPUT) {
|
||||||
if (m_stream.mode == OUTPUT && m_stream.deviceBuffer) {
|
if (m_stream.mode == OUTPUT && m_stream.deviceBuffer) {
|
||||||
uint64_t bytesOut = m_stream.nDeviceChannels[0] * formatBytes(m_stream.deviceFormat[0]);
|
uint64_t bytesOut = m_stream.nDeviceChannels[0] * formatBytes(m_stream.deviceFormat[0]);
|
||||||
if (bufferBytes <= bytesOut) makeBuffer = false;
|
if (bufferBytes <= bytesOut) makeBuffer = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (makeBuffer) {
|
if (makeBuffer) {
|
||||||
bufferBytes *= *bufferSize;
|
bufferBytes *= *_bufferSize;
|
||||||
if (m_stream.deviceBuffer) free(m_stream.deviceBuffer);
|
if (m_stream.deviceBuffer) free(m_stream.deviceBuffer);
|
||||||
m_stream.deviceBuffer = (char *) calloc(bufferBytes, 1);
|
m_stream.deviceBuffer = (char *) calloc(bufferBytes, 1);
|
||||||
if (m_stream.deviceBuffer == NULL) {
|
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;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_stream.device[mode] = device;
|
m_stream.device[_mode] = _device;
|
||||||
// Setup the buffer conversion information structure.
|
// Setup the buffer conversion information structure.
|
||||||
if (m_stream.doConvertBuffer[mode]) {
|
if (m_stream.doConvertBuffer[_mode]) {
|
||||||
setConvertInfo(mode, firstChannel);
|
setConvertInfo(_mode, _firstChannel);
|
||||||
}
|
}
|
||||||
if (!m_stream.apiHandle) {
|
if (!m_stream.apiHandle) {
|
||||||
PulseAudioHandle *pah = new PulseAudioHandle;
|
PulseAudioHandle *pah = new PulseAudioHandle;
|
||||||
if (!pah) {
|
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;
|
goto error;
|
||||||
}
|
}
|
||||||
m_stream.apiHandle = pah;
|
m_stream.apiHandle = pah;
|
||||||
}
|
}
|
||||||
pah = static_cast<PulseAudioHandle *>(m_stream.apiHandle);
|
pah = static_cast<PulseAudioHandle *>(m_stream.apiHandle);
|
||||||
int32_t error;
|
int32_t error;
|
||||||
switch (mode) {
|
switch (_mode) {
|
||||||
case INPUT:
|
case INPUT:
|
||||||
pah->s_rec = pa_simple_new(NULL, "RtAudio", PA_STREAM_RECORD, NULL, "Record", &ss, NULL, NULL, &error);
|
pah->s_rec = pa_simple_new(NULL, "RtAudio", PA_STREAM_RECORD, NULL, "Record", &ss, NULL, NULL, &error);
|
||||||
if (!pah->s_rec) {
|
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;
|
goto error;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case OUTPUT:
|
case OUTPUT:
|
||||||
pah->s_play = pa_simple_new(NULL, "RtAudio", PA_STREAM_PLAYBACK, NULL, "Playback", &ss, NULL, NULL, &error);
|
pah->s_play = pa_simple_new(NULL, "RtAudio", PA_STREAM_PLAYBACK, NULL, "Playback", &ss, NULL, NULL, &error);
|
||||||
if (!pah->s_play) {
|
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;
|
goto error;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -417,8 +404,8 @@ bool airtaudio::api::Pulse::probeDeviceOpen(uint32_t device,
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if (m_stream.mode == UNINITIALIZED) {
|
if (m_stream.mode == UNINITIALIZED) {
|
||||||
m_stream.mode = mode;
|
m_stream.mode = _mode;
|
||||||
} else if (m_stream.mode == mode) {
|
} else if (m_stream.mode == _mode) {
|
||||||
goto error;
|
goto error;
|
||||||
}else {
|
}else {
|
||||||
m_stream.mode = DUPLEX;
|
m_stream.mode = DUPLEX;
|
||||||
@ -428,13 +415,12 @@ bool airtaudio::api::Pulse::probeDeviceOpen(uint32_t device,
|
|||||||
m_stream.callbackInfo.isRunning = true;
|
m_stream.callbackInfo.isRunning = true;
|
||||||
pah->thread = new std::thread(pulseaudio_callback, (void *)&m_stream.callbackInfo);
|
pah->thread = new std::thread(pulseaudio_callback, (void *)&m_stream.callbackInfo);
|
||||||
if (pah->thread == NULL) {
|
if (pah->thread == NULL) {
|
||||||
m_errorText = "airtaudio::api::Pulse::probeDeviceOpen: error creating thread.";
|
ATA_ERROR("airtaudio::api::Pulse::probeDeviceOpen: error creating thread.");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_stream.state = STREAM_STOPPED;
|
m_stream.state = STREAM_STOPPED;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
if (pah && m_stream.callbackInfo.isRunning) {
|
if (pah && m_stream.callbackInfo.isRunning) {
|
||||||
delete pah;
|
delete pah;
|
||||||
|
@ -21,10 +21,10 @@ namespace airtaudio {
|
|||||||
}
|
}
|
||||||
uint32_t getDeviceCount(void);
|
uint32_t getDeviceCount(void);
|
||||||
airtaudio::DeviceInfo getDeviceInfo(uint32_t _device);
|
airtaudio::DeviceInfo getDeviceInfo(uint32_t _device);
|
||||||
void closeStream(void);
|
enum airtaudio::errorType closeStream(void);
|
||||||
void startStream(void);
|
enum airtaudio::errorType startStream(void);
|
||||||
void stopStream(void);
|
enum airtaudio::errorType stopStream(void);
|
||||||
void abortStream(void);
|
enum airtaudio::errorType abortStream(void);
|
||||||
// This function is intended for internal use only. It must be
|
// This function is intended for internal use only. It must be
|
||||||
// public because it is called by the internal callback handler,
|
// public because it is called by the internal callback handler,
|
||||||
// which is not a member of RtAudio. External use of this function
|
// which is not a member of RtAudio. External use of this function
|
||||||
|
@ -28,6 +28,7 @@ namespace airtaudio {
|
|||||||
errorNone, //!< No error
|
errorNone, //!< No error
|
||||||
errorFail, //!< An error occure in the operation
|
errorFail, //!< An error occure in the operation
|
||||||
errorWarning, //!< A non-critical error.
|
errorWarning, //!< A non-critical error.
|
||||||
|
errorInputNull, //!< null input or internal errror
|
||||||
errorInvalidUse, //!< The function was called incorrectly.
|
errorInvalidUse, //!< The function was called incorrectly.
|
||||||
errorSystemError //!< A system error occured.
|
errorSystemError //!< A system error occured.
|
||||||
};
|
};
|
||||||
@ -171,14 +172,6 @@ namespace airtaudio {
|
|||||||
double _streamTime,
|
double _streamTime,
|
||||||
airtaudio::streamStatus _status,
|
airtaudio::streamStatus _status,
|
||||||
void *_userData);
|
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>
|
#include <airtaudio/DeviceInfo.h>
|
||||||
|
12
airtaudio/debug.cpp
Normal file
12
airtaudio/debug.cpp
Normal 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
28
airtaudio/debug.h
Normal 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
|
||||||
|
|
@ -11,6 +11,7 @@ def create(target):
|
|||||||
myModule = module.Module(__file__, 'airtaudio', 'LIBRARY')
|
myModule = module.Module(__file__, 'airtaudio', 'LIBRARY')
|
||||||
|
|
||||||
myModule.add_src_file([
|
myModule.add_src_file([
|
||||||
|
'airtaudio/debug.cpp',
|
||||||
'airtaudio/Interface.cpp',
|
'airtaudio/Interface.cpp',
|
||||||
'airtaudio/Api.cpp',
|
'airtaudio/Api.cpp',
|
||||||
'airtaudio/api/Alsa.cpp',
|
'airtaudio/api/Alsa.cpp',
|
||||||
@ -23,6 +24,7 @@ def create(target):
|
|||||||
'airtaudio/api/Pulse.cpp'
|
'airtaudio/api/Pulse.cpp'
|
||||||
])
|
])
|
||||||
|
|
||||||
|
myModule.add_export_flag_CC(['-D__AIRTAUDIO_API_DUMMY_H__'])
|
||||||
if target.name=="Windows":
|
if target.name=="Windows":
|
||||||
# ASIO API on Windows
|
# ASIO API on Windows
|
||||||
myModule.add_export_flag_CC(['__WINDOWS_ASIO__'])
|
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_CC(['-D__LINUX_PULSE__'])
|
||||||
myModule.add_export_flag_LD("-lpulse-simple")
|
myModule.add_export_flag_LD("-lpulse-simple")
|
||||||
myModule.add_export_flag_LD("-lpulse")
|
myModule.add_export_flag_LD("-lpulse")
|
||||||
#depending libs :
|
|
||||||
myModule.add_export_flag_LD("-lpthread")
|
|
||||||
elif target.name=="MacOs":
|
elif target.name=="MacOs":
|
||||||
# MacOsX core
|
# MacOsX core
|
||||||
myModule.add_export_flag_CC(['__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/")
|
||||||
myModule.add_path(tools.get_current_path(__file__)+"/rtaudio/include/")
|
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
|
# add the currrent module at the
|
||||||
return myModule
|
return myModule
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user