[DEV] add API to open stream with his name (alsa specific)
This commit is contained in:
parent
12342a4ffa
commit
e6de495285
@ -81,7 +81,8 @@ enum airtaudio::error airtaudio::Api::openStream(airtaudio::StreamParameters *oP
|
||||
ATA_ERROR("a non-nullptr input StreamParameters structure cannot have an nChannels value less than one.");
|
||||
return airtaudio::error_invalidUse;
|
||||
}
|
||||
if (oParams == nullptr && iParams == nullptr) {
|
||||
if ( oParams == nullptr
|
||||
&& iParams == nullptr) {
|
||||
ATA_ERROR("input and output StreamParameters structures are both nullptr!");
|
||||
return airtaudio::error_invalidUse;
|
||||
}
|
||||
@ -93,7 +94,8 @@ enum airtaudio::error airtaudio::Api::openStream(airtaudio::StreamParameters *oP
|
||||
uint32_t oChannels = 0;
|
||||
if (oParams) {
|
||||
oChannels = oParams->nChannels;
|
||||
if (oParams->deviceId >= nDevices) {
|
||||
if ( oParams->deviceId >= nDevices
|
||||
&& oParams->deviceName == "") {
|
||||
ATA_ERROR("output device parameter value is invalid.");
|
||||
return airtaudio::error_invalidUse;
|
||||
}
|
||||
@ -101,7 +103,8 @@ enum airtaudio::error airtaudio::Api::openStream(airtaudio::StreamParameters *oP
|
||||
uint32_t iChannels = 0;
|
||||
if (iParams) {
|
||||
iChannels = iParams->nChannels;
|
||||
if (iParams->deviceId >= nDevices) {
|
||||
if ( iParams->deviceId >= nDevices
|
||||
&& iParams->deviceName == "") {
|
||||
ATA_ERROR("input device parameter value is invalid.");
|
||||
return airtaudio::error_invalidUse;
|
||||
}
|
||||
@ -109,28 +112,50 @@ enum airtaudio::error airtaudio::Api::openStream(airtaudio::StreamParameters *oP
|
||||
clearStreamInfo();
|
||||
bool result;
|
||||
if (oChannels > 0) {
|
||||
result = probeDeviceOpen(oParams->deviceId,
|
||||
airtaudio::mode_output,
|
||||
oChannels,
|
||||
oParams->firstChannel,
|
||||
sampleRate,
|
||||
format,
|
||||
bufferFrames,
|
||||
options);
|
||||
if (oParams->deviceId == -1) {
|
||||
result = probeDeviceOpenName(oParams->deviceName,
|
||||
airtaudio::mode_output,
|
||||
oChannels,
|
||||
oParams->firstChannel,
|
||||
sampleRate,
|
||||
format,
|
||||
bufferFrames,
|
||||
options);
|
||||
} else {
|
||||
result = probeDeviceOpen(oParams->deviceId,
|
||||
airtaudio::mode_output,
|
||||
oChannels,
|
||||
oParams->firstChannel,
|
||||
sampleRate,
|
||||
format,
|
||||
bufferFrames,
|
||||
options);
|
||||
}
|
||||
if (result == false) {
|
||||
ATA_ERROR("system ERROR");
|
||||
return airtaudio::error_systemError;
|
||||
}
|
||||
}
|
||||
if (iChannels > 0) {
|
||||
result = probeDeviceOpen(iParams->deviceId,
|
||||
airtaudio::mode_input,
|
||||
iChannels,
|
||||
iParams->firstChannel,
|
||||
sampleRate,
|
||||
format,
|
||||
bufferFrames,
|
||||
options);
|
||||
if (iParams->deviceId == -1) {
|
||||
result = probeDeviceOpenName(iParams->deviceName,
|
||||
airtaudio::mode_input,
|
||||
iChannels,
|
||||
iParams->firstChannel,
|
||||
sampleRate,
|
||||
format,
|
||||
bufferFrames,
|
||||
options);
|
||||
} else {
|
||||
result = probeDeviceOpen(iParams->deviceId,
|
||||
airtaudio::mode_input,
|
||||
iChannels,
|
||||
iParams->firstChannel,
|
||||
sampleRate,
|
||||
format,
|
||||
bufferFrames,
|
||||
options);
|
||||
}
|
||||
if (result == false) {
|
||||
if (oChannels > 0) {
|
||||
closeStream();
|
||||
|
@ -56,6 +56,10 @@ namespace airtaudio {
|
||||
virtual airtaudio::type getCurrentApi() = 0;
|
||||
virtual uint32_t getDeviceCount() = 0;
|
||||
virtual airtaudio::DeviceInfo getDeviceInfo(uint32_t _device) = 0;
|
||||
// TODO : Check API ...
|
||||
virtual bool getNamedDeviceInfo(const std::string& _deviceName, airtaudio::DeviceInfo& _info) {
|
||||
return false;
|
||||
}
|
||||
virtual uint32_t getDefaultInputDevice();
|
||||
virtual uint32_t getDefaultOutputDevice();
|
||||
enum airtaudio::error openStream(airtaudio::StreamParameters* _outputParameters,
|
||||
@ -120,6 +124,14 @@ namespace airtaudio {
|
||||
enum audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
airtaudio::StreamOptions *_options);
|
||||
virtual bool probeDeviceOpenName(const std::string& _deviceName,
|
||||
airtaudio::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
airtaudio::StreamOptions *_options) { return false; }
|
||||
/**
|
||||
* @brief Increment the stream time.
|
||||
*/
|
||||
|
@ -143,14 +143,13 @@ airtaudio::Interface::~Interface() {
|
||||
m_rtapi = nullptr;
|
||||
}
|
||||
|
||||
enum airtaudio::error airtaudio::Interface::openStream(
|
||||
airtaudio::StreamParameters* _outputParameters,
|
||||
airtaudio::StreamParameters* _inputParameters,
|
||||
audio::format _format,
|
||||
uint32_t _sampleRate,
|
||||
uint32_t* _bufferFrames,
|
||||
airtaudio::AirTAudioCallback _callback,
|
||||
airtaudio::StreamOptions* _options) {
|
||||
enum airtaudio::error airtaudio::Interface::openStream(airtaudio::StreamParameters* _outputParameters,
|
||||
airtaudio::StreamParameters* _inputParameters,
|
||||
audio::format _format,
|
||||
uint32_t _sampleRate,
|
||||
uint32_t* _bufferFrames,
|
||||
airtaudio::AirTAudioCallback _callback,
|
||||
airtaudio::StreamOptions* _options) {
|
||||
if (m_rtapi == nullptr) {
|
||||
return airtaudio::error_inputNull;
|
||||
}
|
||||
|
@ -116,6 +116,14 @@ namespace airtaudio {
|
||||
}
|
||||
return m_rtapi->getDeviceInfo(_device);
|
||||
}
|
||||
airtaudio::DeviceInfo getDeviceInfo(const std::string& _deviceName) {
|
||||
if (m_rtapi == nullptr) {
|
||||
return airtaudio::DeviceInfo();
|
||||
}
|
||||
airtaudio::DeviceInfo info;
|
||||
m_rtapi->getNamedDeviceInfo(_deviceName, info);
|
||||
return info;
|
||||
}
|
||||
/**
|
||||
* @brief A function that returns the index of the default output device.
|
||||
*
|
||||
@ -165,7 +173,7 @@ namespace airtaudio {
|
||||
* 0 and getDeviceCount() - 1.
|
||||
* @param _format An audio::format specifying the desired sample data format.
|
||||
* @param _sampleRate The desired sample rate (sample frames per second).
|
||||
* @param *_bufferFrames A pointer to a value indicating the desired
|
||||
* @param _bufferFrames A pointer to a value indicating the desired
|
||||
* internal buffer size in sample frames. The actual value
|
||||
* used by the device is returned via the same pointer. A
|
||||
* value of zero can be specified, in which case the lowest
|
||||
@ -185,12 +193,12 @@ namespace airtaudio {
|
||||
* when an error has occured.
|
||||
*/
|
||||
enum airtaudio::error openStream(airtaudio::StreamParameters *_outputParameters,
|
||||
airtaudio::StreamParameters *_inputParameters,
|
||||
enum audio::format _format,
|
||||
uint32_t _sampleRate,
|
||||
uint32_t *_bufferFrames,
|
||||
airtaudio::AirTAudioCallback _callback,
|
||||
airtaudio::StreamOptions *_options = nullptr);
|
||||
airtaudio::StreamParameters *_inputParameters,
|
||||
enum audio::format _format,
|
||||
uint32_t _sampleRate,
|
||||
uint32_t* _bufferFrames,
|
||||
airtaudio::AirTAudioCallback _callback,
|
||||
airtaudio::StreamOptions *_options = nullptr);
|
||||
|
||||
/**
|
||||
* @brief A function that closes a stream and frees any associated stream memory.
|
||||
|
@ -14,12 +14,13 @@ namespace airtaudio {
|
||||
*/
|
||||
class StreamParameters {
|
||||
public:
|
||||
uint32_t deviceId; //!< Device index (0 to getDeviceCount() - 1).
|
||||
int32_t deviceId; //!< Device index (-1 to getDeviceCount() - 1).
|
||||
std::string deviceName; //!< name of the device (if deviceId==-1 this must not be == "", and the oposite ...)
|
||||
uint32_t nChannels; //!< Number of channels.
|
||||
uint32_t firstChannel; //!< First channel index on device (default = 0).
|
||||
// Default constructor.
|
||||
StreamParameters() :
|
||||
deviceId(0),
|
||||
deviceId(-1),
|
||||
nChannels(0),
|
||||
firstChannel(0) { }
|
||||
};
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <unistd.h>
|
||||
#include <airtaudio/Interface.h>
|
||||
#include <airtaudio/debug.h>
|
||||
#include <etk/stdTools.h>
|
||||
#include <limits.h>
|
||||
|
||||
#undef __class__
|
||||
@ -62,7 +63,9 @@ airtaudio::api::Alsa::~Alsa() {
|
||||
|
||||
uint32_t airtaudio::api::Alsa::getDeviceCount() {
|
||||
unsigned nDevices = 0;
|
||||
int32_t result, subdevice, card;
|
||||
int32_t result= -1;
|
||||
int32_t subdevice = -1;
|
||||
int32_t card = -1;
|
||||
char name[64];
|
||||
snd_ctl_t *handle;
|
||||
// Count cards and devices
|
||||
@ -96,8 +99,9 @@ nextcard:
|
||||
return nDevices;
|
||||
}
|
||||
|
||||
bool airtaudio::api::Alsa::getDeviceInfo(const std::string& _deviceName, airtaudio::DeviceInfo& _info) {
|
||||
bool airtaudio::api::Alsa::getNamedDeviceInfoLocal(const std::string& _deviceName, airtaudio::DeviceInfo& _info, int32_t _cardId, int32_t _subdevice, int32_t _localDeviceId) {
|
||||
int32_t result;
|
||||
snd_ctl_t *chandle;
|
||||
int32_t openMode = SND_PCM_ASYNC;
|
||||
snd_pcm_stream_t stream;
|
||||
snd_pcm_info_t *pcminfo;
|
||||
@ -108,9 +112,18 @@ bool airtaudio::api::Alsa::getDeviceInfo(const std::string& _deviceName, airtaud
|
||||
// First try for playback unless default _device (which has subdev -1)
|
||||
stream = SND_PCM_STREAM_PLAYBACK;
|
||||
snd_pcm_info_set_stream(pcminfo, stream);
|
||||
/*
|
||||
if (subdevice != -1) {
|
||||
snd_pcm_info_set_device(pcminfo, subdevice);
|
||||
std::vector<std::string> listElement = etk::split(_deviceName, ',');
|
||||
if (listElement.size() == 0) {
|
||||
ATA_ERROR("can not get control interface = '" << _deviceName << "' Can not plit at ',' ...");
|
||||
return false;
|
||||
}
|
||||
result = snd_ctl_open(&chandle, listElement[0].c_str(), SND_CTL_NONBLOCK);
|
||||
if (result < 0) {
|
||||
ATA_ERROR("control open, card = " << listElement[0] << ", " << snd_strerror(result) << ".");
|
||||
return false;
|
||||
}
|
||||
if (_subdevice != -1) {
|
||||
snd_pcm_info_set_device(pcminfo, _subdevice);
|
||||
snd_pcm_info_set_subdevice(pcminfo, 0);
|
||||
result = snd_ctl_pcm_info(chandle, pcminfo);
|
||||
if (result < 0) {
|
||||
@ -118,7 +131,6 @@ bool airtaudio::api::Alsa::getDeviceInfo(const std::string& _deviceName, airtaud
|
||||
goto captureProbe;
|
||||
}
|
||||
}
|
||||
*/
|
||||
result = snd_pcm_open(&phandle, _deviceName.c_str(), stream, openMode | SND_PCM_NONBLOCK);
|
||||
if (result < 0) {
|
||||
ATA_ERROR("snd_pcm_open error for device (" << _deviceName << "), " << snd_strerror(result) << ".");
|
||||
@ -149,8 +161,7 @@ captureProbe:
|
||||
stream = SND_PCM_STREAM_CAPTURE;
|
||||
snd_pcm_info_set_stream(pcminfo, stream);
|
||||
// Now try for capture unless default device (with subdev = -1)
|
||||
/*
|
||||
if (subdevice != -1) {
|
||||
if (_subdevice != -1) {
|
||||
result = snd_ctl_pcm_info(chandle, pcminfo);
|
||||
snd_ctl_close(chandle);
|
||||
if (result < 0) {
|
||||
@ -161,7 +172,6 @@ captureProbe:
|
||||
goto probeParameters;
|
||||
}
|
||||
}
|
||||
*/
|
||||
result = snd_pcm_open(&phandle, _deviceName.c_str(), stream, openMode | SND_PCM_NONBLOCK);
|
||||
if (result < 0) {
|
||||
ATA_ERROR("snd_pcm_open error for device (" << _deviceName << "), " << snd_strerror(result) << ".");
|
||||
@ -200,20 +210,18 @@ captureProbe:
|
||||
_info.duplexChannels = (_info.outputChannels > _info.inputChannels) ? _info.inputChannels : _info.outputChannels;
|
||||
}
|
||||
// ALSA doesn't provide default devices so we'll use the first available one.
|
||||
/*
|
||||
if ( _name == 0
|
||||
if ( _localDeviceId == 0
|
||||
&& _info.outputChannels > 0) {
|
||||
info.isDefaultOutput = true;
|
||||
_info.isDefaultOutput = true;
|
||||
}
|
||||
if ( _device == 0
|
||||
if ( _localDeviceId == 0
|
||||
&& _info.inputChannels > 0) {
|
||||
info.isDefaultInput = true;
|
||||
_info.isDefaultInput = true;
|
||||
}
|
||||
*/
|
||||
|
||||
probeParameters:
|
||||
// At this point, we just need to figure out the supported data
|
||||
// formats and sample rates. We'll proceed by opening the device in
|
||||
// formats and sample rates. We'll proceed by opening the device in
|
||||
// the direction with the maximum number of channels, or playback if
|
||||
// they are equal. This might limit our sample rate options, but so
|
||||
// be it.
|
||||
@ -286,14 +294,17 @@ probeParameters:
|
||||
return false;
|
||||
}
|
||||
// Get the device name
|
||||
/*
|
||||
char *cardname;
|
||||
result = snd_card_get_name(card, &cardname);
|
||||
if (result >= 0) {
|
||||
sprintf(name, "hw:%s,%d", cardname, subdevice);
|
||||
if (_cardId != -1) {
|
||||
char *cardname;
|
||||
char name[1024];
|
||||
result = snd_card_get_name(_cardId, &cardname);
|
||||
if (result >= 0) {
|
||||
sprintf(name, "hw:%s,%d", cardname, _subdevice);
|
||||
}
|
||||
_info.name = name;
|
||||
} else {
|
||||
_info.name = _deviceName;
|
||||
}
|
||||
*/
|
||||
_info.name = _deviceName;
|
||||
// That's all ... close the device and return
|
||||
snd_pcm_close(phandle);
|
||||
_info.probed = true;
|
||||
@ -302,14 +313,18 @@ probeParameters:
|
||||
|
||||
airtaudio::DeviceInfo airtaudio::api::Alsa::getDeviceInfo(uint32_t _device) {
|
||||
airtaudio::DeviceInfo info;
|
||||
/*
|
||||
ATA_WARNING("plop");
|
||||
getDeviceInfo("hw:0,0,0", info);
|
||||
info.display();
|
||||
getDeviceInfo("hw:0,0,1", info);
|
||||
info.display();
|
||||
*/
|
||||
info.probed = false;
|
||||
unsigned nDevices = 0;
|
||||
int32_t result, subdevice, card;
|
||||
int32_t result = -1;
|
||||
int32_t subdevice = -1;
|
||||
int32_t card = -1;
|
||||
char name[64];
|
||||
snd_ctl_t *chandle;
|
||||
// Count cards and devices
|
||||
@ -354,12 +369,12 @@ airtaudio::DeviceInfo airtaudio::api::Alsa::getDeviceInfo(uint32_t _device) {
|
||||
}
|
||||
|
||||
foundDevice:
|
||||
snd_ctl_close(chandle);
|
||||
// If a stream is already open, we cannot probe the stream devices.
|
||||
// Thus, use the saved results.
|
||||
if ( m_state != airtaudio::state_closed
|
||||
&& ( m_device[0] == _device
|
||||
|| m_device[1] == _device)) {
|
||||
snd_ctl_close(chandle);
|
||||
if (_device >= m_devices.size()) {
|
||||
ATA_ERROR("device ID was not present before stream was opened.");
|
||||
// TODO : return airtaudio::error_warning;
|
||||
@ -367,204 +382,11 @@ foundDevice:
|
||||
}
|
||||
return m_devices[ _device ];
|
||||
}
|
||||
bool ret = airtaudio::api::Alsa::getDeviceInfo(name, info);
|
||||
|
||||
int32_t openMode = SND_PCM_ASYNC;
|
||||
snd_pcm_stream_t stream;
|
||||
snd_pcm_info_t *pcminfo;
|
||||
snd_pcm_info_alloca(&pcminfo);
|
||||
snd_pcm_t *phandle;
|
||||
snd_pcm_hw_params_t *params;
|
||||
snd_pcm_hw_params_alloca(¶ms);
|
||||
// First try for playback unless default _device (which has subdev -1)
|
||||
stream = SND_PCM_STREAM_PLAYBACK;
|
||||
snd_pcm_info_set_stream(pcminfo, stream);
|
||||
if (subdevice != -1) {
|
||||
snd_pcm_info_set_device(pcminfo, subdevice);
|
||||
snd_pcm_info_set_subdevice(pcminfo, 0);
|
||||
result = snd_ctl_pcm_info(chandle, pcminfo);
|
||||
if (result < 0) {
|
||||
// Device probably doesn't support playback.
|
||||
goto captureProbe;
|
||||
}
|
||||
}
|
||||
result = snd_pcm_open(&phandle, name, stream, openMode | SND_PCM_NONBLOCK);
|
||||
if (result < 0) {
|
||||
ATA_ERROR("snd_pcm_open error for device (" << name << "), " << snd_strerror(result) << ".");
|
||||
// TODO : Return airtaudio::error_warning;
|
||||
goto captureProbe;
|
||||
}
|
||||
// The device is open ... fill the parameter structure.
|
||||
result = snd_pcm_hw_params_any(phandle, params);
|
||||
if (result < 0) {
|
||||
snd_pcm_close(phandle);
|
||||
ATA_ERROR("snd_pcm_hw_params error for device (" << name << "), " << snd_strerror(result) << ".");
|
||||
// TODO : Return airtaudio::error_warning;
|
||||
goto captureProbe;
|
||||
}
|
||||
// Get output channel information.
|
||||
uint32_t value;
|
||||
result = snd_pcm_hw_params_get_channels_max(params, &value);
|
||||
if (result < 0) {
|
||||
snd_pcm_close(phandle);
|
||||
ATA_ERROR("error getting device (" << name << ") output channels, " << snd_strerror(result) << ".");
|
||||
// TODO : Return airtaudio::error_warning;
|
||||
goto captureProbe;
|
||||
}
|
||||
info.outputChannels = value;
|
||||
snd_pcm_close(phandle);
|
||||
|
||||
captureProbe:
|
||||
stream = SND_PCM_STREAM_CAPTURE;
|
||||
snd_pcm_info_set_stream(pcminfo, stream);
|
||||
// Now try for capture unless default device (with subdev = -1)
|
||||
if (subdevice != -1) {
|
||||
result = snd_ctl_pcm_info(chandle, pcminfo);
|
||||
snd_ctl_close(chandle);
|
||||
if (result < 0) {
|
||||
// Device probably doesn't support capture.
|
||||
if (info.outputChannels == 0) {
|
||||
return info;
|
||||
}
|
||||
goto probeParameters;
|
||||
}
|
||||
}
|
||||
result = snd_pcm_open(&phandle, name, stream, openMode | SND_PCM_NONBLOCK);
|
||||
if (result < 0) {
|
||||
ATA_ERROR("snd_pcm_open error for device (" << name << "), " << snd_strerror(result) << ".");
|
||||
// TODO : Return airtaudio::error_warning;
|
||||
if (info.outputChannels == 0) {
|
||||
return info;
|
||||
}
|
||||
goto probeParameters;
|
||||
}
|
||||
// The device is open ... fill the parameter structure.
|
||||
result = snd_pcm_hw_params_any(phandle, params);
|
||||
if (result < 0) {
|
||||
snd_pcm_close(phandle);
|
||||
ATA_ERROR("snd_pcm_hw_params error for device (" << name << "), " << snd_strerror(result) << ".");
|
||||
// TODO : Return airtaudio::error_warning;
|
||||
if (info.outputChannels == 0) {
|
||||
return info;
|
||||
}
|
||||
goto probeParameters;
|
||||
}
|
||||
result = snd_pcm_hw_params_get_channels_max(params, &value);
|
||||
if (result < 0) {
|
||||
snd_pcm_close(phandle);
|
||||
ATA_ERROR("error getting device (" << name << ") input channels, " << snd_strerror(result) << ".");
|
||||
// TODO : Return airtaudio::error_warning;
|
||||
if (info.outputChannels == 0) {
|
||||
return info;
|
||||
}
|
||||
goto probeParameters;
|
||||
}
|
||||
info.inputChannels = value;
|
||||
snd_pcm_close(phandle);
|
||||
// If device opens for both playback and capture, we determine the channels.
|
||||
if (info.outputChannels > 0 && info.inputChannels > 0) {
|
||||
info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels;
|
||||
}
|
||||
// ALSA doesn't provide default devices so we'll use the first available one.
|
||||
if (_device == 0 && info.outputChannels > 0) {
|
||||
info.isDefaultOutput = true;
|
||||
}
|
||||
if (_device == 0 && info.inputChannels > 0) {
|
||||
info.isDefaultInput = true;
|
||||
}
|
||||
|
||||
probeParameters:
|
||||
// At this point, we just need to figure out the supported data
|
||||
// formats and sample rates. We'll proceed by opening the device in
|
||||
// the direction with the maximum number of channels, or playback if
|
||||
// they are equal. This might limit our sample rate options, but so
|
||||
// be it.
|
||||
if (info.outputChannels >= info.inputChannels) {
|
||||
stream = SND_PCM_STREAM_PLAYBACK;
|
||||
} else {
|
||||
stream = SND_PCM_STREAM_CAPTURE;
|
||||
}
|
||||
snd_pcm_info_set_stream(pcminfo, stream);
|
||||
result = snd_pcm_open(&phandle, name, stream, openMode | SND_PCM_NONBLOCK);
|
||||
if (result < 0) {
|
||||
ATA_ERROR("snd_pcm_open error for device (" << name << "), " << snd_strerror(result) << ".");
|
||||
// TODO : Return airtaudio::error_warning;
|
||||
bool ret = airtaudio::api::Alsa::getNamedDeviceInfoLocal(name, info, card, subdevice, _device);
|
||||
if (ret == false) {
|
||||
// TODO : ...
|
||||
return info;
|
||||
}
|
||||
// The device is open ... fill the parameter structure.
|
||||
result = snd_pcm_hw_params_any(phandle, params);
|
||||
if (result < 0) {
|
||||
snd_pcm_close(phandle);
|
||||
ATA_ERROR("snd_pcm_hw_params error for device (" << name << "), " << snd_strerror(result) << ".");
|
||||
// TODO : Return airtaudio::error_warning;
|
||||
return info;
|
||||
}
|
||||
// Test our discrete set of sample rate values.
|
||||
info.sampleRates.clear();
|
||||
#if __CPP_VERSION__ >= 2011
|
||||
for (auto &it : airtaudio::genericSampleRate()) {
|
||||
if (snd_pcm_hw_params_test_rate(phandle, params, it, 0) == 0) {
|
||||
info.sampleRates.push_back(it);
|
||||
}
|
||||
}
|
||||
#else
|
||||
for (std::vector<uint32_t>::const_iterator it(airtaudio::genericSampleRate().begin());
|
||||
it != airtaudio::genericSampleRate().end();
|
||||
++it ) {
|
||||
if (snd_pcm_hw_params_test_rate(phandle, params, *it, 0) == 0) {
|
||||
info.sampleRates.push_back(*it);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (info.sampleRates.size() == 0) {
|
||||
snd_pcm_close(phandle);
|
||||
ATA_ERROR("no supported sample rates found for device (" << name << ").");
|
||||
// TODO : Return airtaudio::error_warning;
|
||||
return info;
|
||||
}
|
||||
// Probe the supported data formats ... we don't care about endian-ness just yet
|
||||
snd_pcm_format_t format;
|
||||
info.nativeFormats.clear();
|
||||
format = SND_PCM_FORMAT_S8;
|
||||
if (snd_pcm_hw_params_test_format(phandle, params, format) == 0) {
|
||||
info.nativeFormats.push_back(audio::format_int8);
|
||||
}
|
||||
format = SND_PCM_FORMAT_S16;
|
||||
if (snd_pcm_hw_params_test_format(phandle, params, format) == 0) {
|
||||
info.nativeFormats.push_back(audio::format_int16);
|
||||
}
|
||||
format = SND_PCM_FORMAT_S24;
|
||||
if (snd_pcm_hw_params_test_format(phandle, params, format) == 0) {
|
||||
info.nativeFormats.push_back(audio::format_int24);
|
||||
}
|
||||
format = SND_PCM_FORMAT_S32;
|
||||
if (snd_pcm_hw_params_test_format(phandle, params, format) == 0) {
|
||||
info.nativeFormats.push_back(audio::format_int32);
|
||||
}
|
||||
format = SND_PCM_FORMAT_FLOAT;
|
||||
if (snd_pcm_hw_params_test_format(phandle, params, format) == 0) {
|
||||
info.nativeFormats.push_back(audio::format_float);
|
||||
}
|
||||
format = SND_PCM_FORMAT_FLOAT64;
|
||||
if (snd_pcm_hw_params_test_format(phandle, params, format) == 0) {
|
||||
info.nativeFormats.push_back(audio::format_double);
|
||||
}
|
||||
// Check that we have at least one supported format
|
||||
if (info.nativeFormats.size() == 0) {
|
||||
ATA_ERROR("pcm device (" << name << ") data format not supported by RtAudio.");
|
||||
// TODO : Return airtaudio::error_warning;
|
||||
return info;
|
||||
}
|
||||
// Get the device name
|
||||
char *cardname;
|
||||
result = snd_card_get_name(card, &cardname);
|
||||
if (result >= 0) {
|
||||
sprintf(name, "hw:%s,%d", cardname, subdevice);
|
||||
}
|
||||
info.name = name;
|
||||
// That's all ... close the device and return
|
||||
snd_pcm_close(phandle);
|
||||
info.probed = true;
|
||||
return info;
|
||||
}
|
||||
|
||||
@ -616,14 +438,6 @@ bool airtaudio::api::Alsa::probeDeviceOpen(uint32_t _device,
|
||||
snd_ctl_close(chandle);
|
||||
snd_card_next(&card);
|
||||
}
|
||||
result = snd_ctl_open(&chandle, "default", SND_CTL_NONBLOCK);
|
||||
if (result == 0) {
|
||||
if (nDevices == _device) {
|
||||
strcpy(name, "default");
|
||||
goto foundDevice;
|
||||
}
|
||||
nDevices++;
|
||||
}
|
||||
if (nDevices == 0) {
|
||||
// This should not happen because a check is made before this function is called.
|
||||
ATA_ERROR("no devices found!");
|
||||
@ -637,6 +451,23 @@ bool airtaudio::api::Alsa::probeDeviceOpen(uint32_t _device,
|
||||
// NOTE : Find the device name : [ END ]
|
||||
|
||||
foundDevice:
|
||||
return probeDeviceOpenName(name, _mode, _channels, _firstChannel, _sampleRate, _format, _bufferSize, _options);
|
||||
}
|
||||
|
||||
bool airtaudio::api::Alsa::probeDeviceOpenName(const std::string& _deviceName,
|
||||
airtaudio::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
airtaudio::StreamOptions *_options) {
|
||||
// I'm not using the "plug" interface ... too much inconsistent behavior.
|
||||
unsigned nDevices = 0;
|
||||
int32_t result, subdevice, card;
|
||||
char name[64];
|
||||
snd_ctl_t *chandle;
|
||||
|
||||
// The getDeviceInfo() function will not work for a device that is
|
||||
// already open. Thus, we'll probe the system before opening a
|
||||
// stream and save the results for use by getDeviceInfo().
|
||||
@ -654,12 +485,12 @@ foundDevice:
|
||||
}
|
||||
snd_pcm_t *phandle;
|
||||
int32_t openMode = SND_PCM_ASYNC;
|
||||
result = snd_pcm_open(&phandle, name, stream, openMode);
|
||||
result = snd_pcm_open(&phandle, _deviceName.c_str(), stream, openMode);
|
||||
if (result < 0) {
|
||||
if (_mode == airtaudio::mode_output) {
|
||||
ATA_ERROR("pcm device (" << name << ") won't open for output.");
|
||||
ATA_ERROR("pcm device (" << _deviceName << ") won't open for output.");
|
||||
} else {
|
||||
ATA_ERROR("pcm device (" << name << ") won't open for input.");
|
||||
ATA_ERROR("pcm device (" << _deviceName << ") won't open for input.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -669,7 +500,7 @@ foundDevice:
|
||||
result = snd_pcm_hw_params_any(phandle, hw_params);
|
||||
if (result < 0) {
|
||||
snd_pcm_close(phandle);
|
||||
ATA_ERROR("error getting pcm device (" << name << ") parameters, " << snd_strerror(result) << ".");
|
||||
ATA_ERROR("error getting pcm device (" << _deviceName << ") parameters, " << snd_strerror(result) << ".");
|
||||
return false;
|
||||
}
|
||||
// Open stream all time in interleave mode (by default): (open in non interleave if we have no choice
|
||||
@ -682,7 +513,7 @@ foundDevice:
|
||||
}
|
||||
if (result < 0) {
|
||||
snd_pcm_close(phandle);
|
||||
ATA_ERROR("error setting pcm device (" << name << ") access, " << snd_strerror(result) << ".");
|
||||
ATA_ERROR("error setting pcm device (" << _deviceName << ") access, " << snd_strerror(result) << ".");
|
||||
return false;
|
||||
}
|
||||
// Determine how to set the device format.
|
||||
@ -706,14 +537,14 @@ foundDevice:
|
||||
} else {
|
||||
// If we get here, no supported format was found.
|
||||
snd_pcm_close(phandle);
|
||||
ATA_ERROR("pcm device " << _device << " data format not supported: " << _format);
|
||||
ATA_ERROR("pcm device " << _deviceName << " data format not supported: " << _format);
|
||||
// TODO : display list of all supported format ..
|
||||
return false;
|
||||
}
|
||||
result = snd_pcm_hw_params_set_format(phandle, hw_params, deviceFormat);
|
||||
if (result < 0) {
|
||||
snd_pcm_close(phandle);
|
||||
ATA_ERROR("error setting pcm device (" << name << ") data format, " << snd_strerror(result) << ".");
|
||||
ATA_ERROR("error setting pcm device (" << _deviceName << ") data format, " << snd_strerror(result) << ".");
|
||||
return false;
|
||||
}
|
||||
// Determine whether byte-swaping is necessary.
|
||||
@ -724,7 +555,7 @@ foundDevice:
|
||||
m_doByteSwap[modeToIdTable(_mode)] = true;
|
||||
} else if (result < 0) {
|
||||
snd_pcm_close(phandle);
|
||||
ATA_ERROR("error getting pcm device (" << name << ") endian-ness, " << snd_strerror(result) << ".");
|
||||
ATA_ERROR("error getting pcm device (" << _deviceName << ") endian-ness, " << snd_strerror(result) << ".");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -732,7 +563,7 @@ foundDevice:
|
||||
result = snd_pcm_hw_params_set_rate_near(phandle, hw_params, (uint32_t*) &_sampleRate, 0);
|
||||
if (result < 0) {
|
||||
snd_pcm_close(phandle);
|
||||
ATA_ERROR("error setting sample rate on device (" << name << "), " << snd_strerror(result) << ".");
|
||||
ATA_ERROR("error setting sample rate on device (" << _deviceName << "), " << snd_strerror(result) << ".");
|
||||
return false;
|
||||
}
|
||||
// Determine the number of channels for this device. We support a possible
|
||||
@ -744,13 +575,13 @@ foundDevice:
|
||||
if ( result < 0
|
||||
|| deviceChannels < _channels + _firstChannel) {
|
||||
snd_pcm_close(phandle);
|
||||
ATA_ERROR("requested channel parameters not supported by device (" << name << "), " << snd_strerror(result) << ".");
|
||||
ATA_ERROR("requested channel parameters not supported by device (" << _deviceName << "), " << snd_strerror(result) << ".");
|
||||
return false;
|
||||
}
|
||||
result = snd_pcm_hw_params_get_channels_min(hw_params, &value);
|
||||
if (result < 0) {
|
||||
snd_pcm_close(phandle);
|
||||
ATA_ERROR("error getting minimum channels for device (" << name << "), " << snd_strerror(result) << ".");
|
||||
ATA_ERROR("error getting minimum channels for device (" << _deviceName << "), " << snd_strerror(result) << ".");
|
||||
return false;
|
||||
}
|
||||
deviceChannels = value;
|
||||
@ -762,7 +593,7 @@ foundDevice:
|
||||
result = snd_pcm_hw_params_set_channels(phandle, hw_params, deviceChannels);
|
||||
if (result < 0) {
|
||||
snd_pcm_close(phandle);
|
||||
ATA_ERROR("error setting channels for device (" << name << "), " << snd_strerror(result) << ".");
|
||||
ATA_ERROR("error setting channels for device (" << _deviceName << "), " << snd_strerror(result) << ".");
|
||||
return false;
|
||||
}
|
||||
// Set the buffer (or period) size.
|
||||
@ -771,7 +602,7 @@ foundDevice:
|
||||
result = snd_pcm_hw_params_set_period_size_near(phandle, hw_params, &periodSize, &dir);
|
||||
if (result < 0) {
|
||||
snd_pcm_close(phandle);
|
||||
ATA_ERROR("error setting period size for device (" << name << "), " << snd_strerror(result) << ".");
|
||||
ATA_ERROR("error setting period size for device (" << _deviceName << "), " << snd_strerror(result) << ".");
|
||||
return false;
|
||||
}
|
||||
*_bufferSize = periodSize;
|
||||
@ -793,7 +624,7 @@ foundDevice:
|
||||
result = snd_pcm_hw_params_set_periods_near(phandle, hw_params, &periods, &dir);
|
||||
if (result < 0) {
|
||||
snd_pcm_close(phandle);
|
||||
ATA_ERROR("error setting periods for device (" << name << "), " << snd_strerror(result) << ".");
|
||||
ATA_ERROR("error setting periods for device (" << _deviceName << "), " << snd_strerror(result) << ".");
|
||||
return false;
|
||||
}
|
||||
// If attempting to setup a duplex stream, the bufferSize parameter
|
||||
@ -802,7 +633,7 @@ foundDevice:
|
||||
&& _mode == airtaudio::mode_input
|
||||
&& *_bufferSize != m_bufferSize) {
|
||||
snd_pcm_close(phandle);
|
||||
ATA_ERROR("system error setting buffer size for duplex stream on device (" << name << ").");
|
||||
ATA_ERROR("system error setting buffer size for duplex stream on device (" << _deviceName << ").");
|
||||
return false;
|
||||
}
|
||||
m_bufferSize = *_bufferSize;
|
||||
@ -819,7 +650,7 @@ foundDevice:
|
||||
result = snd_pcm_hw_params(phandle, hw_params);
|
||||
if (result < 0) {
|
||||
snd_pcm_close(phandle);
|
||||
ATA_ERROR("error installing hardware configuration on device (" << name << "), " << snd_strerror(result) << ".");
|
||||
ATA_ERROR("error installing hardware configuration on device (" << _deviceName << "), " << snd_strerror(result) << ".");
|
||||
return false;
|
||||
}
|
||||
// Set the software configuration to fill buffers with zeros and prevent device stopping on xruns.
|
||||
@ -841,7 +672,7 @@ foundDevice:
|
||||
result = snd_pcm_sw_params(phandle, swParams);
|
||||
if (result < 0) {
|
||||
snd_pcm_close(phandle);
|
||||
ATA_ERROR("error installing software configuration on device (" << name << "), " << snd_strerror(result) << ".");
|
||||
ATA_ERROR("error installing software configuration on device (" << _deviceName << "), " << snd_strerror(result) << ".");
|
||||
return false;
|
||||
}
|
||||
// Set flags for buffer conversion
|
||||
@ -893,7 +724,7 @@ foundDevice:
|
||||
}
|
||||
m_sampleRate = _sampleRate;
|
||||
m_nBuffers = periods;
|
||||
m_device[modeToIdTable(_mode)] = _device;
|
||||
// TODO : m_device[modeToIdTable(_mode)] = _device;
|
||||
m_state = airtaudio::state_stopped;
|
||||
// Setup the buffer conversion information structure.
|
||||
if (m_doConvertBuffer[modeToIdTable(_mode)]) {
|
||||
|
@ -21,7 +21,16 @@ namespace airtaudio {
|
||||
return airtaudio::type_alsa;
|
||||
}
|
||||
uint32_t getDeviceCount();
|
||||
bool getDeviceInfo(const std::string& _deviceName, airtaudio::DeviceInfo& _info);
|
||||
private:
|
||||
bool getNamedDeviceInfoLocal(const std::string& _deviceName,
|
||||
airtaudio::DeviceInfo& _info,
|
||||
int32_t _cardId=-1, // Alsa card ID
|
||||
int32_t _subdevice=-1, // alsa subdevice ID
|
||||
int32_t _localDeviceId=-1); // local ID of device fined
|
||||
public:
|
||||
bool getNamedDeviceInfo(const std::string& _deviceName, airtaudio::DeviceInfo& _info) {
|
||||
return getNamedDeviceInfoLocal(_deviceName, _info);
|
||||
}
|
||||
airtaudio::DeviceInfo getDeviceInfo(uint32_t _device);
|
||||
enum airtaudio::error closeStream();
|
||||
enum airtaudio::error startStream();
|
||||
@ -47,6 +56,15 @@ namespace airtaudio {
|
||||
enum audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
airtaudio::StreamOptions *_options);
|
||||
|
||||
virtual bool probeDeviceOpenName(const std::string& _deviceName,
|
||||
airtaudio::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
airtaudio::StreamOptions *_options);
|
||||
virtual std11::chrono::system_clock::time_point getStreamTime();
|
||||
};
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user