[DEV] rework Airtaudio in audioo::orchestra
This commit is contained in:
parent
d4c53a53bf
commit
f5c3affccb
178
airtaudio/Api.h
178
airtaudio/Api.h
@ -1,178 +0,0 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#ifndef __AIRTAUDIO_API_H__
|
||||
#define __AIRTAUDIO_API_H__
|
||||
|
||||
#include <sstream>
|
||||
#include <airtaudio/debug.h>
|
||||
#include <airtaudio/type.h>
|
||||
#include <airtaudio/state.h>
|
||||
#include <airtaudio/mode.h>
|
||||
|
||||
namespace airtaudio {
|
||||
const std::vector<uint32_t>& genericSampleRate();
|
||||
|
||||
/**
|
||||
* @brief airtaudio callback function prototype.
|
||||
* @param _inputBuffer For input (or duplex) streams, this buffer will hold _nbChunk of input audio chunk (nullptr if no data).
|
||||
* @param _timeInput Timestamp of the first buffer sample (recording time).
|
||||
* @param _outputBuffer For output (or duplex) streams, the client should write _nbChunk of audio chunk into this buffer (nullptr if no data).
|
||||
* @param _timeOutput Timestamp of the first buffer sample (playing time).
|
||||
* @param _nbChunk The number of chunk of input or output chunk in the buffer (same size).
|
||||
* @param _status List of error that occured in the laps of time.
|
||||
*/
|
||||
typedef std11::function<int32_t (const void* _inputBuffer,
|
||||
const std11::chrono::system_clock::time_point& _timeInput,
|
||||
void* _outputBuffer,
|
||||
const std11::chrono::system_clock::time_point& _timeOutput,
|
||||
uint32_t _nbChunk,
|
||||
const std::vector<airtaudio::status>& _status)> AirTAudioCallback;
|
||||
// A protected structure used for buffer conversion.
|
||||
class ConvertInfo {
|
||||
public:
|
||||
int32_t channels;
|
||||
int32_t inJump;
|
||||
int32_t outJump;
|
||||
enum audio::format inFormat;
|
||||
enum audio::format outFormat;
|
||||
std::vector<int> inOffset;
|
||||
std::vector<int> outOffset;
|
||||
};
|
||||
|
||||
class Api {
|
||||
protected:
|
||||
std::string m_name;
|
||||
public:
|
||||
Api();
|
||||
virtual ~Api();
|
||||
void setName(const std::string& _name) {
|
||||
m_name = _name;
|
||||
}
|
||||
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,
|
||||
airtaudio::StreamParameters* _inputParameters,
|
||||
audio::format _format,
|
||||
uint32_t _sampleRate,
|
||||
uint32_t* _nbChunk,
|
||||
airtaudio::AirTAudioCallback _callback,
|
||||
const airtaudio::StreamOptions& _options);
|
||||
virtual enum airtaudio::error closeStream();
|
||||
virtual enum airtaudio::error startStream();
|
||||
virtual enum airtaudio::error stopStream() = 0;
|
||||
virtual enum airtaudio::error abortStream() = 0;
|
||||
long getStreamLatency();
|
||||
uint32_t getStreamSampleRate();
|
||||
virtual std11::chrono::system_clock::time_point getStreamTime();
|
||||
bool isStreamOpen() const {
|
||||
return m_state != airtaudio::state_closed;
|
||||
}
|
||||
bool isStreamRunning() const {
|
||||
return m_state == airtaudio::state_running;
|
||||
}
|
||||
|
||||
protected:
|
||||
mutable std11::mutex m_mutex;
|
||||
airtaudio::AirTAudioCallback m_callback;
|
||||
uint32_t m_device[2]; // Playback and record, respectively.
|
||||
enum airtaudio::mode m_mode; // airtaudio::mode_output, airtaudio::mode_input, or airtaudio::mode_duplex.
|
||||
enum airtaudio::state m_state; // STOPPED, RUNNING, or CLOSED
|
||||
std::vector<char> m_userBuffer[2]; // Playback and record, respectively.
|
||||
char *m_deviceBuffer;
|
||||
bool m_doConvertBuffer[2]; // Playback and record, respectively.
|
||||
bool m_deviceInterleaved[2]; // Playback and record, respectively.
|
||||
bool m_doByteSwap[2]; // Playback and record, respectively.
|
||||
uint32_t m_sampleRate; // TODO : Rename frequency
|
||||
uint32_t m_bufferSize;
|
||||
uint32_t m_nBuffers;
|
||||
uint32_t m_nUserChannels[2]; // Playback and record, respectively. // TODO : set only one config (open inout with the same number of channels (limitation)
|
||||
uint32_t m_nDeviceChannels[2]; // Playback and record channels, respectively.
|
||||
uint32_t m_channelOffset[2]; // Playback and record, respectively.
|
||||
uint64_t m_latency[2]; // Playback and record, respectively.
|
||||
enum audio::format m_userFormat; // TODO : Remove this ==> use can only open in the Harware format ...
|
||||
enum audio::format m_deviceFormat[2]; // Playback and record, respectively.
|
||||
airtaudio::ConvertInfo m_convertInfo[2];
|
||||
|
||||
//std11::chrono::system_clock::time_point
|
||||
std11::chrono::system_clock::time_point m_startTime; //!< start time of the stream (restart at every stop, pause ...)
|
||||
std11::chrono::nanoseconds m_duration; //!< duration from wich the stream is started
|
||||
|
||||
/**
|
||||
* @brief api-specific method that attempts to open a device
|
||||
* with the given parameters. This function MUST be implemented by
|
||||
* all subclasses. If an error is encountered during the probe, a
|
||||
* "warning" message is reported and false is returned. A
|
||||
* successful probe is indicated by a return value of true.
|
||||
*/
|
||||
virtual bool probeDeviceOpen(uint32_t _device,
|
||||
enum airtaudio::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
enum audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const 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,
|
||||
const airtaudio::StreamOptions& _options) { return false; }
|
||||
/**
|
||||
* @brief Increment the stream time.
|
||||
*/
|
||||
void tickStreamTime();
|
||||
/**
|
||||
* @brief Clear an RtApiStream structure.
|
||||
*/
|
||||
void clearStreamInfo();
|
||||
/**
|
||||
* @brief Check the current stream status
|
||||
*/
|
||||
enum airtaudio::error verifyStream();
|
||||
/**
|
||||
* @brief Protected method used to perform format, channel number, and/or interleaving
|
||||
* conversions between the user and device buffers.
|
||||
*/
|
||||
void convertBuffer(char *_outBuffer,
|
||||
char *_inBuffer,
|
||||
airtaudio::ConvertInfo& _info);
|
||||
|
||||
/**
|
||||
* @brief Perform byte-swapping on buffers.
|
||||
*/
|
||||
void byteSwapBuffer(char *_buffer,
|
||||
uint32_t _samples,
|
||||
enum audio::format _format);
|
||||
/**
|
||||
* @brief Sets up the parameters for buffer conversion.
|
||||
*/
|
||||
void setConvertInfo(enum airtaudio::mode _mode,
|
||||
uint32_t _firstChannel);
|
||||
|
||||
public:
|
||||
virtual bool isMasterOf(airtaudio::Api* _api) {
|
||||
return false;
|
||||
};
|
||||
};
|
||||
};
|
||||
/**
|
||||
* @brief Debug operator To display the curent element in a Human redeable information
|
||||
*/
|
||||
std::ostream& operator <<(std::ostream& _os, const airtaudio::type& _obj);
|
||||
|
||||
#endif
|
@ -1,43 +0,0 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#ifndef __AIRTAUDIO_DEVICE_INFO_H__
|
||||
#define __AIRTAUDIO_DEVICE_INFO_H__
|
||||
|
||||
#include <audio/format.h>
|
||||
|
||||
namespace airtaudio {
|
||||
/**
|
||||
* @brief The public device information structure for returning queried values.
|
||||
*/
|
||||
class DeviceInfo {
|
||||
public:
|
||||
bool probed; //!< true if the device capabilities were successfully probed.
|
||||
std::string name; //!< Character string device identifier.
|
||||
uint32_t outputChannels; //!< Maximum output channels supported by device.
|
||||
uint32_t inputChannels; //!< Maximum input channels supported by device.
|
||||
uint32_t duplexChannels; //!< Maximum simultaneous input/output channels supported by device.
|
||||
bool isDefaultOutput; //!< true if this is the default output device.
|
||||
bool isDefaultInput; //!< true if this is the default input device.
|
||||
std::vector<uint32_t> sampleRates; //!< Supported sample rates (queried from list of standard rates).
|
||||
std::vector<audio::format> nativeFormats; //!< Bit mask of supported data formats.
|
||||
// Default constructor.
|
||||
DeviceInfo() :
|
||||
probed(false),
|
||||
outputChannels(0),
|
||||
inputChannels(0),
|
||||
duplexChannels(0),
|
||||
isDefaultOutput(false),
|
||||
isDefaultInput(false),
|
||||
nativeFormats() {}
|
||||
void display(int32_t _tabNumber = 1) const;
|
||||
};
|
||||
std::ostream& operator <<(std::ostream& _os, const airtaudio::DeviceInfo& _obj);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -1,24 +0,0 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#ifndef __AIRTAUDIO_FLAGS_H__
|
||||
#define __AIRTAUDIO_FLAGS_H__
|
||||
|
||||
#include <etk/types.h>
|
||||
|
||||
namespace airtaudio {
|
||||
class Flags {
|
||||
public:
|
||||
bool m_minimizeLatency; // Simple example ==> TODO ...
|
||||
Flags() :
|
||||
m_minimizeLatency(false) {
|
||||
// nothing to do ...
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
@ -1,184 +0,0 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
//#include <etk/types.h>
|
||||
#include <airtaudio/Interface.h>
|
||||
#include <airtaudio/debug.h>
|
||||
#include <iostream>
|
||||
|
||||
#undef __class__
|
||||
#define __class__ "Interface"
|
||||
|
||||
std::vector<enum airtaudio::type> airtaudio::Interface::getCompiledApi() {
|
||||
std::vector<enum airtaudio::type> apis;
|
||||
// The order here will control the order of RtAudio's API search in
|
||||
// the constructor.
|
||||
for (size_t iii=0; iii<m_apiAvaillable.size(); ++iii) {
|
||||
apis.push_back(m_apiAvaillable[iii].first);
|
||||
}
|
||||
return apis;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void airtaudio::Interface::openRtApi(enum airtaudio::type _api) {
|
||||
delete m_rtapi;
|
||||
m_rtapi = nullptr;
|
||||
for (size_t iii=0; iii<m_apiAvaillable.size(); ++iii) {
|
||||
ATA_INFO("try open " << m_apiAvaillable[iii].first);
|
||||
if (_api == m_apiAvaillable[iii].first) {
|
||||
ATA_INFO(" ==> call it");
|
||||
m_rtapi = m_apiAvaillable[iii].second();
|
||||
if (m_rtapi != nullptr) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO : An error occured ...
|
||||
ATA_ERROR("Error in open API ...");
|
||||
}
|
||||
|
||||
|
||||
airtaudio::Interface::Interface() :
|
||||
m_rtapi(nullptr) {
|
||||
ATA_DEBUG("Add interface:");
|
||||
#if defined(__UNIX_JACK__)
|
||||
ATA_DEBUG(" JACK");
|
||||
addInterface(airtaudio::type_jack, airtaudio::api::Jack::Create);
|
||||
#endif
|
||||
#if defined(__LINUX_ALSA__)
|
||||
ATA_DEBUG(" ALSA");
|
||||
addInterface(airtaudio::type_alsa, airtaudio::api::Alsa::Create);
|
||||
#endif
|
||||
#if defined(__LINUX_PULSE__)
|
||||
ATA_DEBUG(" PULSE");
|
||||
addInterface(airtaudio::type_pulse, airtaudio::api::Pulse::Create);
|
||||
#endif
|
||||
#if defined(__LINUX_OSS__)
|
||||
ATA_DEBUG(" OSS");
|
||||
addInterface(airtaudio::type_oss, airtaudio::api::Oss::Create);
|
||||
#endif
|
||||
#if defined(__WINDOWS_ASIO__)
|
||||
ATA_DEBUG(" ASIO");
|
||||
addInterface(airtaudio::type_asio, airtaudio::api::Asio::Create);
|
||||
#endif
|
||||
#if defined(__WINDOWS_DS__)
|
||||
ATA_DEBUG(" DS");
|
||||
addInterface(airtaudio::type_ds, airtaudio::api::Ds::Create);
|
||||
#endif
|
||||
#if defined(__MACOSX_CORE__)
|
||||
ATA_DEBUG(" CORE OSX");
|
||||
addInterface(airtaudio::type_coreOSX, airtaudio::api::Core::Create);
|
||||
#endif
|
||||
#if defined(__IOS_CORE__)
|
||||
ATA_DEBUG(" CORE IOS");
|
||||
addInterface(airtaudio::type_coreIOS, airtaudio::api::CoreIos::Create);
|
||||
#endif
|
||||
#if defined(__ANDROID_JAVA__)
|
||||
ATA_DEBUG(" JAVA");
|
||||
addInterface(airtaudio::type_java, airtaudio::api::Android::Create);
|
||||
#endif
|
||||
#if defined(__AIRTAUDIO_DUMMY__)
|
||||
ATA_DEBUG(" DUMMY");
|
||||
addInterface(airtaudio::type_dummy, airtaudio::api::Dummy::Create);
|
||||
#endif
|
||||
}
|
||||
|
||||
void airtaudio::Interface::addInterface(enum airtaudio::type _api, Api* (*_callbackCreate)()) {
|
||||
m_apiAvaillable.push_back(std::pair<enum airtaudio::type, Api* (*)()>(_api, _callbackCreate));
|
||||
}
|
||||
|
||||
enum airtaudio::error airtaudio::Interface::instanciate(enum airtaudio::type _api) {
|
||||
ATA_INFO("Instanciate API ...");
|
||||
if (m_rtapi != nullptr) {
|
||||
ATA_WARNING("Interface already started ...!");
|
||||
return airtaudio::error_none;
|
||||
}
|
||||
if (_api != airtaudio::type_undefined) {
|
||||
ATA_INFO("API specified : " << _api);
|
||||
// Attempt to open the specified API.
|
||||
openRtApi(_api);
|
||||
if (m_rtapi != nullptr) {
|
||||
if (m_rtapi->getDeviceCount() != 0) {
|
||||
ATA_INFO(" ==> api open");
|
||||
}
|
||||
return airtaudio::error_none;
|
||||
}
|
||||
// No compiled support for specified API value. Issue a debug
|
||||
// warning and continue as if no API was specified.
|
||||
ATA_ERROR("RtAudio: no compiled support for specified API argument!");
|
||||
return airtaudio::error_fail;
|
||||
}
|
||||
ATA_INFO("Auto choice API :");
|
||||
// Iterate through the compiled APIs and return as soon as we find
|
||||
// one with at least one device or we reach the end of the list.
|
||||
std::vector<enum airtaudio::type> apis = getCompiledApi();
|
||||
ATA_INFO(" find : " << apis.size() << " apis.");
|
||||
for (size_t iii=0; iii<apis.size(); ++iii) {
|
||||
ATA_INFO("try open ...");
|
||||
openRtApi(apis[iii]);
|
||||
if(m_rtapi == nullptr) {
|
||||
ATA_ERROR(" ==> can not create ...");
|
||||
continue;
|
||||
}
|
||||
if (m_rtapi->getDeviceCount() != 0) {
|
||||
ATA_INFO(" ==> api open");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (m_rtapi != nullptr) {
|
||||
return airtaudio::error_none;
|
||||
}
|
||||
ATA_ERROR("RtAudio: no compiled API support found ... critical error!!");
|
||||
return airtaudio::error_fail;
|
||||
}
|
||||
|
||||
airtaudio::Interface::~Interface() {
|
||||
ATA_INFO("Remove interface");
|
||||
delete m_rtapi;
|
||||
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,
|
||||
const airtaudio::StreamOptions& _options) {
|
||||
if (m_rtapi == nullptr) {
|
||||
return airtaudio::error_inputNull;
|
||||
}
|
||||
return m_rtapi->openStream(_outputParameters,
|
||||
_inputParameters,
|
||||
_format,
|
||||
_sampleRate,
|
||||
_bufferFrames,
|
||||
_callback,
|
||||
_options);
|
||||
}
|
||||
|
||||
bool airtaudio::Interface::isMasterOf(airtaudio::Interface& _interface) {
|
||||
if (m_rtapi == nullptr) {
|
||||
ATA_ERROR("Current Master API is nullptr ...");
|
||||
return false;
|
||||
}
|
||||
if (_interface.m_rtapi == nullptr) {
|
||||
ATA_ERROR("Current Slave API is nullptr ...");
|
||||
return false;
|
||||
}
|
||||
if (m_rtapi->getCurrentApi() != _interface.m_rtapi->getCurrentApi()) {
|
||||
ATA_ERROR("Can not link 2 Interface with not the same Low level type (???)");//" << _interface.m_adac->getCurrentApi() << " != " << m_adac->getCurrentApi() << ")");
|
||||
return false;
|
||||
}
|
||||
if (m_rtapi->getCurrentApi() != airtaudio::type_alsa) {
|
||||
ATA_ERROR("Link 2 device together work only if the interafec is ????");// << airtaudio::type_alsa << " not for " << m_rtapi->getCurrentApi());
|
||||
return false;
|
||||
}
|
||||
return m_rtapi->isMasterOf(_interface.m_rtapi);
|
||||
}
|
||||
|
@ -1,317 +0,0 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#ifndef __AIRTAUDIO_INTERFACE_H__
|
||||
#define __AIRTAUDIO_INTERFACE_H__
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <airtaudio/base.h>
|
||||
#include <airtaudio/CallbackInfo.h>
|
||||
#include <airtaudio/Api.h>
|
||||
#include <airtaudio/api/Alsa.h>
|
||||
#include <airtaudio/api/Android.h>
|
||||
#include <airtaudio/api/Asio.h>
|
||||
#include <airtaudio/api/Core.h>
|
||||
#include <airtaudio/api/CoreIos.h>
|
||||
#include <airtaudio/api/Ds.h>
|
||||
#include <airtaudio/api/Dummy.h>
|
||||
#include <airtaudio/api/Jack.h>
|
||||
#include <airtaudio/api/Oss.h>
|
||||
#include <airtaudio/api/Pulse.h>
|
||||
namespace airtaudio {
|
||||
/**
|
||||
* @brief airtaudio::Interface class declaration.
|
||||
*
|
||||
* airtaudio::Interface is a "controller" used to select an available audio i/o
|
||||
* interface. It presents a common API for the user to call but all
|
||||
* functionality is implemented by the class RtApi and its
|
||||
* subclasses. RtAudio creates an instance of an RtApi subclass
|
||||
* based on the user's API choice. If no choice is made, RtAudio
|
||||
* attempts to make a "logical" API selection.
|
||||
*/
|
||||
class Interface {
|
||||
protected:
|
||||
std::vector<std::pair<enum airtaudio::type, Api* (*)()> > m_apiAvaillable;
|
||||
protected:
|
||||
airtaudio::Api *m_rtapi;
|
||||
public:
|
||||
void setName(const std::string& _name) {
|
||||
if (m_rtapi == nullptr) {
|
||||
|
||||
return;
|
||||
}
|
||||
m_rtapi->setName(_name);
|
||||
}
|
||||
/**
|
||||
* @brief A static function to determine the available compiled audio APIs.
|
||||
*
|
||||
* The values returned in the std::vector can be compared against
|
||||
* the enumerated list values. Note that there can be more than one
|
||||
* API compiled for certain operating systems.
|
||||
*/
|
||||
std::vector<enum airtaudio::type> getCompiledApi();
|
||||
/**
|
||||
* @brief The class constructor.
|
||||
* @note the creating of the basic instance is done by Instanciate
|
||||
*/
|
||||
Interface();
|
||||
/**
|
||||
* @brief The destructor.
|
||||
*
|
||||
* If a stream is running or open, it will be stopped and closed
|
||||
* automatically.
|
||||
*/
|
||||
virtual ~Interface();
|
||||
/**
|
||||
* @brief Add an interface of the Possible List.
|
||||
* @param[in] _api Type of the interface.
|
||||
* @param[in] _callbackCreate API creation callback.
|
||||
*/
|
||||
void addInterface(enum airtaudio::type _api, Api* (*_callbackCreate)());
|
||||
/**
|
||||
* @brief Create an interface instance
|
||||
*/
|
||||
enum airtaudio::error instanciate(enum airtaudio::type _api = airtaudio::type_undefined);
|
||||
/**
|
||||
* @return the audio API specifier for the current instance of airtaudio.
|
||||
*/
|
||||
enum airtaudio::type getCurrentApi() {
|
||||
if (m_rtapi == nullptr) {
|
||||
return airtaudio::type_undefined;
|
||||
}
|
||||
return m_rtapi->getCurrentApi();
|
||||
}
|
||||
/**
|
||||
* @brief A public function that queries for the number of audio devices available.
|
||||
*
|
||||
* This function performs a system query of available devices each time it
|
||||
* is called, thus supporting devices connected \e after instantiation. If
|
||||
* a system error occurs during processing, a warning will be issued.
|
||||
*/
|
||||
uint32_t getDeviceCount() {
|
||||
if (m_rtapi == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
return m_rtapi->getDeviceCount();
|
||||
}
|
||||
/**
|
||||
* @brief Any device integer between 0 and getDeviceCount() - 1 is valid.
|
||||
* If an invalid argument is provided, an RtError (type = INVALID_USE)
|
||||
* will be thrown. If a device is busy or otherwise unavailable, the
|
||||
* structure member "probed" will have a value of "false" and all
|
||||
* other members are undefined. If the specified device is the
|
||||
* current default input or output device, the corresponding
|
||||
* "isDefault" member will have a value of "true".
|
||||
*
|
||||
* @return An airtaudio::DeviceInfo structure for a specified device number.
|
||||
*/
|
||||
airtaudio::DeviceInfo getDeviceInfo(uint32_t _device) {
|
||||
if (m_rtapi == nullptr) {
|
||||
return airtaudio::DeviceInfo();
|
||||
}
|
||||
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.
|
||||
*
|
||||
* If the underlying audio API does not provide a "default
|
||||
* device", or if no devices are available, the return value will be
|
||||
* 0. Note that this is a valid device identifier and it is the
|
||||
* client's responsibility to verify that a device is available
|
||||
* before attempting to open a stream.
|
||||
*/
|
||||
uint32_t getDefaultOutputDevice() {
|
||||
if (m_rtapi == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
return m_rtapi->getDefaultOutputDevice();
|
||||
}
|
||||
/**
|
||||
* @brief A function that returns the index of the default input device.
|
||||
*
|
||||
* If the underlying audio API does not provide a "default
|
||||
* device", or if no devices are available, the return value will be
|
||||
* 0. Note that this is a valid device identifier and it is the
|
||||
* client's responsibility to verify that a device is available
|
||||
* before attempting to open a stream.
|
||||
*/
|
||||
uint32_t getDefaultInputDevice() {
|
||||
if (m_rtapi == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
return m_rtapi->getDefaultInputDevice();
|
||||
}
|
||||
/**
|
||||
* @brief A public function for opening a stream with the specified parameters.
|
||||
*
|
||||
* An RtError (type = SYSTEM_ERROR) is thrown if a stream cannot be
|
||||
* opened with the specified parameters or an error occurs during
|
||||
* processing. An RtError (type = INVALID_USE) is thrown if any
|
||||
* invalid device ID or channel number parameters are specified.
|
||||
* @param _outputParameters Specifies output stream parameters to use
|
||||
* when opening a stream, including a device ID, number of channels,
|
||||
* and starting channel number. For input-only streams, this
|
||||
* argument should be nullptr. The device ID is an index value between
|
||||
* 0 and getDeviceCount() - 1.
|
||||
* @param _inputParameters Specifies input stream parameters to use
|
||||
* when opening a stream, including a device ID, number of channels,
|
||||
* and starting channel number. For output-only streams, this
|
||||
* argument should be nullptr. The device ID is an index value between
|
||||
* 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
|
||||
* 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
|
||||
* allowable value is determined.
|
||||
* @param _callback A client-defined function that will be invoked
|
||||
* when input data is available and/or output data is needed.
|
||||
* @param _options An optional pointer to a structure containing various
|
||||
* global stream options, including a list of OR'ed airtaudio::streamFlags
|
||||
* and a suggested number of stream buffers that can be used to
|
||||
* control stream latency. More buffers typically result in more
|
||||
* robust performance, though at a cost of greater latency. If a
|
||||
* value of zero is specified, a system-specific median value is
|
||||
* chosen. If the airtaudio_MINIMIZE_LATENCY flag bit is set, the
|
||||
* lowest allowable value is used. The actual value used is
|
||||
* returned via the structure argument. The parameter is API dependent.
|
||||
* @param _errorCallback A client-defined function that will be invoked
|
||||
* 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,
|
||||
const airtaudio::StreamOptions& _options = airtaudio::StreamOptions());
|
||||
|
||||
/**
|
||||
* @brief A function that closes a stream and frees any associated stream memory.
|
||||
*
|
||||
* If a stream is not open, this function issues a warning and
|
||||
* returns (no exception is thrown).
|
||||
*/
|
||||
enum airtaudio::error closeStream() {
|
||||
if (m_rtapi == nullptr) {
|
||||
return airtaudio::error_inputNull;
|
||||
}
|
||||
return m_rtapi->closeStream();
|
||||
}
|
||||
/**
|
||||
* @brief A function that starts a stream.
|
||||
*
|
||||
* An RtError (type = SYSTEM_ERROR) is thrown if an error occurs
|
||||
* during processing. An RtError (type = INVALID_USE) is thrown if a
|
||||
* stream is not open. A warning is issued if the stream is already
|
||||
* running.
|
||||
*/
|
||||
enum airtaudio::error startStream() {
|
||||
if (m_rtapi == nullptr) {
|
||||
return airtaudio::error_inputNull;
|
||||
}
|
||||
return m_rtapi->startStream();
|
||||
}
|
||||
/**
|
||||
* @brief Stop a stream, allowing any samples remaining in the output queue to be played.
|
||||
*
|
||||
* An RtError (type = SYSTEM_ERROR) is thrown if an error occurs
|
||||
* during processing. An RtError (type = INVALID_USE) is thrown if a
|
||||
* stream is not open. A warning is issued if the stream is already
|
||||
* stopped.
|
||||
*/
|
||||
enum airtaudio::error stopStream() {
|
||||
if (m_rtapi == nullptr) {
|
||||
return airtaudio::error_inputNull;
|
||||
}
|
||||
return m_rtapi->stopStream();
|
||||
}
|
||||
/**
|
||||
* @brief Stop a stream, discarding any samples remaining in the input/output queue.
|
||||
* An RtError (type = SYSTEM_ERROR) is thrown if an error occurs
|
||||
* during processing. An RtError (type = INVALID_USE) is thrown if a
|
||||
* stream is not open. A warning is issued if the stream is already
|
||||
* stopped.
|
||||
*/
|
||||
enum airtaudio::error abortStream() {
|
||||
if (m_rtapi == nullptr) {
|
||||
return airtaudio::error_inputNull;
|
||||
}
|
||||
return m_rtapi->abortStream();
|
||||
}
|
||||
/**
|
||||
* @return true if a stream is open and false if not.
|
||||
*/
|
||||
bool isStreamOpen() const {
|
||||
if (m_rtapi == nullptr) {
|
||||
return false;
|
||||
}
|
||||
return m_rtapi->isStreamOpen();
|
||||
}
|
||||
/**
|
||||
* @return true if the stream is running and false if it is stopped or not open.
|
||||
*/
|
||||
bool isStreamRunning() const {
|
||||
if (m_rtapi == nullptr) {
|
||||
return false;
|
||||
}
|
||||
return m_rtapi->isStreamRunning();
|
||||
}
|
||||
/**
|
||||
* @brief If a stream is not open, an RtError (type = INVALID_USE) will be thrown.
|
||||
* @return the number of elapsed seconds since the stream was started.
|
||||
*/
|
||||
std11::chrono::system_clock::time_point getStreamTime() {
|
||||
if (m_rtapi == nullptr) {
|
||||
return std11::chrono::system_clock::time_point();
|
||||
}
|
||||
return m_rtapi->getStreamTime();
|
||||
}
|
||||
/**
|
||||
* @brief The stream latency refers to delay in audio input and/or output
|
||||
* caused by internal buffering by the audio system and/or hardware.
|
||||
* For duplex streams, the returned value will represent the sum of
|
||||
* the input and output latencies. If a stream is not open, an
|
||||
* RtError (type = INVALID_USE) will be thrown. If the API does not
|
||||
* report latency, the return value will be zero.
|
||||
* @return The internal stream latency in sample frames.
|
||||
*/
|
||||
long getStreamLatency() {
|
||||
if (m_rtapi == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
return m_rtapi->getStreamLatency();
|
||||
}
|
||||
/**
|
||||
* @brief On some systems, the sample rate used may be slightly different
|
||||
* than that specified in the stream parameters. If a stream is not
|
||||
* open, an RtError (type = INVALID_USE) will be thrown.
|
||||
* @return Returns actual sample rate in use by the stream.
|
||||
*/
|
||||
uint32_t getStreamSampleRate() {
|
||||
if (m_rtapi == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
return m_rtapi->getStreamSampleRate();
|
||||
}
|
||||
bool isMasterOf(airtaudio::Interface& _interface);
|
||||
protected:
|
||||
void openRtApi(enum airtaudio::type _api);
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
@ -1,45 +0,0 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#include <airtaudio/StreamOptions.h>
|
||||
#include <etk/stdTools.h>
|
||||
#include <airtaudio/debug.h>
|
||||
|
||||
static const char* listValue[] = {
|
||||
"hardware",
|
||||
"trigered",
|
||||
"soft"
|
||||
};
|
||||
|
||||
std::ostream& airtaudio::operator <<(std::ostream& _os, enum airtaudio::timestampMode _obj) {
|
||||
_os << listValue[_obj];
|
||||
return _os;
|
||||
}
|
||||
|
||||
namespace etk {
|
||||
template <> bool from_string<enum airtaudio::timestampMode>(enum airtaudio::timestampMode& _variableRet, const std::string& _value) {
|
||||
if (_value == "hardware") {
|
||||
_variableRet = airtaudio::timestampMode_Hardware;
|
||||
return true;
|
||||
}
|
||||
if (_value == "trigered") {
|
||||
_variableRet = airtaudio::timestampMode_trigered;
|
||||
return true;
|
||||
}
|
||||
if (_value == "soft") {
|
||||
_variableRet = airtaudio::timestampMode_soft;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <enum airtaudio::timestampMode> std::string to_string(const enum airtaudio::timestampMode& _variable) {
|
||||
return listValue[_variable];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,36 +0,0 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#ifndef __AIRTAUDIO_STREAM_OPTION_H__
|
||||
#define __AIRTAUDIO_STREAM_OPTION_H__
|
||||
|
||||
#include <airtaudio/Flags.h>
|
||||
|
||||
namespace airtaudio {
|
||||
enum timestampMode {
|
||||
timestampMode_Hardware, //!< enable harware timestamp
|
||||
timestampMode_trigered, //!< get harware triger time stamp and ingrement with duration
|
||||
timestampMode_soft, //!< Simulate all timestamp.
|
||||
};
|
||||
std::ostream& operator <<(std::ostream& _os, enum airtaudio::timestampMode _obj);
|
||||
|
||||
class StreamOptions {
|
||||
public:
|
||||
airtaudio::Flags flags; //!< A bit-mask of stream flags
|
||||
uint32_t numberOfBuffers; //!< Number of stream buffers.
|
||||
std::string streamName; //!< A stream name (currently used only in Jack).
|
||||
enum timestampMode mode; //!< mode of timestamping data...
|
||||
// Default constructor.
|
||||
StreamOptions() :
|
||||
flags(),
|
||||
numberOfBuffers(0),
|
||||
mode(timestampMode_Hardware) {}
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -1,30 +0,0 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#ifndef __AIRTAUDIO_STREAM_PARAMETER_H__
|
||||
#define __AIRTAUDIO_STREAM_PARAMETER_H__
|
||||
|
||||
namespace airtaudio {
|
||||
/**
|
||||
* @brief The structure for specifying input or ouput stream parameters.
|
||||
*/
|
||||
class StreamParameters {
|
||||
public:
|
||||
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(-1),
|
||||
nChannels(0),
|
||||
firstChannel(0) { }
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -1,75 +0,0 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#if !defined(__AIRTAUDIO_API_ALSA_H__) && defined(__LINUX_ALSA__)
|
||||
#define __AIRTAUDIO_API_ALSA_H__
|
||||
|
||||
namespace airtaudio {
|
||||
namespace api {
|
||||
class AlsaPrivate;
|
||||
class Alsa: public airtaudio::Api {
|
||||
public:
|
||||
static airtaudio::Api* Create();
|
||||
public:
|
||||
Alsa();
|
||||
virtual ~Alsa();
|
||||
enum airtaudio::type getCurrentApi() {
|
||||
return airtaudio::type_alsa;
|
||||
}
|
||||
uint32_t getDeviceCount();
|
||||
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();
|
||||
enum airtaudio::error stopStream();
|
||||
enum airtaudio::error abortStream();
|
||||
// This function is intended for internal use only. It must be
|
||||
// public because it is called by the internal callback handler,
|
||||
// which is not a member of RtAudio. External use of this function
|
||||
// will most likely produce highly undesireable results!
|
||||
void callbackEvent();
|
||||
void callbackEventOneCycle();
|
||||
private:
|
||||
static void alsaCallbackEvent(void* _userData);
|
||||
private:
|
||||
std11::shared_ptr<AlsaPrivate> m_private;
|
||||
std::vector<airtaudio::DeviceInfo> m_devices;
|
||||
void saveDeviceInfo();
|
||||
bool probeDeviceOpen(uint32_t _device,
|
||||
enum airtaudio::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
enum audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const 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,
|
||||
const airtaudio::StreamOptions& _options);
|
||||
virtual std11::chrono::system_clock::time_point getStreamTime();
|
||||
public:
|
||||
bool isMasterOf(airtaudio::Api* _api);
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
@ -1,54 +0,0 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#if !defined(__AIRTAUDIO_API_ANDROID_H__) && defined(__ANDROID_JAVA__)
|
||||
#define __AIRTAUDIO_API_ANDROID_H__
|
||||
|
||||
namespace airtaudio {
|
||||
namespace api {
|
||||
class Android: public airtaudio::Api {
|
||||
public:
|
||||
static airtaudio::Api* Create();
|
||||
public:
|
||||
Android();
|
||||
virtual ~Android();
|
||||
enum airtaudio::type getCurrentApi() {
|
||||
return airtaudio::type_java;
|
||||
}
|
||||
uint32_t getDeviceCount();
|
||||
airtaudio::DeviceInfo getDeviceInfo(uint32_t _device);
|
||||
enum airtaudio::error closeStream();
|
||||
enum airtaudio::error startStream();
|
||||
enum airtaudio::error stopStream();
|
||||
enum airtaudio::error abortStream();
|
||||
// This function is intended for internal use only. It must be
|
||||
// public because it is called by the internal callback handler,
|
||||
// which is not a member of RtAudio. External use of this function
|
||||
// will most likely produce highly undesireable results!
|
||||
void callbackEvent();
|
||||
private:
|
||||
std::vector<airtaudio::DeviceInfo> m_devices;
|
||||
void saveDeviceInfo();
|
||||
bool probeDeviceOpen(uint32_t _device,
|
||||
airtaudio::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const airtaudio::StreamOptions& _options);
|
||||
private:
|
||||
void callBackEvent(void* _data,
|
||||
int32_t _frameRate);
|
||||
static void androidCallBackEvent(void* _data,
|
||||
int32_t _frameRate,
|
||||
void* _userData);
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
@ -1,52 +0,0 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#if !defined(__AIRTAUDIO_API_ASIO_H__) && defined(__WINDOWS_ASIO__)
|
||||
#define __AIRTAUDIO_API_ASIO_H__
|
||||
|
||||
namespace airtaudio {
|
||||
namespace api {
|
||||
class AsioPrivate:
|
||||
class Asio: public airtaudio::Api {
|
||||
public:
|
||||
static airtaudio::Api* Create();
|
||||
public:
|
||||
Asio();
|
||||
virtual ~Asio();
|
||||
enum airtaudio::type getCurrentApi() {
|
||||
return airtaudio::WINDOWS_ASIO;
|
||||
}
|
||||
uint32_t getDeviceCount();
|
||||
airtaudio::DeviceInfo getDeviceInfo(uint32_t _device);
|
||||
enum airtaudio::error closeStream();
|
||||
enum airtaudio::error startStream();
|
||||
enum airtaudio::error stopStream();
|
||||
enum airtaudio::error abortStream();
|
||||
long getStreamLatency();
|
||||
// This function is intended for internal use only. It must be
|
||||
// public because it is called by the internal callback handler,
|
||||
// which is not a member of RtAudio. External use of this function
|
||||
// will most likely produce highly undesireable results!
|
||||
bool callbackEvent(long _bufferIndex);
|
||||
private:
|
||||
std::shared_ptr<AsioPrivate> m_private;
|
||||
std::vector<airtaudio::DeviceInfo> m_devices;
|
||||
void saveDeviceInfo();
|
||||
bool m_coInitialized;
|
||||
bool probeDeviceOpen(uint32_t _device,
|
||||
airtaudio::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const airtaudio.::StreamOptions& _options);
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
@ -1,66 +0,0 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#if !defined(__AIRTAUDIO_API_CORE_H__) && defined(__MACOSX_CORE__)
|
||||
#define __AIRTAUDIO_API_CORE_H__
|
||||
|
||||
#include <CoreAudio/AudioHardware.h>
|
||||
|
||||
namespace airtaudio {
|
||||
namespace api {
|
||||
class CorePrivate;
|
||||
class Core: public airtaudio::Api {
|
||||
public:
|
||||
static airtaudio::Api* Create();
|
||||
public:
|
||||
Core();
|
||||
virtual ~Core();
|
||||
enum airtaudio::type getCurrentApi() {
|
||||
return airtaudio::type_coreOSX;
|
||||
}
|
||||
uint32_t getDeviceCount();
|
||||
airtaudio::DeviceInfo getDeviceInfo(uint32_t _device);
|
||||
uint32_t getDefaultOutputDevice();
|
||||
uint32_t getDefaultInputDevice();
|
||||
enum airtaudio::error closeStream();
|
||||
enum airtaudio::error startStream();
|
||||
enum airtaudio::error stopStream();
|
||||
enum airtaudio::error abortStream();
|
||||
long getStreamLatency();
|
||||
bool callbackEvent(AudioDeviceID _deviceId,
|
||||
const AudioBufferList *_inBufferList,
|
||||
const std11::chrono::system_clock::time_point& _inTime,
|
||||
const AudioBufferList *_outBufferList,
|
||||
const std11::chrono::system_clock::time_point& _outTime);
|
||||
static OSStatus callbackEvent(AudioDeviceID _inDevice,
|
||||
const AudioTimeStamp* _inNow,
|
||||
const AudioBufferList* _inInputData,
|
||||
const AudioTimeStamp* _inInputTime,
|
||||
AudioBufferList* _outOutputData,
|
||||
const AudioTimeStamp* _inOutputTime,
|
||||
void* _infoPointer);
|
||||
static void coreStopStream(void *_userData);
|
||||
private:
|
||||
std::shared_ptr<CorePrivate> m_private;
|
||||
bool probeDeviceOpen(uint32_t _device,
|
||||
airtaudio::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const airtaudio.::StreamOptions& _options);
|
||||
static const char* getErrorCode(OSStatus _code);
|
||||
static OSStatus xrunListener(AudioObjectID _inDevice,
|
||||
uint32_t _nAddresses,
|
||||
const AudioObjectPropertyAddress _properties[],
|
||||
void* _userData);
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
@ -1,54 +0,0 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#if !defined(__AIRTAUDIO_API_CORE_IOS_H__) && defined(__IOS_CORE__)
|
||||
#define __AIRTAUDIO_API_CORE_IOS_H__
|
||||
|
||||
namespace airtaudio {
|
||||
namespace api {
|
||||
class CoreIosPrivate;
|
||||
class CoreIos: public airtaudio::Api {
|
||||
public:
|
||||
static airtaudio::Api* Create();
|
||||
public:
|
||||
CoreIos();
|
||||
virtual ~CoreIos();
|
||||
enum airtaudio::type getCurrentApi() {
|
||||
return airtaudio::type_coreIOS;
|
||||
}
|
||||
uint32_t getDeviceCount();
|
||||
airtaudio::DeviceInfo getDeviceInfo(uint32_t _device);
|
||||
enum airtaudio::error closeStream();
|
||||
enum airtaudio::error startStream();
|
||||
enum airtaudio::error stopStream();
|
||||
enum airtaudio::error abortStream();
|
||||
// This function is intended for internal use only. It must be
|
||||
// public because it is called by the internal callback handler,
|
||||
// which is not a member of RtAudio. External use of this function
|
||||
// will most likely produce highly undesireable results!
|
||||
void callbackEvent();
|
||||
private:
|
||||
std::vector<airtaudio::DeviceInfo> m_devices;
|
||||
void saveDeviceInfo();
|
||||
bool probeDeviceOpen(uint32_t _device,
|
||||
airtaudio::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const airtaudio.::StreamOptions& _options);
|
||||
public:
|
||||
void callBackEvent(void* _data,
|
||||
int32_t _frameRate);
|
||||
public:
|
||||
std11::shared_ptr<CoreIosPrivate> m_private;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
@ -1,55 +0,0 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#if !defined(__AIRTAUDIO_API_DS_H__) && defined(__WINDOWS_DS__)
|
||||
#define __AIRTAUDIO_API_DS_H__
|
||||
|
||||
namespace airtaudio {
|
||||
namespace api {
|
||||
class DsPrivate;
|
||||
class Ds: public airtaudio::Api {
|
||||
public:
|
||||
static airtaudio::Api* Create();
|
||||
public:
|
||||
Ds();
|
||||
virtual ~Ds();
|
||||
enum airtaudio::type getCurrentApi() {
|
||||
return airtaudio::type_ds;
|
||||
}
|
||||
uint32_t getDeviceCount();
|
||||
uint32_t getDefaultOutputDevice();
|
||||
uint32_t getDefaultInputDevice();
|
||||
airtaudio::DeviceInfo getDeviceInfo(uint32_t _device);
|
||||
enum airtaudio::error closeStream();
|
||||
enum airtaudio::error startStream();
|
||||
enum airtaudio::error stopStream();
|
||||
enum airtaudio::error abortStream();
|
||||
long getStreamLatency();
|
||||
// This function is intended for internal use only. It must be
|
||||
// public because it is called by the internal callback handler,
|
||||
// which is not a member of RtAudio. External use of this function
|
||||
// will most likely produce highly undesireable results!
|
||||
void callbackEvent();
|
||||
private:
|
||||
static void dsCallbackEvent(void *_userData);
|
||||
std11::shared_ptr<DsPrivate> m_private;
|
||||
bool m_coInitialized;
|
||||
bool m_buffersRolling;
|
||||
long m_duplexPrerollBytes;
|
||||
bool probeDeviceOpen(uint32_t _device,
|
||||
enum airtaudio::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
enum audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const airtaudio.::StreamOptions& _options);
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
@ -1,63 +0,0 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#if defined(__DUMMY__)
|
||||
#include <airtaudio/api/Dummy.h>
|
||||
#include <airtaudio/debug.h>
|
||||
|
||||
#undef __class__
|
||||
#define __class__ "api::Dummy"
|
||||
|
||||
airtaudio::Api* airtaudio::api::Dummy::Create() {
|
||||
return new airtaudio::api::Dummy();
|
||||
}
|
||||
|
||||
|
||||
airtaudio::api::Dummy::Dummy() {
|
||||
ATA_WARNING("This class provides no functionality.");
|
||||
}
|
||||
|
||||
uint32_t airtaudio::api::Dummy::getDeviceCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
airtaudio::DeviceInfo airtaudio::api::Dummy::getDeviceInfo(uint32_t _device) {
|
||||
(void)_device;
|
||||
return airtaudio::DeviceInfo();
|
||||
}
|
||||
|
||||
enum airtaudio::error airtaudio::api::Dummy::closeStream() {
|
||||
return airtaudio::error_none;
|
||||
}
|
||||
|
||||
enum airtaudio::error airtaudio::api::Dummy::startStream() {
|
||||
// TODO : Check return ...
|
||||
airtaudio::Api::startStream();
|
||||
return airtaudio::error_none;
|
||||
}
|
||||
|
||||
enum airtaudio::error airtaudio::api::Dummy::stopStream() {
|
||||
return airtaudio::error_none;
|
||||
}
|
||||
|
||||
enum airtaudio::error airtaudio::api::Dummy::abortStream() {
|
||||
return airtaudio::error_none;
|
||||
}
|
||||
|
||||
bool airtaudio::api::Dummy::probeDeviceOpen(uint32_t _device,
|
||||
airtaudio::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const airtaudio::StreamOptions& _options) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,42 +0,0 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#if !defined(__AIRTAUDIO_DUMMY__) && defined(__DUMMY__)
|
||||
#define __AIRTAUDIO_DUMMY__
|
||||
|
||||
#include <airtaudio/Interface.h>
|
||||
|
||||
namespace airtaudio {
|
||||
namespace api {
|
||||
class Dummy: public airtaudio::Api {
|
||||
public:
|
||||
static airtaudio::Api* Create();
|
||||
public:
|
||||
Dummy();
|
||||
enum airtaudio::type getCurrentApi() {
|
||||
return airtaudio::type_dummy;
|
||||
}
|
||||
uint32_t getDeviceCount();
|
||||
airtaudio::DeviceInfo getDeviceInfo(uint32_t _device);
|
||||
enum airtaudio::error closeStream();
|
||||
enum airtaudio::error startStream();
|
||||
enum airtaudio::error stopStream();
|
||||
enum airtaudio::error abortStream();
|
||||
private:
|
||||
bool probeDeviceOpen(uint32_t _device,
|
||||
airtaudio::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const airtaudio::StreamOptions& _options);
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
@ -1,55 +0,0 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#if !defined(__AIRTAUDIO_API_JACK_H__) && defined(__UNIX_JACK__)
|
||||
#define __AIRTAUDIO_API_JACK_H__
|
||||
|
||||
#include <jack/jack.h>
|
||||
namespace airtaudio {
|
||||
namespace api {
|
||||
class JackPrivate;
|
||||
class Jack: public airtaudio::Api {
|
||||
public:
|
||||
static airtaudio::Api* Create();
|
||||
public:
|
||||
Jack();
|
||||
virtual ~Jack();
|
||||
enum airtaudio::type getCurrentApi() {
|
||||
return airtaudio::type_jack;
|
||||
}
|
||||
uint32_t getDeviceCount();
|
||||
airtaudio::DeviceInfo getDeviceInfo(uint32_t _device);
|
||||
enum airtaudio::error closeStream();
|
||||
enum airtaudio::error startStream();
|
||||
enum airtaudio::error stopStream();
|
||||
enum airtaudio::error abortStream();
|
||||
long getStreamLatency();
|
||||
// This function is intended for internal use only. It must be
|
||||
// public because it is called by the internal callback handler,
|
||||
// which is not a member of RtAudio. External use of this function
|
||||
// will most likely produce highly undesireable results!
|
||||
bool callbackEvent(uint64_t _nframes);
|
||||
private:
|
||||
static int32_t jackXrun(void* _userData);
|
||||
static void jackCloseStream(void* _userData);
|
||||
static void jackShutdown(void* _userData);
|
||||
static int32_t jackCallbackHandler(jack_nframes_t _nframes, void* _userData);
|
||||
private:
|
||||
std11::shared_ptr<JackPrivate> m_private;
|
||||
bool probeDeviceOpen(uint32_t _device,
|
||||
airtaudio::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const airtaudio.::StreamOptions& _options);
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
@ -1,48 +0,0 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#if !defined(__AIRTAUDIO_API_OSS_H__) && defined(__LINUX_OSS__)
|
||||
#define __AIRTAUDIO_API_OSS_H__
|
||||
|
||||
namespace airtaudio {
|
||||
namespace api {
|
||||
class OssPrivate;
|
||||
class Oss: public airtaudio::Api {
|
||||
public:
|
||||
static airtaudio::Api* Create();
|
||||
public:
|
||||
Oss();
|
||||
virtual ~Oss();
|
||||
enum airtaudio::type getCurrentApi() {
|
||||
return airtaudio::type_oss;
|
||||
}
|
||||
uint32_t getDeviceCount();
|
||||
airtaudio::DeviceInfo getDeviceInfo(uint32_t _device);
|
||||
enum airtaudio::error closeStream();
|
||||
enum airtaudio::error startStream();
|
||||
enum airtaudio::error stopStream();
|
||||
enum airtaudio::error abortStream();
|
||||
// This function is intended for internal use only. It must be
|
||||
// public because it is called by the internal callback handler,
|
||||
// which is not a member of RtAudio. External use of this function
|
||||
// will most likely produce highly undesireable results!
|
||||
void callbackEvent();
|
||||
private:
|
||||
std11::shared_ptr<OssPrivate> m_private;
|
||||
bool probeDeviceOpen(uint32_t _device,
|
||||
airtaudio::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const airtaudio.::StreamOptions& _options);
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
@ -1,51 +0,0 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#if !defined(__AIRTAUDIO_API_PULSE_H__) && defined(__LINUX_PULSE__)
|
||||
#define __AIRTAUDIO_API_PULSE_H__
|
||||
|
||||
namespace airtaudio {
|
||||
namespace api {
|
||||
class PulsePrivate;
|
||||
class Pulse: public airtaudio::Api {
|
||||
public:
|
||||
static airtaudio::Api* Create();
|
||||
public:
|
||||
Pulse();
|
||||
virtual ~Pulse();
|
||||
enum airtaudio::type getCurrentApi() {
|
||||
return airtaudio::type_pulse;
|
||||
}
|
||||
uint32_t getDeviceCount();
|
||||
airtaudio::DeviceInfo getDeviceInfo(uint32_t _device);
|
||||
enum airtaudio::error closeStream();
|
||||
enum airtaudio::error startStream();
|
||||
enum airtaudio::error stopStream();
|
||||
enum airtaudio::error abortStream();
|
||||
// This function is intended for internal use only. It must be
|
||||
// public because it is called by the internal callback handler,
|
||||
// which is not a member of RtAudio. External use of this function
|
||||
// will most likely produce highly undesireable results!
|
||||
void callbackEventOneCycle();
|
||||
void callbackEvent();
|
||||
private:
|
||||
std11::shared_ptr<PulsePrivate> m_private;
|
||||
std::vector<airtaudio::DeviceInfo> m_devices;
|
||||
void saveDeviceInfo();
|
||||
bool probeDeviceOpen(uint32_t _device,
|
||||
airtaudio::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const airtaudio.::StreamOptions& _options);
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
@ -1,24 +0,0 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#ifndef __AIRTAUDIO_ERROR_H__
|
||||
#define __AIRTAUDIO_ERROR_H__
|
||||
|
||||
#include <etk/types.h>
|
||||
|
||||
namespace airtaudio {
|
||||
enum error {
|
||||
error_none, //!< No error
|
||||
error_fail, //!< An error occure in the operation
|
||||
error_warning, //!< A non-critical error.
|
||||
error_inputNull, //!< null input or internal errror
|
||||
error_invalidUse, //!< The function was called incorrectly.
|
||||
error_systemError //!< A system error occured.
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
@ -1,23 +0,0 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#ifndef __AIRTAUDIO_MODE_H__
|
||||
#define __AIRTAUDIO_MODE_H__
|
||||
|
||||
#include <etk/types.h>
|
||||
|
||||
namespace airtaudio {
|
||||
enum mode {
|
||||
mode_unknow,
|
||||
mode_output,
|
||||
mode_input,
|
||||
mode_duplex
|
||||
};
|
||||
int32_t modeToIdTable(enum mode _mode);
|
||||
}
|
||||
|
||||
#endif
|
@ -1,22 +0,0 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#ifndef __AIRTAUDIO_STATE_H__
|
||||
#define __AIRTAUDIO_STATE_H__
|
||||
|
||||
#include <etk/types.h>
|
||||
|
||||
namespace airtaudio {
|
||||
enum state {
|
||||
state_closed,
|
||||
state_stopped,
|
||||
state_stopping,
|
||||
state_running
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -1,24 +0,0 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#ifndef __AIRTAUDIO_STATUS_H__
|
||||
#define __AIRTAUDIO_STATUS_H__
|
||||
|
||||
#include <etk/types.h>
|
||||
|
||||
namespace airtaudio {
|
||||
enum status {
|
||||
status_ok, //!< nothing...
|
||||
status_overflow, //!< Internal buffer has more data than they can accept
|
||||
status_underflow //!< The internal buffer is empty
|
||||
};
|
||||
std::ostream& operator <<(std::ostream& _os, enum airtaudio::status _obj);
|
||||
std::ostream& operator <<(std::ostream& _os, const std::vector<enum airtaudio::status>& _obj);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
@ -1,41 +0,0 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#ifndef __AIRTAUDIO_TYPE_H__
|
||||
#define __AIRTAUDIO_TYPE_H__
|
||||
|
||||
#include <etk/types.h>
|
||||
#include <etk/stdTools.h>
|
||||
|
||||
namespace airtaudio {
|
||||
/**
|
||||
* @brief Audio API specifier arguments.
|
||||
*/
|
||||
enum type {
|
||||
type_undefined, //!< Error API.
|
||||
type_alsa, //!< LINUX The Advanced Linux Sound Architecture.
|
||||
type_pulse, //!< LINUX The Linux PulseAudio.
|
||||
type_oss, //!< LINUX The Linux Open Sound System.
|
||||
type_jack, //!< UNIX The Jack Low-Latency Audio Server.
|
||||
type_coreOSX, //!< Macintosh OSX Core Audio.
|
||||
type_coreIOS, //!< Macintosh iOS Core Audio.
|
||||
type_asio, //!< WINDOWS The Steinberg Audio Stream I/O.
|
||||
type_ds, //!< WINDOWS The Microsoft Direct Sound.
|
||||
type_java, //!< ANDROID Interface.
|
||||
type_dummy, //!< Empty wrapper (non-functional).
|
||||
type_user1, //!< User interface 1.
|
||||
type_user2, //!< User interface 2.
|
||||
type_user3, //!< User interface 3.
|
||||
type_user4, //!< User interface 4.
|
||||
};
|
||||
std::ostream& operator <<(std::ostream& _os, const enum airtaudio::type& _obj);
|
||||
std::ostream& operator <<(std::ostream& _os, const std::vector<enum airtaudio::type>& _obj);
|
||||
std::string getTypeString(enum airtaudio::type _value);
|
||||
enum airtaudio::type getTypeFromString(const std::string& _value);
|
||||
}
|
||||
|
||||
#endif
|
@ -6,8 +6,8 @@
|
||||
*/
|
||||
|
||||
//#include <etk/types.h>
|
||||
#include <airtaudio/Interface.h>
|
||||
#include <airtaudio/debug.h>
|
||||
#include <audio/orchestra/Interface.h>
|
||||
#include <audio/orchestra/debug.h>
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
@ -18,7 +18,7 @@
|
||||
|
||||
|
||||
// Static variable definitions.
|
||||
const std::vector<uint32_t>& airtaudio::genericSampleRate() {
|
||||
const std::vector<uint32_t>& audio::orchestra::genericSampleRate() {
|
||||
static std::vector<uint32_t> list;
|
||||
if (list.size() == 0) {
|
||||
list.push_back(4000);
|
||||
@ -42,55 +42,55 @@ const std::vector<uint32_t>& airtaudio::genericSampleRate() {
|
||||
};
|
||||
|
||||
|
||||
airtaudio::Api::Api() :
|
||||
audio::orchestra::Api::Api() :
|
||||
m_callback(nullptr),
|
||||
m_deviceBuffer(nullptr) {
|
||||
m_device[0] = 11111;
|
||||
m_device[1] = 11111;
|
||||
m_state = airtaudio::state_closed;
|
||||
m_mode = airtaudio::mode_unknow;
|
||||
m_state = audio::orchestra::state_closed;
|
||||
m_mode = audio::orchestra::mode_unknow;
|
||||
}
|
||||
|
||||
airtaudio::Api::~Api() {
|
||||
audio::orchestra::Api::~Api() {
|
||||
|
||||
}
|
||||
|
||||
enum airtaudio::error airtaudio::Api::startStream() {
|
||||
enum audio::orchestra::error audio::orchestra::Api::startStream() {
|
||||
ATA_VERBOSE("Start Stream");
|
||||
m_startTime = std11::chrono::system_clock::now();
|
||||
m_duration = std11::chrono::microseconds(0);
|
||||
return airtaudio::error_none;
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
enum airtaudio::error airtaudio::Api::openStream(airtaudio::StreamParameters* _oParams,
|
||||
airtaudio::StreamParameters* _iParams,
|
||||
enum audio::orchestra::error audio::orchestra::Api::openStream(audio::orchestra::StreamParameters* _oParams,
|
||||
audio::orchestra::StreamParameters* _iParams,
|
||||
enum audio::format _format,
|
||||
uint32_t _sampleRate,
|
||||
uint32_t* _bufferFrames,
|
||||
airtaudio::AirTAudioCallback _callback,
|
||||
const airtaudio::StreamOptions& _options) {
|
||||
if (m_state != airtaudio::state_closed) {
|
||||
audio::orchestra::AirTAudioCallback _callback,
|
||||
const audio::orchestra::StreamOptions& _options) {
|
||||
if (m_state != audio::orchestra::state_closed) {
|
||||
ATA_ERROR("a stream is already open!");
|
||||
return airtaudio::error_invalidUse;
|
||||
return audio::orchestra::error_invalidUse;
|
||||
}
|
||||
if ( _oParams != nullptr
|
||||
&& _oParams->nChannels < 1) {
|
||||
ATA_ERROR("a non-nullptr output StreamParameters structure cannot have an nChannels value less than one.");
|
||||
return airtaudio::error_invalidUse;
|
||||
return audio::orchestra::error_invalidUse;
|
||||
}
|
||||
if ( _iParams != nullptr
|
||||
&& _iParams->nChannels < 1) {
|
||||
ATA_ERROR("a non-nullptr input StreamParameters structure cannot have an nChannels value less than one.");
|
||||
return airtaudio::error_invalidUse;
|
||||
return audio::orchestra::error_invalidUse;
|
||||
}
|
||||
if ( _oParams == nullptr
|
||||
&& _iParams == nullptr) {
|
||||
ATA_ERROR("input and output StreamParameters structures are both nullptr!");
|
||||
return airtaudio::error_invalidUse;
|
||||
return audio::orchestra::error_invalidUse;
|
||||
}
|
||||
if (audio::getFormatBytes(_format) == 0) {
|
||||
ATA_ERROR("'format' parameter value is undefined.");
|
||||
return airtaudio::error_invalidUse;
|
||||
return audio::orchestra::error_invalidUse;
|
||||
}
|
||||
uint32_t nDevices = getDeviceCount();
|
||||
uint32_t oChannels = 0;
|
||||
@ -99,7 +99,7 @@ enum airtaudio::error airtaudio::Api::openStream(airtaudio::StreamParameters* _o
|
||||
if ( _oParams->deviceId >= nDevices
|
||||
&& _oParams->deviceName == "") {
|
||||
ATA_ERROR("output device parameter value is invalid.");
|
||||
return airtaudio::error_invalidUse;
|
||||
return audio::orchestra::error_invalidUse;
|
||||
}
|
||||
}
|
||||
uint32_t iChannels = 0;
|
||||
@ -108,7 +108,7 @@ enum airtaudio::error airtaudio::Api::openStream(airtaudio::StreamParameters* _o
|
||||
if ( _iParams->deviceId >= nDevices
|
||||
&& _iParams->deviceName == "") {
|
||||
ATA_ERROR("input device parameter value is invalid.");
|
||||
return airtaudio::error_invalidUse;
|
||||
return audio::orchestra::error_invalidUse;
|
||||
}
|
||||
}
|
||||
clearStreamInfo();
|
||||
@ -116,7 +116,7 @@ enum airtaudio::error airtaudio::Api::openStream(airtaudio::StreamParameters* _o
|
||||
if (oChannels > 0) {
|
||||
if (_oParams->deviceId == -1) {
|
||||
result = probeDeviceOpenName(_oParams->deviceName,
|
||||
airtaudio::mode_output,
|
||||
audio::orchestra::mode_output,
|
||||
oChannels,
|
||||
_oParams->firstChannel,
|
||||
_sampleRate,
|
||||
@ -125,7 +125,7 @@ enum airtaudio::error airtaudio::Api::openStream(airtaudio::StreamParameters* _o
|
||||
_options);
|
||||
} else {
|
||||
result = probeDeviceOpen(_oParams->deviceId,
|
||||
airtaudio::mode_output,
|
||||
audio::orchestra::mode_output,
|
||||
oChannels,
|
||||
_oParams->firstChannel,
|
||||
_sampleRate,
|
||||
@ -135,13 +135,13 @@ enum airtaudio::error airtaudio::Api::openStream(airtaudio::StreamParameters* _o
|
||||
}
|
||||
if (result == false) {
|
||||
ATA_ERROR("system ERROR");
|
||||
return airtaudio::error_systemError;
|
||||
return audio::orchestra::error_systemError;
|
||||
}
|
||||
}
|
||||
if (iChannels > 0) {
|
||||
if (_iParams->deviceId == -1) {
|
||||
result = probeDeviceOpenName(_iParams->deviceName,
|
||||
airtaudio::mode_input,
|
||||
audio::orchestra::mode_input,
|
||||
iChannels,
|
||||
_iParams->firstChannel,
|
||||
_sampleRate,
|
||||
@ -150,7 +150,7 @@ enum airtaudio::error airtaudio::Api::openStream(airtaudio::StreamParameters* _o
|
||||
_options);
|
||||
} else {
|
||||
result = probeDeviceOpen(_iParams->deviceId,
|
||||
airtaudio::mode_input,
|
||||
audio::orchestra::mode_input,
|
||||
iChannels,
|
||||
_iParams->firstChannel,
|
||||
_sampleRate,
|
||||
@ -163,90 +163,90 @@ enum airtaudio::error airtaudio::Api::openStream(airtaudio::StreamParameters* _o
|
||||
closeStream();
|
||||
}
|
||||
ATA_ERROR("system error");
|
||||
return airtaudio::error_systemError;
|
||||
return audio::orchestra::error_systemError;
|
||||
}
|
||||
}
|
||||
m_callback = _callback;
|
||||
//_options.numberOfBuffers = m_nBuffers;
|
||||
m_state = airtaudio::state_stopped;
|
||||
return airtaudio::error_none;
|
||||
m_state = audio::orchestra::state_stopped;
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
uint32_t airtaudio::Api::getDefaultInputDevice() {
|
||||
uint32_t audio::orchestra::Api::getDefaultInputDevice() {
|
||||
// Should be implemented in subclasses if possible.
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t airtaudio::Api::getDefaultOutputDevice() {
|
||||
uint32_t audio::orchestra::Api::getDefaultOutputDevice() {
|
||||
// Should be implemented in subclasses if possible.
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum airtaudio::error airtaudio::Api::closeStream() {
|
||||
enum audio::orchestra::error audio::orchestra::Api::closeStream() {
|
||||
ATA_VERBOSE("Close Stream");
|
||||
// MUST be implemented in subclasses!
|
||||
return airtaudio::error_none;
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
bool airtaudio::Api::probeDeviceOpen(uint32_t /*device*/,
|
||||
airtaudio::mode /*mode*/,
|
||||
bool audio::orchestra::Api::probeDeviceOpen(uint32_t /*device*/,
|
||||
audio::orchestra::mode /*mode*/,
|
||||
uint32_t /*channels*/,
|
||||
uint32_t /*firstChannel*/,
|
||||
uint32_t /*sampleRate*/,
|
||||
audio::format /*format*/,
|
||||
uint32_t * /*bufferSize*/,
|
||||
const airtaudio::StreamOptions& /*options*/) {
|
||||
const audio::orchestra::StreamOptions& /*options*/) {
|
||||
// MUST be implemented in subclasses!
|
||||
return false;
|
||||
}
|
||||
|
||||
void airtaudio::Api::tickStreamTime() {
|
||||
void audio::orchestra::Api::tickStreamTime() {
|
||||
//ATA_WARNING("tick : size=" << m_bufferSize << " rate=" << m_sampleRate << " time=" << std11::chrono::nanoseconds((int64_t(m_bufferSize) * int64_t(1000000000)) / int64_t(m_sampleRate)).count());
|
||||
//ATA_WARNING(" one element=" << std11::chrono::nanoseconds((int64_t(1000000000)) / int64_t(m_sampleRate)).count());
|
||||
m_duration += std11::chrono::nanoseconds((int64_t(m_bufferSize) * int64_t(1000000000)) / int64_t(m_sampleRate));
|
||||
}
|
||||
|
||||
long airtaudio::Api::getStreamLatency() {
|
||||
if (verifyStream() != airtaudio::error_none) {
|
||||
long audio::orchestra::Api::getStreamLatency() {
|
||||
if (verifyStream() != audio::orchestra::error_none) {
|
||||
return 0;
|
||||
}
|
||||
long totalLatency = 0;
|
||||
if ( m_mode == airtaudio::mode_output
|
||||
|| m_mode == airtaudio::mode_duplex) {
|
||||
if ( m_mode == audio::orchestra::mode_output
|
||||
|| m_mode == audio::orchestra::mode_duplex) {
|
||||
totalLatency = m_latency[0];
|
||||
}
|
||||
if ( m_mode == airtaudio::mode_input
|
||||
|| m_mode == airtaudio::mode_duplex) {
|
||||
if ( m_mode == audio::orchestra::mode_input
|
||||
|| m_mode == audio::orchestra::mode_duplex) {
|
||||
totalLatency += m_latency[1];
|
||||
}
|
||||
return totalLatency;
|
||||
}
|
||||
|
||||
std11::chrono::system_clock::time_point airtaudio::Api::getStreamTime() {
|
||||
if (verifyStream() != airtaudio::error_none) {
|
||||
std11::chrono::system_clock::time_point audio::orchestra::Api::getStreamTime() {
|
||||
if (verifyStream() != audio::orchestra::error_none) {
|
||||
return std11::chrono::system_clock::time_point();
|
||||
}
|
||||
return m_startTime + m_duration;
|
||||
}
|
||||
|
||||
uint32_t airtaudio::Api::getStreamSampleRate() {
|
||||
if (verifyStream() != airtaudio::error_none) {
|
||||
uint32_t audio::orchestra::Api::getStreamSampleRate() {
|
||||
if (verifyStream() != audio::orchestra::error_none) {
|
||||
return 0;
|
||||
}
|
||||
return m_sampleRate;
|
||||
}
|
||||
|
||||
enum airtaudio::error airtaudio::Api::verifyStream() {
|
||||
if (m_state == airtaudio::state_closed) {
|
||||
enum audio::orchestra::error audio::orchestra::Api::verifyStream() {
|
||||
if (m_state == audio::orchestra::state_closed) {
|
||||
ATA_ERROR("a stream is not open!");
|
||||
return airtaudio::error_invalidUse;
|
||||
return audio::orchestra::error_invalidUse;
|
||||
}
|
||||
return airtaudio::error_none;
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
void airtaudio::Api::clearStreamInfo() {
|
||||
m_mode = airtaudio::mode_unknow;
|
||||
m_state = airtaudio::state_closed;
|
||||
void audio::orchestra::Api::clearStreamInfo() {
|
||||
m_mode = audio::orchestra::mode_unknow;
|
||||
m_state = audio::orchestra::state_closed;
|
||||
m_sampleRate = 0;
|
||||
m_bufferSize = 0;
|
||||
m_nBuffers = 0;
|
||||
@ -276,9 +276,9 @@ void airtaudio::Api::clearStreamInfo() {
|
||||
}
|
||||
}
|
||||
|
||||
void airtaudio::Api::setConvertInfo(airtaudio::mode _mode, uint32_t _firstChannel) {
|
||||
int32_t idTable = airtaudio::modeToIdTable(_mode);
|
||||
if (_mode == airtaudio::mode_input) { // convert device to user buffer
|
||||
void audio::orchestra::Api::setConvertInfo(audio::orchestra::mode _mode, uint32_t _firstChannel) {
|
||||
int32_t idTable = audio::orchestra::modeToIdTable(_mode);
|
||||
if (_mode == audio::orchestra::mode_input) { // convert device to user buffer
|
||||
m_convertInfo[idTable].inJump = m_nDeviceChannels[1];
|
||||
m_convertInfo[idTable].outJump = m_nUserChannels[1];
|
||||
m_convertInfo[idTable].inFormat = m_deviceFormat[1];
|
||||
@ -296,7 +296,7 @@ void airtaudio::Api::setConvertInfo(airtaudio::mode _mode, uint32_t _firstChanne
|
||||
}
|
||||
// Set up the interleave/deinterleave offsets.
|
||||
if (m_deviceInterleaved[idTable] == false) {
|
||||
if (_mode == airtaudio::mode_input) {
|
||||
if (_mode == audio::orchestra::mode_input) {
|
||||
for (int32_t kkk=0; kkk<m_convertInfo[idTable].channels; ++kkk) {
|
||||
m_convertInfo[idTable].inOffset.push_back(kkk * m_bufferSize);
|
||||
m_convertInfo[idTable].outOffset.push_back(kkk);
|
||||
@ -319,7 +319,7 @@ void airtaudio::Api::setConvertInfo(airtaudio::mode _mode, uint32_t _firstChanne
|
||||
// Add channel offset.
|
||||
if (_firstChannel > 0) {
|
||||
if (m_deviceInterleaved[idTable]) {
|
||||
if (_mode == airtaudio::mode_output) {
|
||||
if (_mode == audio::orchestra::mode_output) {
|
||||
for (int32_t kkk=0; kkk<m_convertInfo[idTable].channels; ++kkk) {
|
||||
m_convertInfo[idTable].outOffset[kkk] += _firstChannel;
|
||||
}
|
||||
@ -329,7 +329,7 @@ void airtaudio::Api::setConvertInfo(airtaudio::mode _mode, uint32_t _firstChanne
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (_mode == airtaudio::mode_output) {
|
||||
if (_mode == audio::orchestra::mode_output) {
|
||||
for (int32_t kkk=0; kkk<m_convertInfo[idTable].channels; ++kkk) {
|
||||
m_convertInfo[idTable].outOffset[kkk] += (_firstChannel * m_bufferSize);
|
||||
}
|
||||
@ -342,14 +342,14 @@ void airtaudio::Api::setConvertInfo(airtaudio::mode _mode, uint32_t _firstChanne
|
||||
}
|
||||
}
|
||||
|
||||
void airtaudio::Api::convertBuffer(char *_outBuffer, char *_inBuffer, airtaudio::ConvertInfo &_info) {
|
||||
void audio::orchestra::Api::convertBuffer(char *_outBuffer, char *_inBuffer, audio::orchestra::ConvertInfo &_info) {
|
||||
// This function does format conversion, input/output channel compensation, and
|
||||
// data interleaving/deinterleaving. 24-bit integers are assumed to occupy
|
||||
// the lower three bytes of a 32-bit integer.
|
||||
|
||||
// Clear our device buffer when in/out duplex device channels are different
|
||||
if ( _outBuffer == m_deviceBuffer
|
||||
&& m_mode == airtaudio::mode_duplex
|
||||
&& m_mode == audio::orchestra::mode_duplex
|
||||
&& m_nDeviceChannels[0] < m_nDeviceChannels[1]) {
|
||||
memset(_outBuffer, 0, m_bufferSize * _info.outJump * audio::getFormatBytes(_info.outFormat));
|
||||
}
|
||||
@ -409,7 +409,7 @@ void airtaudio::Api::convertBuffer(char *_outBuffer, char *_inBuffer, airtaudio:
|
||||
}
|
||||
}
|
||||
|
||||
void airtaudio::Api::byteSwapBuffer(char *_buffer, uint32_t _samples, audio::format _format) {
|
||||
void audio::orchestra::Api::byteSwapBuffer(char *_buffer, uint32_t _samples, audio::format _format) {
|
||||
char val;
|
||||
char *ptr;
|
||||
ptr = _buffer;
|
180
audio/orchestra/Api.h
Normal file
180
audio/orchestra/Api.h
Normal file
@ -0,0 +1,180 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#ifndef __AUDIO_ORCHESTRA_API_H__
|
||||
#define __AUDIO_ORCHESTRA_API_H__
|
||||
|
||||
#include <sstream>
|
||||
#include <audio/orchestra/debug.h>
|
||||
#include <audio/orchestra/type.h>
|
||||
#include <audio/orchestra/state.h>
|
||||
#include <audio/orchestra/mode.h>
|
||||
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
const std::vector<uint32_t>& genericSampleRate();
|
||||
|
||||
/**
|
||||
* @brief airtaudio callback function prototype.
|
||||
* @param _inputBuffer For input (or duplex) streams, this buffer will hold _nbChunk of input audio chunk (nullptr if no data).
|
||||
* @param _timeInput Timestamp of the first buffer sample (recording time).
|
||||
* @param _outputBuffer For output (or duplex) streams, the client should write _nbChunk of audio chunk into this buffer (nullptr if no data).
|
||||
* @param _timeOutput Timestamp of the first buffer sample (playing time).
|
||||
* @param _nbChunk The number of chunk of input or output chunk in the buffer (same size).
|
||||
* @param _status List of error that occured in the laps of time.
|
||||
*/
|
||||
typedef std11::function<int32_t (const void* _inputBuffer,
|
||||
const std11::chrono::system_clock::time_point& _timeInput,
|
||||
void* _outputBuffer,
|
||||
const std11::chrono::system_clock::time_point& _timeOutput,
|
||||
uint32_t _nbChunk,
|
||||
const std::vector<audio::orchestra::status>& _status)> AirTAudioCallback;
|
||||
// A protected structure used for buffer conversion.
|
||||
class ConvertInfo {
|
||||
public:
|
||||
int32_t channels;
|
||||
int32_t inJump;
|
||||
int32_t outJump;
|
||||
enum audio::format inFormat;
|
||||
enum audio::format outFormat;
|
||||
std::vector<int> inOffset;
|
||||
std::vector<int> outOffset;
|
||||
};
|
||||
|
||||
class Api {
|
||||
protected:
|
||||
std::string m_name;
|
||||
public:
|
||||
Api();
|
||||
virtual ~Api();
|
||||
void setName(const std::string& _name) {
|
||||
m_name = _name;
|
||||
}
|
||||
virtual audio::orchestra::type getCurrentApi() = 0;
|
||||
virtual uint32_t getDeviceCount() = 0;
|
||||
virtual audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _device) = 0;
|
||||
// TODO : Check API ...
|
||||
virtual bool getNamedDeviceInfo(const std::string& _deviceName, audio::orchestra::DeviceInfo& _info) {
|
||||
return false;
|
||||
}
|
||||
virtual uint32_t getDefaultInputDevice();
|
||||
virtual uint32_t getDefaultOutputDevice();
|
||||
enum audio::orchestra::error openStream(audio::orchestra::StreamParameters* _outputParameters,
|
||||
audio::orchestra::StreamParameters* _inputParameters,
|
||||
audio::format _format,
|
||||
uint32_t _sampleRate,
|
||||
uint32_t* _nbChunk,
|
||||
audio::orchestra::AirTAudioCallback _callback,
|
||||
const audio::orchestra::StreamOptions& _options);
|
||||
virtual enum audio::orchestra::error closeStream();
|
||||
virtual enum audio::orchestra::error startStream();
|
||||
virtual enum audio::orchestra::error stopStream() = 0;
|
||||
virtual enum audio::orchestra::error abortStream() = 0;
|
||||
long getStreamLatency();
|
||||
uint32_t getStreamSampleRate();
|
||||
virtual std11::chrono::system_clock::time_point getStreamTime();
|
||||
bool isStreamOpen() const {
|
||||
return m_state != audio::orchestra::state_closed;
|
||||
}
|
||||
bool isStreamRunning() const {
|
||||
return m_state == audio::orchestra::state_running;
|
||||
}
|
||||
|
||||
protected:
|
||||
mutable std11::mutex m_mutex;
|
||||
audio::orchestra::AirTAudioCallback m_callback;
|
||||
uint32_t m_device[2]; // Playback and record, respectively.
|
||||
enum audio::orchestra::mode m_mode; // audio::orchestra::mode_output, audio::orchestra::mode_input, or audio::orchestra::mode_duplex.
|
||||
enum audio::orchestra::state m_state; // STOPPED, RUNNING, or CLOSED
|
||||
std::vector<char> m_userBuffer[2]; // Playback and record, respectively.
|
||||
char *m_deviceBuffer;
|
||||
bool m_doConvertBuffer[2]; // Playback and record, respectively.
|
||||
bool m_deviceInterleaved[2]; // Playback and record, respectively.
|
||||
bool m_doByteSwap[2]; // Playback and record, respectively.
|
||||
uint32_t m_sampleRate; // TODO : Rename frequency
|
||||
uint32_t m_bufferSize;
|
||||
uint32_t m_nBuffers;
|
||||
uint32_t m_nUserChannels[2]; // Playback and record, respectively. // TODO : set only one config (open inout with the same number of channels (limitation)
|
||||
uint32_t m_nDeviceChannels[2]; // Playback and record channels, respectively.
|
||||
uint32_t m_channelOffset[2]; // Playback and record, respectively.
|
||||
uint64_t m_latency[2]; // Playback and record, respectively.
|
||||
enum audio::format m_userFormat; // TODO : Remove this ==> use can only open in the Harware format ...
|
||||
enum audio::format m_deviceFormat[2]; // Playback and record, respectively.
|
||||
audio::orchestra::ConvertInfo m_convertInfo[2];
|
||||
|
||||
//std11::chrono::system_clock::time_point
|
||||
std11::chrono::system_clock::time_point m_startTime; //!< start time of the stream (restart at every stop, pause ...)
|
||||
std11::chrono::nanoseconds m_duration; //!< duration from wich the stream is started
|
||||
|
||||
/**
|
||||
* @brief api-specific method that attempts to open a device
|
||||
* with the given parameters. This function MUST be implemented by
|
||||
* all subclasses. If an error is encountered during the probe, a
|
||||
* "warning" message is reported and false is returned. A
|
||||
* successful probe is indicated by a return value of true.
|
||||
*/
|
||||
virtual bool probeDeviceOpen(uint32_t _device,
|
||||
enum audio::orchestra::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
enum audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const audio::orchestra::StreamOptions& _options);
|
||||
virtual bool probeDeviceOpenName(const std::string& _deviceName,
|
||||
audio::orchestra::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const audio::orchestra::StreamOptions& _options) { return false; }
|
||||
/**
|
||||
* @brief Increment the stream time.
|
||||
*/
|
||||
void tickStreamTime();
|
||||
/**
|
||||
* @brief Clear an RtApiStream structure.
|
||||
*/
|
||||
void clearStreamInfo();
|
||||
/**
|
||||
* @brief Check the current stream status
|
||||
*/
|
||||
enum audio::orchestra::error verifyStream();
|
||||
/**
|
||||
* @brief Protected method used to perform format, channel number, and/or interleaving
|
||||
* conversions between the user and device buffers.
|
||||
*/
|
||||
void convertBuffer(char *_outBuffer,
|
||||
char *_inBuffer,
|
||||
audio::orchestra::ConvertInfo& _info);
|
||||
|
||||
/**
|
||||
* @brief Perform byte-swapping on buffers.
|
||||
*/
|
||||
void byteSwapBuffer(char *_buffer,
|
||||
uint32_t _samples,
|
||||
enum audio::format _format);
|
||||
/**
|
||||
* @brief Sets up the parameters for buffer conversion.
|
||||
*/
|
||||
void setConvertInfo(enum audio::orchestra::mode _mode,
|
||||
uint32_t _firstChannel);
|
||||
|
||||
public:
|
||||
virtual bool isMasterOf(audio::orchestra::Api* _api) {
|
||||
return false;
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief Debug operator To display the curent element in a Human redeable information
|
||||
*/
|
||||
std::ostream& operator <<(std::ostream& _os, const audio::orchestra::type& _obj);
|
||||
|
||||
#endif
|
@ -6,15 +6,15 @@
|
||||
*/
|
||||
|
||||
//#include <etk/types.h>
|
||||
#include <airtaudio/debug.h>
|
||||
#include <airtaudio/DeviceInfo.h>
|
||||
#include <audio/orchestra/debug.h>
|
||||
#include <audio/orchestra/DeviceInfo.h>
|
||||
#include <etk/stdTools.h>
|
||||
#include <iostream>
|
||||
|
||||
#undef __class__
|
||||
#define __class__ "DeviceInfo"
|
||||
|
||||
void airtaudio::DeviceInfo::display(int32_t _tabNumber) const {
|
||||
void audio::orchestra::DeviceInfo::display(int32_t _tabNumber) const {
|
||||
std::string space;
|
||||
for (int32_t iii=0; iii<_tabNumber; ++iii) {
|
||||
space += " ";
|
||||
@ -30,7 +30,7 @@ void airtaudio::DeviceInfo::display(int32_t _tabNumber) const {
|
||||
ATA_INFO(space + "native Format: " << nativeFormats);
|
||||
}
|
||||
|
||||
std::ostream& airtaudio::operator <<(std::ostream& _os, const airtaudio::DeviceInfo& _obj) {
|
||||
std::ostream& audio::orchestra::operator <<(std::ostream& _os, const audio::orchestra::DeviceInfo& _obj) {
|
||||
_os << "{";
|
||||
_os << "probe=" << _obj.probed << ", ";
|
||||
_os << "name=" << _obj.name << ", ";
|
46
audio/orchestra/DeviceInfo.h
Normal file
46
audio/orchestra/DeviceInfo.h
Normal file
@ -0,0 +1,46 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#ifndef __AUDIO_ORCHESTRA_DEVICE_INFO_H__
|
||||
#define __AUDIO_ORCHESTRA_DEVICE_INFO_H__
|
||||
|
||||
#include <audio/format.h>
|
||||
|
||||
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
/**
|
||||
* @brief The public device information structure for returning queried values.
|
||||
*/
|
||||
class DeviceInfo {
|
||||
public:
|
||||
bool probed; //!< true if the device capabilities were successfully probed.
|
||||
std::string name; //!< Character string device identifier.
|
||||
uint32_t outputChannels; //!< Maximum output channels supported by device.
|
||||
uint32_t inputChannels; //!< Maximum input channels supported by device.
|
||||
uint32_t duplexChannels; //!< Maximum simultaneous input/output channels supported by device.
|
||||
bool isDefaultOutput; //!< true if this is the default output device.
|
||||
bool isDefaultInput; //!< true if this is the default input device.
|
||||
std::vector<uint32_t> sampleRates; //!< Supported sample rates (queried from list of standard rates).
|
||||
std::vector<audio::format> nativeFormats; //!< Bit mask of supported data formats.
|
||||
// Default constructor.
|
||||
DeviceInfo() :
|
||||
probed(false),
|
||||
outputChannels(0),
|
||||
inputChannels(0),
|
||||
duplexChannels(0),
|
||||
isDefaultOutput(false),
|
||||
isDefaultInput(false),
|
||||
nativeFormats() {}
|
||||
void display(int32_t _tabNumber = 1) const;
|
||||
};
|
||||
std::ostream& operator <<(std::ostream& _os, const audio::orchestra::DeviceInfo& _obj);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -5,5 +5,5 @@
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#include <airtaudio/Flags.h>
|
||||
#include <airtaudio/debug.h>
|
||||
#include <audio/orchestra/Flags.h>
|
||||
#include <audio/orchestra/debug.h>
|
27
audio/orchestra/Flags.h
Normal file
27
audio/orchestra/Flags.h
Normal file
@ -0,0 +1,27 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#ifndef __AUDIO_ORCHESTRA_FLAGS_H__
|
||||
#define __AUDIO_ORCHESTRA_FLAGS_H__
|
||||
|
||||
#include <etk/types.h>
|
||||
|
||||
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
class Flags {
|
||||
public:
|
||||
bool m_minimizeLatency; // Simple example ==> TODO ...
|
||||
Flags() :
|
||||
m_minimizeLatency(false) {
|
||||
// nothing to do ...
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
184
audio/orchestra/Interface.cpp
Normal file
184
audio/orchestra/Interface.cpp
Normal file
@ -0,0 +1,184 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
//#include <etk/types.h>
|
||||
#include <audio/orchestra/Interface.h>
|
||||
#include <audio/orchestra/debug.h>
|
||||
#include <iostream>
|
||||
|
||||
#undef __class__
|
||||
#define __class__ "Interface"
|
||||
|
||||
std::vector<enum audio::orchestra::type> audio::orchestra::Interface::getCompiledApi() {
|
||||
std::vector<enum audio::orchestra::type> apis;
|
||||
// The order here will control the order of RtAudio's API search in
|
||||
// the constructor.
|
||||
for (size_t iii=0; iii<m_apiAvaillable.size(); ++iii) {
|
||||
apis.push_back(m_apiAvaillable[iii].first);
|
||||
}
|
||||
return apis;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void audio::orchestra::Interface::openRtApi(enum audio::orchestra::type _api) {
|
||||
delete m_rtapi;
|
||||
m_rtapi = nullptr;
|
||||
for (size_t iii=0; iii<m_apiAvaillable.size(); ++iii) {
|
||||
ATA_INFO("try open " << m_apiAvaillable[iii].first);
|
||||
if (_api == m_apiAvaillable[iii].first) {
|
||||
ATA_INFO(" ==> call it");
|
||||
m_rtapi = m_apiAvaillable[iii].second();
|
||||
if (m_rtapi != nullptr) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO : An error occured ...
|
||||
ATA_ERROR("Error in open API ...");
|
||||
}
|
||||
|
||||
|
||||
audio::orchestra::Interface::Interface() :
|
||||
m_rtapi(nullptr) {
|
||||
ATA_DEBUG("Add interface:");
|
||||
#if defined(ORCHESTRA_BUILD_JACK)
|
||||
ATA_DEBUG(" JACK");
|
||||
addInterface(audio::orchestra::type_jack, audio::orchestra::api::Jack::Create);
|
||||
#endif
|
||||
#if defined(ORCHESTRA_BUILD_ALSA)
|
||||
ATA_DEBUG(" ALSA");
|
||||
addInterface(audio::orchestra::type_alsa, audio::orchestra::api::Alsa::Create);
|
||||
#endif
|
||||
#if defined(ORCHESTRA_BUILD_PULSE)
|
||||
ATA_DEBUG(" PULSE");
|
||||
addInterface(audio::orchestra::type_pulse, audio::orchestra::api::Pulse::Create);
|
||||
#endif
|
||||
#if defined(ORCHESTRA_BUILD_OSS)
|
||||
ATA_DEBUG(" OSS");
|
||||
addInterface(audio::orchestra::type_oss, audio::orchestra::api::Oss::Create);
|
||||
#endif
|
||||
#if defined(ORCHESTRA_BUILD_ASIO)
|
||||
ATA_DEBUG(" ASIO");
|
||||
addInterface(audio::orchestra::type_asio, audio::orchestra::api::Asio::Create);
|
||||
#endif
|
||||
#if defined(ORCHESTRA_BUILD_DS)
|
||||
ATA_DEBUG(" DS");
|
||||
addInterface(audio::orchestra::type_ds, audio::orchestra::api::Ds::Create);
|
||||
#endif
|
||||
#if defined(ORCHESTRA_BUILD_MACOSX_CORE)
|
||||
ATA_DEBUG(" CORE OSX");
|
||||
addInterface(audio::orchestra::type_coreOSX, audio::orchestra::api::Core::Create);
|
||||
#endif
|
||||
#if defined(ORCHESTRA_BUILD_IOS_CORE)
|
||||
ATA_DEBUG(" CORE IOS");
|
||||
addInterface(audio::orchestra::type_coreIOS, audio::orchestra::api::CoreIos::Create);
|
||||
#endif
|
||||
#if defined(ORCHESTRA_BUILD_JAVA)
|
||||
ATA_DEBUG(" JAVA");
|
||||
addInterface(audio::orchestra::type_java, audio::orchestra::api::Android::Create);
|
||||
#endif
|
||||
#if defined(ORCHESTRA_BUILD_DUMMY)
|
||||
ATA_DEBUG(" DUMMY");
|
||||
addInterface(audio::orchestra::type_dummy, audio::orchestra::api::Dummy::Create);
|
||||
#endif
|
||||
}
|
||||
|
||||
void audio::orchestra::Interface::addInterface(enum audio::orchestra::type _api, Api* (*_callbackCreate)()) {
|
||||
m_apiAvaillable.push_back(std::pair<enum audio::orchestra::type, Api* (*)()>(_api, _callbackCreate));
|
||||
}
|
||||
|
||||
enum audio::orchestra::error audio::orchestra::Interface::instanciate(enum audio::orchestra::type _api) {
|
||||
ATA_INFO("Instanciate API ...");
|
||||
if (m_rtapi != nullptr) {
|
||||
ATA_WARNING("Interface already started ...!");
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
if (_api != audio::orchestra::type_undefined) {
|
||||
ATA_INFO("API specified : " << _api);
|
||||
// Attempt to open the specified API.
|
||||
openRtApi(_api);
|
||||
if (m_rtapi != nullptr) {
|
||||
if (m_rtapi->getDeviceCount() != 0) {
|
||||
ATA_INFO(" ==> api open");
|
||||
}
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
// No compiled support for specified API value. Issue a debug
|
||||
// warning and continue as if no API was specified.
|
||||
ATA_ERROR("RtAudio: no compiled support for specified API argument!");
|
||||
return audio::orchestra::error_fail;
|
||||
}
|
||||
ATA_INFO("Auto choice API :");
|
||||
// Iterate through the compiled APIs and return as soon as we find
|
||||
// one with at least one device or we reach the end of the list.
|
||||
std::vector<enum audio::orchestra::type> apis = getCompiledApi();
|
||||
ATA_INFO(" find : " << apis.size() << " apis.");
|
||||
for (size_t iii=0; iii<apis.size(); ++iii) {
|
||||
ATA_INFO("try open ...");
|
||||
openRtApi(apis[iii]);
|
||||
if(m_rtapi == nullptr) {
|
||||
ATA_ERROR(" ==> can not create ...");
|
||||
continue;
|
||||
}
|
||||
if (m_rtapi->getDeviceCount() != 0) {
|
||||
ATA_INFO(" ==> api open");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (m_rtapi != nullptr) {
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
ATA_ERROR("RtAudio: no compiled API support found ... critical error!!");
|
||||
return audio::orchestra::error_fail;
|
||||
}
|
||||
|
||||
audio::orchestra::Interface::~Interface() {
|
||||
ATA_INFO("Remove interface");
|
||||
delete m_rtapi;
|
||||
m_rtapi = nullptr;
|
||||
}
|
||||
|
||||
enum audio::orchestra::error audio::orchestra::Interface::openStream(audio::orchestra::StreamParameters* _outputParameters,
|
||||
audio::orchestra::StreamParameters* _inputParameters,
|
||||
audio::format _format,
|
||||
uint32_t _sampleRate,
|
||||
uint32_t* _bufferFrames,
|
||||
audio::orchestra::AirTAudioCallback _callback,
|
||||
const audio::orchestra::StreamOptions& _options) {
|
||||
if (m_rtapi == nullptr) {
|
||||
return audio::orchestra::error_inputNull;
|
||||
}
|
||||
return m_rtapi->openStream(_outputParameters,
|
||||
_inputParameters,
|
||||
_format,
|
||||
_sampleRate,
|
||||
_bufferFrames,
|
||||
_callback,
|
||||
_options);
|
||||
}
|
||||
|
||||
bool audio::orchestra::Interface::isMasterOf(audio::orchestra::Interface& _interface) {
|
||||
if (m_rtapi == nullptr) {
|
||||
ATA_ERROR("Current Master API is nullptr ...");
|
||||
return false;
|
||||
}
|
||||
if (_interface.m_rtapi == nullptr) {
|
||||
ATA_ERROR("Current Slave API is nullptr ...");
|
||||
return false;
|
||||
}
|
||||
if (m_rtapi->getCurrentApi() != _interface.m_rtapi->getCurrentApi()) {
|
||||
ATA_ERROR("Can not link 2 Interface with not the same Low level type (?)");//" << _interface.m_adac->getCurrentApi() << " != " << m_adac->getCurrentApi() << ")");
|
||||
return false;
|
||||
}
|
||||
if (m_rtapi->getCurrentApi() != audio::orchestra::type_alsa) {
|
||||
ATA_ERROR("Link 2 device together work only if the interafec is ?");// << audio::orchestra::type_alsa << " not for " << m_rtapi->getCurrentApi());
|
||||
return false;
|
||||
}
|
||||
return m_rtapi->isMasterOf(_interface.m_rtapi);
|
||||
}
|
||||
|
320
audio/orchestra/Interface.h
Normal file
320
audio/orchestra/Interface.h
Normal file
@ -0,0 +1,320 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#ifndef __AUDIO_ORCHESTRA_INTERFACE_H__
|
||||
#define __AUDIO_ORCHESTRA_INTERFACE_H__
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <audio/orchestra/base.h>
|
||||
#include <audio/orchestra/CallbackInfo.h>
|
||||
#include <audio/orchestra/Api.h>
|
||||
#include <audio/orchestra/api/Alsa.h>
|
||||
#include <audio/orchestra/api/Android.h>
|
||||
#include <audio/orchestra/api/Asio.h>
|
||||
#include <audio/orchestra/api/Core.h>
|
||||
#include <audio/orchestra/api/CoreIos.h>
|
||||
#include <audio/orchestra/api/Ds.h>
|
||||
#include <audio/orchestra/api/Dummy.h>
|
||||
#include <audio/orchestra/api/Jack.h>
|
||||
#include <audio/orchestra/api/Oss.h>
|
||||
#include <audio/orchestra/api/Pulse.h>
|
||||
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
/**
|
||||
* @brief audio::orchestra::Interface class declaration.
|
||||
*
|
||||
* audio::orchestra::Interface is a "controller" used to select an available audio i/o
|
||||
* interface. It presents a common API for the user to call but all
|
||||
* functionality is implemented by the class RtApi and its
|
||||
* subclasses. RtAudio creates an instance of an RtApi subclass
|
||||
* based on the user's API choice. If no choice is made, RtAudio
|
||||
* attempts to make a "logical" API selection.
|
||||
*/
|
||||
class Interface {
|
||||
protected:
|
||||
std::vector<std::pair<enum audio::orchestra::type, Api* (*)()> > m_apiAvaillable;
|
||||
protected:
|
||||
audio::orchestra::Api *m_rtapi;
|
||||
public:
|
||||
void setName(const std::string& _name) {
|
||||
if (m_rtapi == nullptr) {
|
||||
|
||||
return;
|
||||
}
|
||||
m_rtapi->setName(_name);
|
||||
}
|
||||
/**
|
||||
* @brief A static function to determine the available compiled audio APIs.
|
||||
*
|
||||
* The values returned in the std::vector can be compared against
|
||||
* the enumerated list values. Note that there can be more than one
|
||||
* API compiled for certain operating systems.
|
||||
*/
|
||||
std::vector<enum audio::orchestra::type> getCompiledApi();
|
||||
/**
|
||||
* @brief The class constructor.
|
||||
* @note the creating of the basic instance is done by Instanciate
|
||||
*/
|
||||
Interface();
|
||||
/**
|
||||
* @brief The destructor.
|
||||
*
|
||||
* If a stream is running or open, it will be stopped and closed
|
||||
* automatically.
|
||||
*/
|
||||
virtual ~Interface();
|
||||
/**
|
||||
* @brief Add an interface of the Possible List.
|
||||
* @param[in] _api Type of the interface.
|
||||
* @param[in] _callbackCreate API creation callback.
|
||||
*/
|
||||
void addInterface(enum audio::orchestra::type _api, Api* (*_callbackCreate)());
|
||||
/**
|
||||
* @brief Create an interface instance
|
||||
*/
|
||||
enum audio::orchestra::error instanciate(enum audio::orchestra::type _api = audio::orchestra::type_undefined);
|
||||
/**
|
||||
* @return the audio API specifier for the current instance of airtaudio.
|
||||
*/
|
||||
enum audio::orchestra::type getCurrentApi() {
|
||||
if (m_rtapi == nullptr) {
|
||||
return audio::orchestra::type_undefined;
|
||||
}
|
||||
return m_rtapi->getCurrentApi();
|
||||
}
|
||||
/**
|
||||
* @brief A public function that queries for the number of audio devices available.
|
||||
*
|
||||
* This function performs a system query of available devices each time it
|
||||
* is called, thus supporting devices connected \e after instantiation. If
|
||||
* a system error occurs during processing, a warning will be issued.
|
||||
*/
|
||||
uint32_t getDeviceCount() {
|
||||
if (m_rtapi == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
return m_rtapi->getDeviceCount();
|
||||
}
|
||||
/**
|
||||
* @brief Any device integer between 0 and getDeviceCount() - 1 is valid.
|
||||
* If an invalid argument is provided, an RtError (type = INVALID_USE)
|
||||
* will be thrown. If a device is busy or otherwise unavailable, the
|
||||
* structure member "probed" will have a value of "false" and all
|
||||
* other members are undefined. If the specified device is the
|
||||
* current default input or output device, the corresponding
|
||||
* "isDefault" member will have a value of "true".
|
||||
*
|
||||
* @return An audio::orchestra::DeviceInfo structure for a specified device number.
|
||||
*/
|
||||
audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _device) {
|
||||
if (m_rtapi == nullptr) {
|
||||
return audio::orchestra::DeviceInfo();
|
||||
}
|
||||
return m_rtapi->getDeviceInfo(_device);
|
||||
}
|
||||
audio::orchestra::DeviceInfo getDeviceInfo(const std::string& _deviceName) {
|
||||
if (m_rtapi == nullptr) {
|
||||
return audio::orchestra::DeviceInfo();
|
||||
}
|
||||
audio::orchestra::DeviceInfo info;
|
||||
m_rtapi->getNamedDeviceInfo(_deviceName, info);
|
||||
return info;
|
||||
}
|
||||
/**
|
||||
* @brief A function that returns the index of the default output device.
|
||||
*
|
||||
* If the underlying audio API does not provide a "default
|
||||
* device", or if no devices are available, the return value will be
|
||||
* 0. Note that this is a valid device identifier and it is the
|
||||
* client's responsibility to verify that a device is available
|
||||
* before attempting to open a stream.
|
||||
*/
|
||||
uint32_t getDefaultOutputDevice() {
|
||||
if (m_rtapi == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
return m_rtapi->getDefaultOutputDevice();
|
||||
}
|
||||
/**
|
||||
* @brief A function that returns the index of the default input device.
|
||||
*
|
||||
* If the underlying audio API does not provide a "default
|
||||
* device", or if no devices are available, the return value will be
|
||||
* 0. Note that this is a valid device identifier and it is the
|
||||
* client's responsibility to verify that a device is available
|
||||
* before attempting to open a stream.
|
||||
*/
|
||||
uint32_t getDefaultInputDevice() {
|
||||
if (m_rtapi == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
return m_rtapi->getDefaultInputDevice();
|
||||
}
|
||||
/**
|
||||
* @brief A public function for opening a stream with the specified parameters.
|
||||
*
|
||||
* An RtError (type = SYSTEM_ERROR) is thrown if a stream cannot be
|
||||
* opened with the specified parameters or an error occurs during
|
||||
* processing. An RtError (type = INVALID_USE) is thrown if any
|
||||
* invalid device ID or channel number parameters are specified.
|
||||
* @param _outputParameters Specifies output stream parameters to use
|
||||
* when opening a stream, including a device ID, number of channels,
|
||||
* and starting channel number. For input-only streams, this
|
||||
* argument should be nullptr. The device ID is an index value between
|
||||
* 0 and getDeviceCount() - 1.
|
||||
* @param _inputParameters Specifies input stream parameters to use
|
||||
* when opening a stream, including a device ID, number of channels,
|
||||
* and starting channel number. For output-only streams, this
|
||||
* argument should be nullptr. The device ID is an index value between
|
||||
* 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
|
||||
* 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
|
||||
* allowable value is determined.
|
||||
* @param _callback A client-defined function that will be invoked
|
||||
* when input data is available and/or output data is needed.
|
||||
* @param _options An optional pointer to a structure containing various
|
||||
* global stream options, including a list of OR'ed audio::orchestra::streamFlags
|
||||
* and a suggested number of stream buffers that can be used to
|
||||
* control stream latency. More buffers typically result in more
|
||||
* robust performance, though at a cost of greater latency. If a
|
||||
* value of zero is specified, a system-specific median value is
|
||||
* chosen. If the airtaudio_MINIMIZE_LATENCY flag bit is set, the
|
||||
* lowest allowable value is used. The actual value used is
|
||||
* returned via the structure argument. The parameter is API dependent.
|
||||
* @param _errorCallback A client-defined function that will be invoked
|
||||
* when an error has occured.
|
||||
*/
|
||||
enum audio::orchestra::error openStream(audio::orchestra::StreamParameters *_outputParameters,
|
||||
audio::orchestra::StreamParameters *_inputParameters,
|
||||
enum audio::format _format,
|
||||
uint32_t _sampleRate,
|
||||
uint32_t* _bufferFrames,
|
||||
audio::orchestra::AirTAudioCallback _callback,
|
||||
const audio::orchestra::StreamOptions& _options = audio::orchestra::StreamOptions());
|
||||
|
||||
/**
|
||||
* @brief A function that closes a stream and frees any associated stream memory.
|
||||
*
|
||||
* If a stream is not open, this function issues a warning and
|
||||
* returns (no exception is thrown).
|
||||
*/
|
||||
enum audio::orchestra::error closeStream() {
|
||||
if (m_rtapi == nullptr) {
|
||||
return audio::orchestra::error_inputNull;
|
||||
}
|
||||
return m_rtapi->closeStream();
|
||||
}
|
||||
/**
|
||||
* @brief A function that starts a stream.
|
||||
*
|
||||
* An RtError (type = SYSTEM_ERROR) is thrown if an error occurs
|
||||
* during processing. An RtError (type = INVALID_USE) is thrown if a
|
||||
* stream is not open. A warning is issued if the stream is already
|
||||
* running.
|
||||
*/
|
||||
enum audio::orchestra::error startStream() {
|
||||
if (m_rtapi == nullptr) {
|
||||
return audio::orchestra::error_inputNull;
|
||||
}
|
||||
return m_rtapi->startStream();
|
||||
}
|
||||
/**
|
||||
* @brief Stop a stream, allowing any samples remaining in the output queue to be played.
|
||||
*
|
||||
* An RtError (type = SYSTEM_ERROR) is thrown if an error occurs
|
||||
* during processing. An RtError (type = INVALID_USE) is thrown if a
|
||||
* stream is not open. A warning is issued if the stream is already
|
||||
* stopped.
|
||||
*/
|
||||
enum audio::orchestra::error stopStream() {
|
||||
if (m_rtapi == nullptr) {
|
||||
return audio::orchestra::error_inputNull;
|
||||
}
|
||||
return m_rtapi->stopStream();
|
||||
}
|
||||
/**
|
||||
* @brief Stop a stream, discarding any samples remaining in the input/output queue.
|
||||
* An RtError (type = SYSTEM_ERROR) is thrown if an error occurs
|
||||
* during processing. An RtError (type = INVALID_USE) is thrown if a
|
||||
* stream is not open. A warning is issued if the stream is already
|
||||
* stopped.
|
||||
*/
|
||||
enum audio::orchestra::error abortStream() {
|
||||
if (m_rtapi == nullptr) {
|
||||
return audio::orchestra::error_inputNull;
|
||||
}
|
||||
return m_rtapi->abortStream();
|
||||
}
|
||||
/**
|
||||
* @return true if a stream is open and false if not.
|
||||
*/
|
||||
bool isStreamOpen() const {
|
||||
if (m_rtapi == nullptr) {
|
||||
return false;
|
||||
}
|
||||
return m_rtapi->isStreamOpen();
|
||||
}
|
||||
/**
|
||||
* @return true if the stream is running and false if it is stopped or not open.
|
||||
*/
|
||||
bool isStreamRunning() const {
|
||||
if (m_rtapi == nullptr) {
|
||||
return false;
|
||||
}
|
||||
return m_rtapi->isStreamRunning();
|
||||
}
|
||||
/**
|
||||
* @brief If a stream is not open, an RtError (type = INVALID_USE) will be thrown.
|
||||
* @return the number of elapsed seconds since the stream was started.
|
||||
*/
|
||||
std11::chrono::system_clock::time_point getStreamTime() {
|
||||
if (m_rtapi == nullptr) {
|
||||
return std11::chrono::system_clock::time_point();
|
||||
}
|
||||
return m_rtapi->getStreamTime();
|
||||
}
|
||||
/**
|
||||
* @brief The stream latency refers to delay in audio input and/or output
|
||||
* caused by internal buffering by the audio system and/or hardware.
|
||||
* For duplex streams, the returned value will represent the sum of
|
||||
* the input and output latencies. If a stream is not open, an
|
||||
* RtError (type = INVALID_USE) will be thrown. If the API does not
|
||||
* report latency, the return value will be zero.
|
||||
* @return The internal stream latency in sample frames.
|
||||
*/
|
||||
long getStreamLatency() {
|
||||
if (m_rtapi == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
return m_rtapi->getStreamLatency();
|
||||
}
|
||||
/**
|
||||
* @brief On some systems, the sample rate used may be slightly different
|
||||
* than that specified in the stream parameters. If a stream is not
|
||||
* open, an RtError (type = INVALID_USE) will be thrown.
|
||||
* @return Returns actual sample rate in use by the stream.
|
||||
*/
|
||||
uint32_t getStreamSampleRate() {
|
||||
if (m_rtapi == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
return m_rtapi->getStreamSampleRate();
|
||||
}
|
||||
bool isMasterOf(audio::orchestra::Interface& _interface);
|
||||
protected:
|
||||
void openRtApi(enum audio::orchestra::type _api);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
45
audio/orchestra/StreamOptions.cpp
Normal file
45
audio/orchestra/StreamOptions.cpp
Normal file
@ -0,0 +1,45 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#include <audio/orchestra/StreamOptions.h>
|
||||
#include <etk/stdTools.h>
|
||||
#include <audio/orchestra/debug.h>
|
||||
|
||||
static const char* listValue[] = {
|
||||
"hardware",
|
||||
"trigered",
|
||||
"soft"
|
||||
};
|
||||
|
||||
std::ostream& audio::orchestra::operator <<(std::ostream& _os, enum audio::orchestra::timestampMode _obj) {
|
||||
_os << listValue[_obj];
|
||||
return _os;
|
||||
}
|
||||
|
||||
namespace etk {
|
||||
template <> bool from_string<enum audio::orchestra::timestampMode>(enum audio::orchestra::timestampMode& _variableRet, const std::string& _value) {
|
||||
if (_value == "hardware") {
|
||||
_variableRet = audio::orchestra::timestampMode_Hardware;
|
||||
return true;
|
||||
}
|
||||
if (_value == "trigered") {
|
||||
_variableRet = audio::orchestra::timestampMode_trigered;
|
||||
return true;
|
||||
}
|
||||
if (_value == "soft") {
|
||||
_variableRet = audio::orchestra::timestampMode_soft;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <enum audio::orchestra::timestampMode> std::string to_string(const enum audio::orchestra::timestampMode& _variable) {
|
||||
return listValue[_variable];
|
||||
}
|
||||
}
|
||||
|
||||
|
39
audio/orchestra/StreamOptions.h
Normal file
39
audio/orchestra/StreamOptions.h
Normal file
@ -0,0 +1,39 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#ifndef __AUDIO_ORCHESTRA_STREAM_OPTION_H__
|
||||
#define __AUDIO_ORCHESTRA_STREAM_OPTION_H__
|
||||
|
||||
#include <audio/orchestra/Flags.h>
|
||||
|
||||
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
enum timestampMode {
|
||||
timestampMode_Hardware, //!< enable harware timestamp
|
||||
timestampMode_trigered, //!< get harware triger time stamp and ingrement with duration
|
||||
timestampMode_soft, //!< Simulate all timestamp.
|
||||
};
|
||||
std::ostream& operator <<(std::ostream& _os, enum audio::orchestra::timestampMode _obj);
|
||||
|
||||
class StreamOptions {
|
||||
public:
|
||||
audio::orchestra::Flags flags; //!< A bit-mask of stream flags
|
||||
uint32_t numberOfBuffers; //!< Number of stream buffers.
|
||||
std::string streamName; //!< A stream name (currently used only in Jack).
|
||||
enum timestampMode mode; //!< mode of timestamping data...
|
||||
// Default constructor.
|
||||
StreamOptions() :
|
||||
flags(),
|
||||
numberOfBuffers(0),
|
||||
mode(timestampMode_Hardware) {}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
35
audio/orchestra/StreamParameters.h
Normal file
35
audio/orchestra/StreamParameters.h
Normal file
@ -0,0 +1,35 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#ifndef __AUDIO_ORCHESTRA_STREAM_PARAMETER_H__
|
||||
#define __AUDIO_ORCHESTRA_STREAM_PARAMETER_H__
|
||||
|
||||
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
/**
|
||||
* @brief The structure for specifying input or ouput stream parameters.
|
||||
*/
|
||||
class StreamParameters {
|
||||
public:
|
||||
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(-1),
|
||||
nChannels(0),
|
||||
firstChannel(0) {
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -6,64 +6,66 @@
|
||||
*/
|
||||
|
||||
|
||||
#if defined(__LINUX_ALSA__)
|
||||
#if defined(ORCHESTRA_BUILD_ALSA)
|
||||
|
||||
#include <alsa/asoundlib.h>
|
||||
#include <unistd.h>
|
||||
#include <airtaudio/Interface.h>
|
||||
#include <airtaudio/debug.h>
|
||||
#include <audio/orchestra/Interface.h>
|
||||
#include <audio/orchestra/debug.h>
|
||||
#include <etk/stdTools.h>
|
||||
#include <etk/thread/tools.h>
|
||||
#include <limits.h>
|
||||
#include <airtaudio/api/Alsa.h>
|
||||
#include <audio/orchestra/api/Alsa.h>
|
||||
|
||||
#undef __class__
|
||||
#define __class__ "api::Alsa"
|
||||
|
||||
airtaudio::Api* airtaudio::api::Alsa::Create() {
|
||||
return new airtaudio::api::Alsa();
|
||||
audio::orchestra::Api* audio::orchestra::api::Alsa::Create() {
|
||||
return new audio::orchestra::api::Alsa();
|
||||
}
|
||||
|
||||
namespace airtaudio {
|
||||
namespace api {
|
||||
class AlsaPrivate {
|
||||
public:
|
||||
snd_pcm_t *handles[2];
|
||||
bool synchronized;
|
||||
bool xrun[2];
|
||||
std11::condition_variable runnable_cv;
|
||||
bool runnable;
|
||||
std11::thread* thread;
|
||||
bool threadRunning;
|
||||
enum timestampMode timeMode; //!< the timestamp of the flow came from the harware.
|
||||
AlsaPrivate() :
|
||||
synchronized(false),
|
||||
runnable(false),
|
||||
thread(nullptr),
|
||||
threadRunning(false),
|
||||
timeMode(timestampMode_soft) {
|
||||
handles[0] = nullptr;
|
||||
handles[1] = nullptr;
|
||||
xrun[0] = false;
|
||||
xrun[1] = false;
|
||||
// TODO : Wait thread ...
|
||||
}
|
||||
};
|
||||
};
|
||||
};
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
namespace api {
|
||||
class AlsaPrivate {
|
||||
public:
|
||||
snd_pcm_t *handles[2];
|
||||
bool synchronized;
|
||||
bool xrun[2];
|
||||
std11::condition_variable runnable_cv;
|
||||
bool runnable;
|
||||
std11::thread* thread;
|
||||
bool threadRunning;
|
||||
enum timestampMode timeMode; //!< the timestamp of the flow came from the harware.
|
||||
AlsaPrivate() :
|
||||
synchronized(false),
|
||||
runnable(false),
|
||||
thread(nullptr),
|
||||
threadRunning(false),
|
||||
timeMode(timestampMode_soft) {
|
||||
handles[0] = nullptr;
|
||||
handles[1] = nullptr;
|
||||
xrun[0] = false;
|
||||
xrun[1] = false;
|
||||
// TODO : Wait thread ...
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
airtaudio::api::Alsa::Alsa() :
|
||||
m_private(new airtaudio::api::AlsaPrivate()) {
|
||||
audio::orchestra::api::Alsa::Alsa() :
|
||||
m_private(new audio::orchestra::api::AlsaPrivate()) {
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
airtaudio::api::Alsa::~Alsa() {
|
||||
if (m_state != airtaudio::state_closed) {
|
||||
audio::orchestra::api::Alsa::~Alsa() {
|
||||
if (m_state != audio::orchestra::state_closed) {
|
||||
closeStream();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t airtaudio::api::Alsa::getDeviceCount() {
|
||||
uint32_t audio::orchestra::api::Alsa::getDeviceCount() {
|
||||
unsigned nDevices = 0;
|
||||
int32_t result= -1;
|
||||
int32_t subdevice = -1;
|
||||
@ -78,7 +80,7 @@ uint32_t airtaudio::api::Alsa::getDeviceCount() {
|
||||
result = snd_ctl_open(&handle, name, 0);
|
||||
if (result < 0) {
|
||||
ATA_ERROR("control open, card = " << card << ", " << snd_strerror(result) << ".");
|
||||
// TODO : Return error airtaudio::error_warning;
|
||||
// TODO : Return error audio::orchestra::error_warning;
|
||||
goto nextcard;
|
||||
}
|
||||
subdevice = -1;
|
||||
@ -86,7 +88,7 @@ uint32_t airtaudio::api::Alsa::getDeviceCount() {
|
||||
result = snd_ctl_pcm_next_device(handle, &subdevice);
|
||||
if (result < 0) {
|
||||
ATA_ERROR("control next device, card = " << card << ", " << snd_strerror(result) << ".");
|
||||
// TODO : Return error airtaudio::error_warning;
|
||||
// TODO : Return error audio::orchestra::error_warning;
|
||||
break;
|
||||
}
|
||||
if (subdevice < 0) {
|
||||
@ -101,7 +103,7 @@ nextcard:
|
||||
return nDevices;
|
||||
}
|
||||
|
||||
bool airtaudio::api::Alsa::getNamedDeviceInfoLocal(const std::string& _deviceName, airtaudio::DeviceInfo& _info, int32_t _cardId, int32_t _subdevice, int32_t _localDeviceId) {
|
||||
bool audio::orchestra::api::Alsa::getNamedDeviceInfoLocal(const std::string& _deviceName, audio::orchestra::DeviceInfo& _info, int32_t _cardId, int32_t _subdevice, int32_t _localDeviceId) {
|
||||
int32_t result;
|
||||
snd_ctl_t *chandle;
|
||||
int32_t openMode = SND_PCM_ASYNC;
|
||||
@ -141,7 +143,7 @@ bool airtaudio::api::Alsa::getNamedDeviceInfoLocal(const std::string& _deviceNam
|
||||
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) << ".");
|
||||
// TODO : Return airtaudio::error_warning;
|
||||
// TODO : Return audio::orchestra::error_warning;
|
||||
goto captureProbe;
|
||||
}
|
||||
// The device is open ... fill the parameter structure.
|
||||
@ -149,7 +151,7 @@ bool airtaudio::api::Alsa::getNamedDeviceInfoLocal(const std::string& _deviceNam
|
||||
if (result < 0) {
|
||||
snd_pcm_close(phandle);
|
||||
ATA_ERROR("snd_pcm_hw_params error for device (" << _deviceName << "), " << snd_strerror(result) << ".");
|
||||
// TODO : Return airtaudio::error_warning;
|
||||
// TODO : Return audio::orchestra::error_warning;
|
||||
goto captureProbe;
|
||||
}
|
||||
// Get output channel information.
|
||||
@ -158,7 +160,7 @@ bool airtaudio::api::Alsa::getNamedDeviceInfoLocal(const std::string& _deviceNam
|
||||
if (result < 0) {
|
||||
snd_pcm_close(phandle);
|
||||
ATA_ERROR("error getting device (" << _deviceName << ") output channels, " << snd_strerror(result) << ".");
|
||||
// TODO : Return airtaudio::error_warning;
|
||||
// TODO : Return audio::orchestra::error_warning;
|
||||
goto captureProbe;
|
||||
}
|
||||
_info.outputChannels = value;
|
||||
@ -182,7 +184,7 @@ 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) << ".");
|
||||
// TODO : Return airtaudio::error_warning;
|
||||
// TODO : Return audio::orchestra::error_warning;
|
||||
if (_info.outputChannels == 0) {
|
||||
return true;
|
||||
}
|
||||
@ -193,7 +195,7 @@ captureProbe:
|
||||
if (result < 0) {
|
||||
snd_pcm_close(phandle);
|
||||
ATA_ERROR("snd_pcm_hw_params error for device (" << _deviceName << "), " << snd_strerror(result) << ".");
|
||||
// TODO : Return airtaudio::error_warning;
|
||||
// TODO : Return audio::orchestra::error_warning;
|
||||
if (_info.outputChannels == 0) {
|
||||
return true;
|
||||
}
|
||||
@ -203,7 +205,7 @@ captureProbe:
|
||||
if (result < 0) {
|
||||
snd_pcm_close(phandle);
|
||||
ATA_ERROR("error getting device (" << _deviceName << ") input channels, " << snd_strerror(result) << ".");
|
||||
// TODO : Return airtaudio::error_warning;
|
||||
// TODO : Return audio::orchestra::error_warning;
|
||||
if (_info.outputChannels == 0) {
|
||||
return true;
|
||||
}
|
||||
@ -241,7 +243,7 @@ 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) << ".");
|
||||
// TODO : Return airtaudio::error_warning;
|
||||
// TODO : Return audio::orchestra::error_warning;
|
||||
return false;
|
||||
}
|
||||
// The device is open ... fill the parameter structure.
|
||||
@ -249,13 +251,13 @@ probeParameters:
|
||||
if (result < 0) {
|
||||
snd_pcm_close(phandle);
|
||||
ATA_ERROR("snd_pcm_hw_params error for device (" << _deviceName << "), " << snd_strerror(result) << ".");
|
||||
// TODO : Return airtaudio::error_warning;
|
||||
// TODO : Return audio::orchestra::error_warning;
|
||||
return false;
|
||||
}
|
||||
// Test our discrete set of sample rate values.
|
||||
_info.sampleRates.clear();
|
||||
for (std::vector<uint32_t>::const_iterator it(airtaudio::genericSampleRate().begin());
|
||||
it != airtaudio::genericSampleRate().end();
|
||||
for (std::vector<uint32_t>::const_iterator it(audio::orchestra::genericSampleRate().begin());
|
||||
it != audio::orchestra::genericSampleRate().end();
|
||||
++it ) {
|
||||
if (snd_pcm_hw_params_test_rate(phandle, params, *it, 0) == 0) {
|
||||
_info.sampleRates.push_back(*it);
|
||||
@ -264,7 +266,7 @@ probeParameters:
|
||||
if (_info.sampleRates.size() == 0) {
|
||||
snd_pcm_close(phandle);
|
||||
ATA_ERROR("no supported sample rates found for device (" << _deviceName << ").");
|
||||
// TODO : Return airtaudio::error_warning;
|
||||
// TODO : Return audio::orchestra::error_warning;
|
||||
return false;
|
||||
}
|
||||
// Probe the supported data formats ... we don't care about endian-ness just yet
|
||||
@ -297,7 +299,7 @@ probeParameters:
|
||||
// Check that we have at least one supported format
|
||||
if (_info.nativeFormats.size() == 0) {
|
||||
ATA_ERROR("pcm device (" << _deviceName << ") data format not supported by RtAudio.");
|
||||
// TODO : Return airtaudio::error_warning;
|
||||
// TODO : Return audio::orchestra::error_warning;
|
||||
return false;
|
||||
}
|
||||
// Get the device name
|
||||
@ -318,8 +320,8 @@ probeParameters:
|
||||
return true;
|
||||
}
|
||||
|
||||
airtaudio::DeviceInfo airtaudio::api::Alsa::getDeviceInfo(uint32_t _device) {
|
||||
airtaudio::DeviceInfo info;
|
||||
audio::orchestra::DeviceInfo audio::orchestra::api::Alsa::getDeviceInfo(uint32_t _device) {
|
||||
audio::orchestra::DeviceInfo info;
|
||||
/*
|
||||
ATA_WARNING("plop");
|
||||
getDeviceInfo("hw:0,0,0", info);
|
||||
@ -366,12 +368,12 @@ airtaudio::DeviceInfo airtaudio::api::Alsa::getDeviceInfo(uint32_t _device) {
|
||||
}
|
||||
if (nDevices == 0) {
|
||||
ATA_ERROR("no devices found!");
|
||||
// TODO : airtaudio::error_invalidUse;
|
||||
// TODO : audio::orchestra::error_invalidUse;
|
||||
return info;
|
||||
}
|
||||
if (_device >= nDevices) {
|
||||
ATA_ERROR("device ID is invalid!");
|
||||
// TODO : airtaudio::error_invalidUse;
|
||||
// TODO : audio::orchestra::error_invalidUse;
|
||||
return info;
|
||||
}
|
||||
|
||||
@ -379,17 +381,17 @@ 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
|
||||
if ( m_state != audio::orchestra::state_closed
|
||||
&& ( m_device[0] == _device
|
||||
|| m_device[1] == _device)) {
|
||||
if (_device >= m_devices.size()) {
|
||||
ATA_ERROR("device ID was not present before stream was opened.");
|
||||
// TODO : return airtaudio::error_warning;
|
||||
// TODO : return audio::orchestra::error_warning;
|
||||
return info;
|
||||
}
|
||||
return m_devices[ _device ];
|
||||
}
|
||||
bool ret = airtaudio::api::Alsa::getNamedDeviceInfoLocal(name, info, card, subdevice, _device);
|
||||
bool ret = audio::orchestra::api::Alsa::getNamedDeviceInfoLocal(name, info, card, subdevice, _device);
|
||||
if (ret == false) {
|
||||
// TODO : ...
|
||||
return info;
|
||||
@ -397,7 +399,7 @@ foundDevice:
|
||||
return info;
|
||||
}
|
||||
|
||||
void airtaudio::api::Alsa::saveDeviceInfo() {
|
||||
void audio::orchestra::api::Alsa::saveDeviceInfo() {
|
||||
m_devices.clear();
|
||||
uint32_t nDevices = getDeviceCount();
|
||||
m_devices.resize(nDevices);
|
||||
@ -406,14 +408,14 @@ void airtaudio::api::Alsa::saveDeviceInfo() {
|
||||
}
|
||||
}
|
||||
|
||||
bool airtaudio::api::Alsa::probeDeviceOpen(uint32_t _device,
|
||||
airtaudio::mode _mode,
|
||||
bool audio::orchestra::api::Alsa::probeDeviceOpen(uint32_t _device,
|
||||
audio::orchestra::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const airtaudio::StreamOptions& _options) {
|
||||
const audio::orchestra::StreamOptions& _options) {
|
||||
// I'm not using the "plug" interface ... too much inconsistent behavior.
|
||||
unsigned nDevices = 0;
|
||||
int32_t result, subdevice, card;
|
||||
@ -461,14 +463,14 @@ foundDevice:
|
||||
return probeDeviceOpenName(name, _mode, _channels, _firstChannel, _sampleRate, _format, _bufferSize, _options);
|
||||
}
|
||||
|
||||
bool airtaudio::api::Alsa::probeDeviceOpenName(const std::string& _deviceName,
|
||||
airtaudio::mode _mode,
|
||||
bool audio::orchestra::api::Alsa::probeDeviceOpenName(const std::string& _deviceName,
|
||||
audio::orchestra::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const airtaudio::StreamOptions& _options) {
|
||||
const audio::orchestra::StreamOptions& _options) {
|
||||
ATA_DEBUG("Probe ALSA device : ");
|
||||
ATA_DEBUG(" _deviceName=" << _deviceName);
|
||||
ATA_DEBUG(" _mode=" << _mode);
|
||||
@ -487,14 +489,14 @@ bool airtaudio::api::Alsa::probeDeviceOpenName(const std::string& _deviceName,
|
||||
// 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().
|
||||
if ( _mode == airtaudio::mode_output
|
||||
|| ( _mode == airtaudio::mode_input
|
||||
&& m_mode != airtaudio::mode_output)) {
|
||||
if ( _mode == audio::orchestra::mode_output
|
||||
|| ( _mode == audio::orchestra::mode_input
|
||||
&& m_mode != audio::orchestra::mode_output)) {
|
||||
// only do once
|
||||
this->saveDeviceInfo();
|
||||
}
|
||||
snd_pcm_stream_t stream;
|
||||
if (_mode == airtaudio::mode_output) {
|
||||
if (_mode == audio::orchestra::mode_output) {
|
||||
stream = SND_PCM_STREAM_PLAYBACK;
|
||||
} else {
|
||||
stream = SND_PCM_STREAM_CAPTURE;
|
||||
@ -504,7 +506,7 @@ bool airtaudio::api::Alsa::probeDeviceOpenName(const std::string& _deviceName,
|
||||
result = snd_pcm_open(&phandle, _deviceName.c_str(), stream, openMode);
|
||||
ATA_DEBUG("Configure Mode : SND_PCM_ASYNC");
|
||||
if (result < 0) {
|
||||
if (_mode == airtaudio::mode_output) {
|
||||
if (_mode == audio::orchestra::mode_output) {
|
||||
ATA_ERROR("pcm device (" << _deviceName << ") won't open for output.");
|
||||
} else {
|
||||
ATA_ERROR("pcm device (" << _deviceName << ") won't open for input.");
|
||||
@ -660,8 +662,8 @@ bool airtaudio::api::Alsa::probeDeviceOpenName(const std::string& _deviceName,
|
||||
m_sampleRate = _sampleRate;
|
||||
// If attempting to setup a duplex stream, the bufferSize parameter
|
||||
// MUST be the same in both directions!
|
||||
if ( m_mode == airtaudio::mode_output
|
||||
&& _mode == airtaudio::mode_input
|
||||
if ( m_mode == audio::orchestra::mode_output
|
||||
&& _mode == audio::orchestra::mode_input
|
||||
&& *_bufferSize != m_bufferSize) {
|
||||
snd_pcm_close(phandle);
|
||||
ATA_ERROR("system error setting buffer size for duplex stream on device (" << _deviceName << ").");
|
||||
@ -788,8 +790,8 @@ bool airtaudio::api::Alsa::probeDeviceOpenName(const std::string& _deviceName,
|
||||
if (m_doConvertBuffer[modeToIdTable(_mode)]) {
|
||||
bool makeBuffer = true;
|
||||
bufferBytes = m_nDeviceChannels[modeToIdTable(_mode)] * audio::getFormatBytes(m_deviceFormat[modeToIdTable(_mode)]);
|
||||
if (_mode == airtaudio::mode_input) {
|
||||
if ( m_mode == airtaudio::mode_output
|
||||
if (_mode == audio::orchestra::mode_input) {
|
||||
if ( m_mode == audio::orchestra::mode_output
|
||||
&& m_deviceBuffer) {
|
||||
uint64_t bytesOut = m_nDeviceChannels[0] * audio::getFormatBytes(m_deviceFormat[0]);
|
||||
if (bufferBytes <= bytesOut) {
|
||||
@ -813,29 +815,29 @@ bool airtaudio::api::Alsa::probeDeviceOpenName(const std::string& _deviceName,
|
||||
m_nBuffers = periods;
|
||||
ATA_INFO("ALSA NB buffer = " << m_nBuffers);
|
||||
// TODO : m_device[modeToIdTable(_mode)] = _device;
|
||||
m_state = airtaudio::state_stopped;
|
||||
m_state = audio::orchestra::state_stopped;
|
||||
// Setup the buffer conversion information structure.
|
||||
if (m_doConvertBuffer[modeToIdTable(_mode)]) {
|
||||
setConvertInfo(_mode, _firstChannel);
|
||||
}
|
||||
// Setup thread if necessary.
|
||||
if ( m_mode == airtaudio::mode_output
|
||||
&& _mode == airtaudio::mode_input) {
|
||||
if ( m_mode == audio::orchestra::mode_output
|
||||
&& _mode == audio::orchestra::mode_input) {
|
||||
// We had already set up an output stream.
|
||||
m_mode = airtaudio::mode_duplex;
|
||||
m_mode = audio::orchestra::mode_duplex;
|
||||
// Link the streams if possible.
|
||||
m_private->synchronized = false;
|
||||
if (snd_pcm_link(m_private->handles[0], m_private->handles[1]) == 0) {
|
||||
m_private->synchronized = true;
|
||||
} else {
|
||||
ATA_ERROR("unable to synchronize input and output devices.");
|
||||
// TODO : airtaudio::error_warning;
|
||||
// TODO : audio::orchestra::error_warning;
|
||||
}
|
||||
} else {
|
||||
m_mode = _mode;
|
||||
// Setup callback thread.
|
||||
m_private->threadRunning = true;
|
||||
m_private->thread = new std11::thread(&airtaudio::api::Alsa::alsaCallbackEvent, this);
|
||||
m_private->thread = new std11::thread(&audio::orchestra::api::Alsa::alsaCallbackEvent, this);
|
||||
if (m_private->thread == nullptr) {
|
||||
m_private->threadRunning = false;
|
||||
ATA_ERROR("creating callback thread!");
|
||||
@ -863,18 +865,18 @@ error:
|
||||
free(m_deviceBuffer);
|
||||
m_deviceBuffer = 0;
|
||||
}
|
||||
m_state = airtaudio::state_closed;
|
||||
m_state = audio::orchestra::state_closed;
|
||||
return false;
|
||||
}
|
||||
|
||||
enum airtaudio::error airtaudio::api::Alsa::closeStream() {
|
||||
if (m_state == airtaudio::state_closed) {
|
||||
enum audio::orchestra::error audio::orchestra::api::Alsa::closeStream() {
|
||||
if (m_state == audio::orchestra::state_closed) {
|
||||
ATA_ERROR("no open stream to close!");
|
||||
return airtaudio::error_warning;
|
||||
return audio::orchestra::error_warning;
|
||||
}
|
||||
m_private->threadRunning = false;
|
||||
m_mutex.lock();
|
||||
if (m_state == airtaudio::state_stopped) {
|
||||
if (m_state == audio::orchestra::state_stopped) {
|
||||
m_private->runnable = true;
|
||||
m_private->runnable_cv.notify_one();
|
||||
}
|
||||
@ -883,14 +885,14 @@ enum airtaudio::error airtaudio::api::Alsa::closeStream() {
|
||||
m_private->thread->join();
|
||||
m_private->thread = nullptr;
|
||||
}
|
||||
if (m_state == airtaudio::state_running) {
|
||||
m_state = airtaudio::state_stopped;
|
||||
if ( m_mode == airtaudio::mode_output
|
||||
|| m_mode == airtaudio::mode_duplex) {
|
||||
if (m_state == audio::orchestra::state_running) {
|
||||
m_state = audio::orchestra::state_stopped;
|
||||
if ( m_mode == audio::orchestra::mode_output
|
||||
|| m_mode == audio::orchestra::mode_duplex) {
|
||||
snd_pcm_drop(m_private->handles[0]);
|
||||
}
|
||||
if ( m_mode == airtaudio::mode_input
|
||||
|| m_mode == airtaudio::mode_duplex) {
|
||||
if ( m_mode == audio::orchestra::mode_input
|
||||
|| m_mode == audio::orchestra::mode_duplex) {
|
||||
snd_pcm_drop(m_private->handles[1]);
|
||||
}
|
||||
}
|
||||
@ -910,28 +912,28 @@ enum airtaudio::error airtaudio::api::Alsa::closeStream() {
|
||||
free(m_deviceBuffer);
|
||||
m_deviceBuffer = 0;
|
||||
}
|
||||
m_mode = airtaudio::mode_unknow;
|
||||
m_state = airtaudio::state_closed;
|
||||
return airtaudio::error_none;
|
||||
m_mode = audio::orchestra::mode_unknow;
|
||||
m_state = audio::orchestra::state_closed;
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
enum airtaudio::error airtaudio::api::Alsa::startStream() {
|
||||
enum audio::orchestra::error audio::orchestra::api::Alsa::startStream() {
|
||||
// TODO : Check return ...
|
||||
//airtaudio::Api::startStream();
|
||||
//audio::orchestra::Api::startStream();
|
||||
// This method calls snd_pcm_prepare if the device isn't already in that state.
|
||||
if (verifyStream() != airtaudio::error_none) {
|
||||
return airtaudio::error_fail;
|
||||
if (verifyStream() != audio::orchestra::error_none) {
|
||||
return audio::orchestra::error_fail;
|
||||
}
|
||||
if (m_state == airtaudio::state_running) {
|
||||
if (m_state == audio::orchestra::state_running) {
|
||||
ATA_ERROR("the stream is already running!");
|
||||
return airtaudio::error_warning;
|
||||
return audio::orchestra::error_warning;
|
||||
}
|
||||
std11::unique_lock<std11::mutex> lck(m_mutex);
|
||||
int32_t result = 0;
|
||||
snd_pcm_state_t state;
|
||||
snd_pcm_t **handle = (snd_pcm_t **) m_private->handles;
|
||||
if ( m_mode == airtaudio::mode_output
|
||||
|| m_mode == airtaudio::mode_duplex) {
|
||||
if ( m_mode == audio::orchestra::mode_output
|
||||
|| m_mode == audio::orchestra::mode_duplex) {
|
||||
if (handle[0] == nullptr) {
|
||||
ATA_ERROR("send nullptr to alsa ...");
|
||||
if (handle[1] != nullptr) {
|
||||
@ -947,8 +949,8 @@ enum airtaudio::error airtaudio::api::Alsa::startStream() {
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( ( m_mode == airtaudio::mode_input
|
||||
|| m_mode == airtaudio::mode_duplex)
|
||||
if ( ( m_mode == audio::orchestra::mode_input
|
||||
|| m_mode == audio::orchestra::mode_duplex)
|
||||
&& !m_private->synchronized) {
|
||||
if (handle[1] == nullptr) {
|
||||
ATA_ERROR("send nullptr to alsa ...");
|
||||
@ -965,29 +967,29 @@ enum airtaudio::error airtaudio::api::Alsa::startStream() {
|
||||
}
|
||||
}
|
||||
}
|
||||
m_state = airtaudio::state_running;
|
||||
m_state = audio::orchestra::state_running;
|
||||
unlock:
|
||||
m_private->runnable = true;
|
||||
m_private->runnable_cv.notify_one();
|
||||
if (result >= 0) {
|
||||
return airtaudio::error_none;
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
return airtaudio::error_systemError;
|
||||
return audio::orchestra::error_systemError;
|
||||
}
|
||||
|
||||
enum airtaudio::error airtaudio::api::Alsa::stopStream() {
|
||||
if (verifyStream() != airtaudio::error_none) {
|
||||
return airtaudio::error_fail;
|
||||
enum audio::orchestra::error audio::orchestra::api::Alsa::stopStream() {
|
||||
if (verifyStream() != audio::orchestra::error_none) {
|
||||
return audio::orchestra::error_fail;
|
||||
}
|
||||
if (m_state == airtaudio::state_stopped) {
|
||||
if (m_state == audio::orchestra::state_stopped) {
|
||||
ATA_ERROR("the stream is already stopped!");
|
||||
return airtaudio::error_warning;
|
||||
return audio::orchestra::error_warning;
|
||||
}
|
||||
m_state = airtaudio::state_stopped;
|
||||
m_state = audio::orchestra::state_stopped;
|
||||
std11::unique_lock<std11::mutex> lck(m_mutex);
|
||||
int32_t result = 0;
|
||||
if ( m_mode == airtaudio::mode_output
|
||||
|| m_mode == airtaudio::mode_duplex) {
|
||||
if ( m_mode == audio::orchestra::mode_output
|
||||
|| m_mode == audio::orchestra::mode_duplex) {
|
||||
if (m_private->synchronized) {
|
||||
result = snd_pcm_drop( m_private->handles[0]);
|
||||
} else {
|
||||
@ -998,8 +1000,8 @@ enum airtaudio::error airtaudio::api::Alsa::stopStream() {
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
if ( ( m_mode == airtaudio::mode_input
|
||||
|| m_mode == airtaudio::mode_duplex)
|
||||
if ( ( m_mode == audio::orchestra::mode_input
|
||||
|| m_mode == audio::orchestra::mode_duplex)
|
||||
&& !m_private->synchronized) {
|
||||
result = snd_pcm_drop( m_private->handles[1]);
|
||||
if (result < 0) {
|
||||
@ -1009,33 +1011,33 @@ enum airtaudio::error airtaudio::api::Alsa::stopStream() {
|
||||
}
|
||||
unlock:
|
||||
if (result >= 0) {
|
||||
return airtaudio::error_none;
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
return airtaudio::error_systemError;
|
||||
return audio::orchestra::error_systemError;
|
||||
}
|
||||
|
||||
enum airtaudio::error airtaudio::api::Alsa::abortStream() {
|
||||
if (verifyStream() != airtaudio::error_none) {
|
||||
return airtaudio::error_fail;
|
||||
enum audio::orchestra::error audio::orchestra::api::Alsa::abortStream() {
|
||||
if (verifyStream() != audio::orchestra::error_none) {
|
||||
return audio::orchestra::error_fail;
|
||||
}
|
||||
if (m_state == airtaudio::state_stopped) {
|
||||
if (m_state == audio::orchestra::state_stopped) {
|
||||
ATA_ERROR("the stream is already stopped!");
|
||||
return airtaudio::error_warning;
|
||||
return audio::orchestra::error_warning;
|
||||
}
|
||||
m_state = airtaudio::state_stopped;
|
||||
m_state = audio::orchestra::state_stopped;
|
||||
std11::unique_lock<std11::mutex> lck(m_mutex);
|
||||
int32_t result = 0;
|
||||
snd_pcm_t **handle = (snd_pcm_t **) m_private->handles;
|
||||
if ( m_mode == airtaudio::mode_output
|
||||
|| m_mode == airtaudio::mode_duplex) {
|
||||
if ( m_mode == audio::orchestra::mode_output
|
||||
|| m_mode == audio::orchestra::mode_duplex) {
|
||||
result = snd_pcm_drop(handle[0]);
|
||||
if (result < 0) {
|
||||
ATA_ERROR("error aborting output pcm device, " << snd_strerror(result) << ".");
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
if ( ( m_mode == airtaudio::mode_input
|
||||
|| m_mode == airtaudio::mode_duplex)
|
||||
if ( ( m_mode == audio::orchestra::mode_input
|
||||
|| m_mode == audio::orchestra::mode_duplex)
|
||||
&& !m_private->synchronized) {
|
||||
result = snd_pcm_drop(handle[1]);
|
||||
if (result < 0) {
|
||||
@ -1045,25 +1047,25 @@ enum airtaudio::error airtaudio::api::Alsa::abortStream() {
|
||||
}
|
||||
unlock:
|
||||
if (result >= 0) {
|
||||
return airtaudio::error_none;
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
return airtaudio::error_systemError;
|
||||
return audio::orchestra::error_systemError;
|
||||
}
|
||||
|
||||
|
||||
void airtaudio::api::Alsa::alsaCallbackEvent(void *_userData) {
|
||||
airtaudio::api::Alsa* myClass = reinterpret_cast<airtaudio::api::Alsa*>(_userData);
|
||||
void audio::orchestra::api::Alsa::alsaCallbackEvent(void *_userData) {
|
||||
audio::orchestra::api::Alsa* myClass = reinterpret_cast<audio::orchestra::api::Alsa*>(_userData);
|
||||
myClass->callbackEvent();
|
||||
}
|
||||
|
||||
void airtaudio::api::Alsa::callbackEvent() {
|
||||
void audio::orchestra::api::Alsa::callbackEvent() {
|
||||
etk::thread::setName("Alsa IO-" + m_name);
|
||||
while (m_private->threadRunning == true) {
|
||||
callbackEventOneCycle();
|
||||
}
|
||||
}
|
||||
|
||||
std11::chrono::system_clock::time_point airtaudio::api::Alsa::getStreamTime() {
|
||||
std11::chrono::system_clock::time_point audio::orchestra::api::Alsa::getStreamTime() {
|
||||
//ATA_DEBUG("mode : " << m_private->timeMode);
|
||||
if (m_private->timeMode == timestampMode_Hardware) {
|
||||
snd_pcm_status_t *status = nullptr;
|
||||
@ -1146,8 +1148,8 @@ std11::chrono::system_clock::time_point airtaudio::api::Alsa::getStreamTime() {
|
||||
return m_startTime + m_duration;
|
||||
}
|
||||
|
||||
void airtaudio::api::Alsa::callbackEventOneCycle() {
|
||||
if (m_state == airtaudio::state_stopped) {
|
||||
void audio::orchestra::api::Alsa::callbackEventOneCycle() {
|
||||
if (m_state == audio::orchestra::state_stopped) {
|
||||
std11::unique_lock<std11::mutex> lck(m_mutex);
|
||||
// TODO : Set this back ....
|
||||
/*
|
||||
@ -1156,25 +1158,25 @@ void airtaudio::api::Alsa::callbackEventOneCycle() {
|
||||
}
|
||||
*/
|
||||
usleep(1000);
|
||||
if (m_state != airtaudio::state_running) {
|
||||
if (m_state != audio::orchestra::state_running) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (m_state == airtaudio::state_closed) {
|
||||
if (m_state == audio::orchestra::state_closed) {
|
||||
ATA_CRITICAL("the stream is closed ... this shouldn't happen!");
|
||||
return; // TODO : notify appl: airtaudio::error_warning;
|
||||
return; // TODO : notify appl: audio::orchestra::error_warning;
|
||||
}
|
||||
int32_t doStopStream = 0;
|
||||
std11::chrono::system_clock::time_point streamTime;
|
||||
std::vector<enum airtaudio::status> status;
|
||||
if ( m_mode != airtaudio::mode_input
|
||||
std::vector<enum audio::orchestra::status> status;
|
||||
if ( m_mode != audio::orchestra::mode_input
|
||||
&& m_private->xrun[0] == true) {
|
||||
status.push_back(airtaudio::status_underflow);
|
||||
status.push_back(audio::orchestra::status_underflow);
|
||||
m_private->xrun[0] = false;
|
||||
}
|
||||
if ( m_mode != airtaudio::mode_output
|
||||
if ( m_mode != audio::orchestra::mode_output
|
||||
&& m_private->xrun[1] == true) {
|
||||
status.push_back(airtaudio::status_overflow);
|
||||
status.push_back(audio::orchestra::status_overflow);
|
||||
m_private->xrun[1] = false;
|
||||
}
|
||||
int32_t result;
|
||||
@ -1183,12 +1185,12 @@ void airtaudio::api::Alsa::callbackEventOneCycle() {
|
||||
snd_pcm_sframes_t frames;
|
||||
audio::format format;
|
||||
|
||||
if (m_state == airtaudio::state_stopped) {
|
||||
if (m_state == audio::orchestra::state_stopped) {
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if ( m_mode == airtaudio::mode_input
|
||||
|| m_mode == airtaudio::mode_duplex) {
|
||||
if ( m_mode == audio::orchestra::mode_input
|
||||
|| m_mode == audio::orchestra::mode_duplex) {
|
||||
std11::unique_lock<std11::mutex> lck(m_mutex);
|
||||
// Setup parameters.
|
||||
if (m_doConvertBuffer[1]) {
|
||||
@ -1236,7 +1238,7 @@ void airtaudio::api::Alsa::callbackEventOneCycle() {
|
||||
ATA_ERROR("audio read error, " << snd_strerror(result) << ".");
|
||||
usleep(10000);
|
||||
}
|
||||
// TODO : Notify application ... airtaudio::error_warning;
|
||||
// TODO : Notify application ... audio::orchestra::error_warning;
|
||||
goto noInput;
|
||||
}
|
||||
// Do byte swapping if necessary.
|
||||
@ -1277,8 +1279,8 @@ noInput:
|
||||
return;
|
||||
}
|
||||
|
||||
if ( m_mode == airtaudio::mode_output
|
||||
|| m_mode == airtaudio::mode_duplex) {
|
||||
if ( m_mode == audio::orchestra::mode_output
|
||||
|| m_mode == audio::orchestra::mode_duplex) {
|
||||
std11::unique_lock<std11::mutex> lck(m_mutex);
|
||||
// Setup parameters and do buffer conversion if necessary.
|
||||
if (m_doConvertBuffer[0]) {
|
||||
@ -1322,7 +1324,7 @@ noInput:
|
||||
} else {
|
||||
ATA_ERROR("audio write error, " << snd_strerror(result) << ".");
|
||||
}
|
||||
// TODO : Notuify application airtaudio::error_warning;
|
||||
// TODO : Notuify application audio::orchestra::error_warning;
|
||||
goto unlock;
|
||||
}
|
||||
// Check stream latency
|
||||
@ -1334,23 +1336,23 @@ noInput:
|
||||
}
|
||||
|
||||
unlock:
|
||||
airtaudio::Api::tickStreamTime();
|
||||
audio::orchestra::Api::tickStreamTime();
|
||||
if (doStopStream == 1) {
|
||||
this->stopStream();
|
||||
}
|
||||
}
|
||||
|
||||
bool airtaudio::api::Alsa::isMasterOf(airtaudio::Api* _api) {
|
||||
airtaudio::api::Alsa* slave = dynamic_cast<airtaudio::api::Alsa*>(_api);
|
||||
bool audio::orchestra::api::Alsa::isMasterOf(audio::orchestra::Api* _api) {
|
||||
audio::orchestra::api::Alsa* slave = dynamic_cast<audio::orchestra::api::Alsa*>(_api);
|
||||
if (slave == nullptr) {
|
||||
ATA_ERROR("NULL ptr API (not ALSA ...)");
|
||||
return false;
|
||||
}
|
||||
if (m_state == airtaudio::state_running) {
|
||||
if (m_state == audio::orchestra::state_running) {
|
||||
ATA_ERROR("The MASTER stream is already running! ==> can not synchronize ...");
|
||||
return false;
|
||||
}
|
||||
if (slave->m_state == airtaudio::state_running) {
|
||||
if (slave->m_state == audio::orchestra::state_running) {
|
||||
ATA_ERROR("The SLAVE stream is already running! ==> can not synchronize ...");
|
||||
return false;
|
||||
}
|
77
audio/orchestra/api/Alsa.h
Normal file
77
audio/orchestra/api/Alsa.h
Normal file
@ -0,0 +1,77 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#if !defined(__AUDIO_ORCHESTRA_API_ALSA_H__) && defined(ORCHESTRA_BUILD_ALSA)
|
||||
#define __AUDIO_ORCHESTRA_API_ALSA_H__
|
||||
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
namespace api {
|
||||
class AlsaPrivate;
|
||||
class Alsa: public audio::orchestra::Api {
|
||||
public:
|
||||
static audio::orchestra::Api* Create();
|
||||
public:
|
||||
Alsa();
|
||||
virtual ~Alsa();
|
||||
enum audio::orchestra::type getCurrentApi() {
|
||||
return audio::orchestra::type_alsa;
|
||||
}
|
||||
uint32_t getDeviceCount();
|
||||
private:
|
||||
bool getNamedDeviceInfoLocal(const std::string& _deviceName,
|
||||
audio::orchestra::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, audio::orchestra::DeviceInfo& _info) {
|
||||
return getNamedDeviceInfoLocal(_deviceName, _info);
|
||||
}
|
||||
audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _device);
|
||||
enum audio::orchestra::error closeStream();
|
||||
enum audio::orchestra::error startStream();
|
||||
enum audio::orchestra::error stopStream();
|
||||
enum audio::orchestra::error abortStream();
|
||||
// This function is intended for internal use only. It must be
|
||||
// public because it is called by the internal callback handler,
|
||||
// which is not a member of RtAudio. External use of this function
|
||||
// will most likely produce highly undesireable results!
|
||||
void callbackEvent();
|
||||
void callbackEventOneCycle();
|
||||
private:
|
||||
static void alsaCallbackEvent(void* _userData);
|
||||
private:
|
||||
std11::shared_ptr<AlsaPrivate> m_private;
|
||||
std::vector<audio::orchestra::DeviceInfo> m_devices;
|
||||
void saveDeviceInfo();
|
||||
bool probeDeviceOpen(uint32_t _device,
|
||||
enum audio::orchestra::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
enum audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const audio::orchestra::StreamOptions& _options);
|
||||
|
||||
virtual bool probeDeviceOpenName(const std::string& _deviceName,
|
||||
audio::orchestra::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const audio::orchestra::StreamOptions& _options);
|
||||
virtual std11::chrono::system_clock::time_point getStreamTime();
|
||||
public:
|
||||
bool isMasterOf(audio::orchestra::Api* _api);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -5,24 +5,24 @@
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#ifdef __ANDROID_JAVA__
|
||||
#ifdef ORCHESTRA_BUILD_JAVA
|
||||
|
||||
#include <ewol/context/Context.h>
|
||||
#include <unistd.h>
|
||||
#include <airtaudio/Interface.h>
|
||||
#include <airtaudio/debug.h>
|
||||
#include <audio/orchestra/Interface.h>
|
||||
#include <audio/orchestra/debug.h>
|
||||
#include <limits.h>
|
||||
|
||||
#undef __class__
|
||||
#define __class__ "api::Android"
|
||||
|
||||
airtaudio::Api* airtaudio::api::Android::Create() {
|
||||
audio::orchestra::Api* audio::orchestra::api::Android::Create() {
|
||||
ATA_INFO("Create Android device ... ");
|
||||
return new airtaudio::api::Android();
|
||||
return new audio::orchestra::api::Android();
|
||||
}
|
||||
|
||||
|
||||
airtaudio::api::Android::Android() {
|
||||
audio::orchestra::api::Android::Android() {
|
||||
ATA_INFO("new Android");
|
||||
// On android, we set a static device ...
|
||||
ATA_INFO("get context");
|
||||
@ -34,7 +34,7 @@ airtaudio::api::Android::Android() {
|
||||
std::string property = tmpContext.audioGetDeviceProperty(iii);
|
||||
ATA_ERROR("Get devices property : " << property);
|
||||
std::vector<std::string> listProperty = etk::split(property, ':');
|
||||
airtaudio::DeviceInfo tmp;
|
||||
audio::orchestra::DeviceInfo tmp;
|
||||
tmp.name = listProperty[0];
|
||||
std::vector<std::string> listFreq = etk::split(listProperty[2], ',');
|
||||
for(size_t fff=0; fff<listFreq.size(); ++fff) {
|
||||
@ -63,63 +63,63 @@ airtaudio::api::Android::Android() {
|
||||
ATA_INFO("Create Android interface (end)");
|
||||
}
|
||||
|
||||
airtaudio::api::Android::~Android() {
|
||||
audio::orchestra::api::Android::~Android() {
|
||||
ATA_INFO("Destroy Android interface");
|
||||
}
|
||||
|
||||
uint32_t airtaudio::api::Android::getDeviceCount() {
|
||||
uint32_t audio::orchestra::api::Android::getDeviceCount() {
|
||||
//ATA_INFO("Get device count:"<< m_devices.size());
|
||||
return m_devices.size();
|
||||
}
|
||||
|
||||
airtaudio::DeviceInfo airtaudio::api::Android::getDeviceInfo(uint32_t _device) {
|
||||
audio::orchestra::DeviceInfo audio::orchestra::api::Android::getDeviceInfo(uint32_t _device) {
|
||||
//ATA_INFO("Get device info ...");
|
||||
return m_devices[_device];
|
||||
}
|
||||
|
||||
enum airtaudio::error airtaudio::api::Android::closeStream() {
|
||||
enum audio::orchestra::error audio::orchestra::api::Android::closeStream() {
|
||||
ATA_INFO("Clese Stream");
|
||||
// Can not close the stream now...
|
||||
return airtaudio::error_none;
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
enum airtaudio::error airtaudio::api::Android::startStream() {
|
||||
enum audio::orchestra::error audio::orchestra::api::Android::startStream() {
|
||||
ATA_INFO("Start Stream");
|
||||
// TODO : Check return ...
|
||||
airtaudio::Api::startStream();
|
||||
audio::orchestra::Api::startStream();
|
||||
// Can not close the stream now...
|
||||
return airtaudio::error_none;
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
enum airtaudio::error airtaudio::api::Android::stopStream() {
|
||||
enum audio::orchestra::error audio::orchestra::api::Android::stopStream() {
|
||||
ATA_INFO("Stop stream");
|
||||
ewol::Context& tmpContext = ewol::getContext();
|
||||
tmpContext.audioCloseDevice(0);
|
||||
// Can not close the stream now...
|
||||
return airtaudio::error_none;
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
enum airtaudio::error airtaudio::api::Android::abortStream() {
|
||||
enum audio::orchestra::error audio::orchestra::api::Android::abortStream() {
|
||||
ATA_INFO("Abort Stream");
|
||||
ewol::Context& tmpContext = ewol::getContext();
|
||||
tmpContext.audioCloseDevice(0);
|
||||
// Can not close the stream now...
|
||||
return airtaudio::error_none;
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
void airtaudio::api::Android::callBackEvent(void* _data,
|
||||
void audio::orchestra::api::Android::callBackEvent(void* _data,
|
||||
int32_t _frameRate) {
|
||||
int32_t doStopStream = 0;
|
||||
std11::chrono::system_clock::time_point streamTime = getStreamTime();
|
||||
std::vector<enum airtaudio::status> status;
|
||||
if (m_doConvertBuffer[airtaudio::mode_output] == true) {
|
||||
std::vector<enum audio::orchestra::status> status;
|
||||
if (m_doConvertBuffer[audio::orchestra::mode_output] == true) {
|
||||
doStopStream = m_callback(nullptr,
|
||||
std11::chrono::system_clock::time_point(),
|
||||
m_userBuffer[airtaudio::mode_output],
|
||||
m_userBuffer[audio::orchestra::mode_output],
|
||||
streamTime,
|
||||
_frameRate,
|
||||
status);
|
||||
convertBuffer((char*)_data, (char*)m_userBuffer[airtaudio::mode_output], m_convertInfo[airtaudio::mode_output]);
|
||||
convertBuffer((char*)_data, (char*)m_userBuffer[audio::orchestra::mode_output], m_convertInfo[audio::orchestra::mode_output]);
|
||||
} else {
|
||||
doStopStream = m_callback(_data,
|
||||
streamTime,
|
||||
@ -132,30 +132,30 @@ void airtaudio::api::Android::callBackEvent(void* _data,
|
||||
abortStream();
|
||||
return;
|
||||
}
|
||||
airtaudio::Api::tickStreamTime();
|
||||
audio::orchestra::Api::tickStreamTime();
|
||||
}
|
||||
|
||||
void airtaudio::api::Android::androidCallBackEvent(void* _data,
|
||||
void audio::orchestra::api::Android::androidCallBackEvent(void* _data,
|
||||
int32_t _frameRate,
|
||||
void* _userData) {
|
||||
if (_userData == nullptr) {
|
||||
ATA_INFO("callback event ... nullptr pointer");
|
||||
return;
|
||||
}
|
||||
airtaudio::api::Android* myClass = static_cast<airtaudio::api::Android*>(_userData);
|
||||
audio::orchestra::api::Android* myClass = static_cast<audio::orchestra::api::Android*>(_userData);
|
||||
myClass->callBackEvent(_data, _frameRate/2);
|
||||
}
|
||||
|
||||
bool airtaudio::api::Android::probeDeviceOpen(uint32_t _device,
|
||||
airtaudio::mode _mode,
|
||||
bool audio::orchestra::api::Android::probeDeviceOpen(uint32_t _device,
|
||||
audio::orchestra::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const airtaudio::StreamOptions& _options) {
|
||||
const audio::orchestra::StreamOptions& _options) {
|
||||
ATA_INFO("Probe : device=" << _device << " channels=" << _channels << " firstChannel=" << _firstChannel << " sampleRate=" << _sampleRate);
|
||||
if (_mode != airtaudio::mode_output) {
|
||||
if (_mode != audio::orchestra::mode_output) {
|
||||
ATA_ERROR("Can not start a device input or duplex for Android ...");
|
||||
return false;
|
||||
}
|
||||
@ -193,7 +193,7 @@ bool airtaudio::api::Android::probeDeviceOpen(uint32_t _device,
|
||||
uint64_t bufferBytes = m_nUserChannels[modeToIdTable(_mode)] * m_bufferSize * audio::getFormatBytes(m_userFormat);
|
||||
m_userBuffer[modeToIdTable(_mode)] = (char *) calloc(bufferBytes, 1);
|
||||
if (m_userBuffer[modeToIdTable(_mode)] == nullptr) {
|
||||
ATA_ERROR("airtaudio::api::Android::probeDeviceOpen: error allocating user buffer memory.");
|
||||
ATA_ERROR("audio::orchestra::api::Android::probeDeviceOpen: error allocating user buffer memory.");
|
||||
}
|
||||
setConvertInfo(_mode, _firstChannel);
|
||||
}
|
56
audio/orchestra/api/Android.h
Normal file
56
audio/orchestra/api/Android.h
Normal file
@ -0,0 +1,56 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#if !defined(__AUDIO_ORCHESTRA_API_ANDROID_H__) && defined(ORCHESTRA_BUILD_JAVA)
|
||||
#define __AUDIO_ORCHESTRA_API_ANDROID_H__
|
||||
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
namespace api {
|
||||
class Android: public audio::orchestra::Api {
|
||||
public:
|
||||
static audio::orchestra::Api* Create();
|
||||
public:
|
||||
Android();
|
||||
virtual ~Android();
|
||||
enum audio::orchestra::type getCurrentApi() {
|
||||
return audio::orchestra::type_java;
|
||||
}
|
||||
uint32_t getDeviceCount();
|
||||
audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _device);
|
||||
enum audio::orchestra::error closeStream();
|
||||
enum audio::orchestra::error startStream();
|
||||
enum audio::orchestra::error stopStream();
|
||||
enum audio::orchestra::error abortStream();
|
||||
// This function is intended for internal use only. It must be
|
||||
// public because it is called by the internal callback handler,
|
||||
// which is not a member of RtAudio. External use of this function
|
||||
// will most likely produce highly undesireable results!
|
||||
void callbackEvent();
|
||||
private:
|
||||
std::vector<audio::orchestra::DeviceInfo> m_devices;
|
||||
void saveDeviceInfo();
|
||||
bool probeDeviceOpen(uint32_t _device,
|
||||
audio::orchestra::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const audio::orchestra::StreamOptions& _options);
|
||||
private:
|
||||
void callBackEvent(void* _data,
|
||||
int32_t _frameRate);
|
||||
static void androidCallBackEvent(void* _data,
|
||||
int32_t _frameRate,
|
||||
void* _userData);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -6,13 +6,13 @@
|
||||
*/
|
||||
|
||||
|
||||
#if defined(__WINDOWS_ASIO__) // ASIO API on Windows
|
||||
#if defined(ORCHESTRA_BUILD_ASIO)
|
||||
|
||||
#include <airtaudio/Interface.h>
|
||||
#include <airtaudio/debug.h>
|
||||
#include <audio/orchestra/Interface.h>
|
||||
#include <audio/orchestra/debug.h>
|
||||
|
||||
airtaudio::Api* airtaudio::api::Asio::Create() {
|
||||
return new airtaudio::api::Asio();
|
||||
audio::orchestra::Api* audio::orchestra::api::Asio::Create() {
|
||||
return new audio::orchestra::api::Asio();
|
||||
}
|
||||
|
||||
|
||||
@ -47,21 +47,23 @@ static ASIODriverInfo driverInfo;
|
||||
static CallbackInfo *asioCallbackInfo;
|
||||
static bool asioXRun;
|
||||
|
||||
namespace airtaudio {
|
||||
namespace api {
|
||||
class AsioPrivate {
|
||||
public:
|
||||
int32_t drainCounter; // Tracks callback counts when draining
|
||||
bool internalDrain; // Indicates if stop is initiated from callback or not.
|
||||
ASIOBufferInfo *bufferInfos;
|
||||
HANDLE condition;
|
||||
AsioPrivate() :
|
||||
drainCounter(0),
|
||||
internalDrain(false),
|
||||
bufferInfos(0) {
|
||||
|
||||
}
|
||||
};
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
namespace api {
|
||||
class AsioPrivate {
|
||||
public:
|
||||
int32_t drainCounter; // Tracks callback counts when draining
|
||||
bool internalDrain; // Indicates if stop is initiated from callback or not.
|
||||
ASIOBufferInfo *bufferInfos;
|
||||
HANDLE condition;
|
||||
AsioPrivate() :
|
||||
drainCounter(0),
|
||||
internalDrain(false),
|
||||
bufferInfos(0) {
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -70,8 +72,8 @@ static const char* getAsioErrorString(ASIOError _result);
|
||||
static void sampleRateChanged(ASIOSampleRate _sRate);
|
||||
static long asioMessages(long _selector, long _value, void* _message, double* _opt);
|
||||
|
||||
airtaudio::api::Asio::Asio() :
|
||||
m_private(new airtaudio::api::AsioPrivate()) {
|
||||
audio::orchestra::api::Asio::Asio() :
|
||||
m_private(new audio::orchestra::api::AsioPrivate()) {
|
||||
// ASIO cannot run on a multi-threaded appartment. You can call
|
||||
// CoInitialize beforehand, but it must be for appartment threading
|
||||
// (in which case, CoInitilialize will return S_FALSE here).
|
||||
@ -87,8 +89,8 @@ airtaudio::api::Asio::Asio() :
|
||||
driverInfo.sysRef = GetForegroundWindow();
|
||||
}
|
||||
|
||||
airtaudio::api::Asio::~Asio() {
|
||||
if (m_state != airtaudio::state_closed) {
|
||||
audio::orchestra::api::Asio::~Asio() {
|
||||
if (m_state != audio::orchestra::state_closed) {
|
||||
closeStream();
|
||||
}
|
||||
if (m_coInitialized) {
|
||||
@ -96,11 +98,11 @@ airtaudio::api::Asio::~Asio() {
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t airtaudio::api::Asio::getDeviceCount() {
|
||||
uint32_t audio::orchestra::api::Asio::getDeviceCount() {
|
||||
return (uint32_t) drivers.asioGetNumDev();
|
||||
}
|
||||
|
||||
rtaudio::DeviceInfo airtaudio::api::Asio::getDeviceInfo(uint32_t _device) {
|
||||
rtaudio::DeviceInfo audio::orchestra::api::Asio::getDeviceInfo(uint32_t _device) {
|
||||
rtaudio::DeviceInfo info;
|
||||
info.probed = false;
|
||||
// Get device ID
|
||||
@ -114,7 +116,7 @@ rtaudio::DeviceInfo airtaudio::api::Asio::getDeviceInfo(uint32_t _device) {
|
||||
return info;
|
||||
}
|
||||
// If a stream is already open, we cannot probe other devices. Thus, use the saved results.
|
||||
if (m_state != airtaudio::state_closed) {
|
||||
if (m_state != audio::orchestra::state_closed) {
|
||||
if (_device >= m_devices.size()) {
|
||||
ATA_ERROR("device ID was not present before stream was opened.");
|
||||
return info;
|
||||
@ -208,7 +210,7 @@ static void bufferSwitch(long _index, ASIOBool _processNow) {
|
||||
object->callbackEvent(_index);
|
||||
}
|
||||
|
||||
void airtaudio::api::Asio::saveDeviceInfo() {
|
||||
void audio::orchestra::api::Asio::saveDeviceInfo() {
|
||||
m_devices.clear();
|
||||
uint32_t nDevices = getDeviceCount();
|
||||
m_devices.resize(nDevices);
|
||||
@ -217,17 +219,17 @@ void airtaudio::api::Asio::saveDeviceInfo() {
|
||||
}
|
||||
}
|
||||
|
||||
bool airtaudio::api::Asio::probeDeviceOpen(uint32_t _device,
|
||||
airtaudio::mode _mode,
|
||||
bool audio::orchestra::api::Asio::probeDeviceOpen(uint32_t _device,
|
||||
audio::orchestra::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t* _bufferSize,
|
||||
const airtaudio::StreamOptions& _options) {
|
||||
const audio::orchestra::StreamOptions& _options) {
|
||||
// For ASIO, a duplex stream MUST use the same driver.
|
||||
if ( _mode == airtaudio::mode_input
|
||||
&& m_mode == airtaudio::mode_output
|
||||
if ( _mode == audio::orchestra::mode_input
|
||||
&& m_mode == audio::orchestra::mode_output
|
||||
&& m_device[0] != _device) {
|
||||
ATA_ERROR("an ASIO duplex stream must use the same device for input and output!");
|
||||
return false;
|
||||
@ -239,8 +241,8 @@ bool airtaudio::api::Asio::probeDeviceOpen(uint32_t _device,
|
||||
return false;
|
||||
}
|
||||
// Only load the driver once for duplex stream.
|
||||
if ( _mode != airtaudio::mode_input
|
||||
|| m_mode != airtaudio::mode_output) {
|
||||
if ( _mode != audio::orchestra::mode_input
|
||||
|| m_mode != audio::orchestra::mode_output) {
|
||||
// The getDeviceInfo() function will not work when a stream is open
|
||||
// because ASIO does not allow multiple devices to run at the same
|
||||
// time. Thus, we'll probe the system before opening a stream and
|
||||
@ -264,9 +266,9 @@ bool airtaudio::api::Asio::probeDeviceOpen(uint32_t _device,
|
||||
ATA_ERROR("error (" << getAsioErrorString(result) << ") getting channel count (" << driverName << ").");
|
||||
return false;
|
||||
}
|
||||
if ( ( _mode == airtaudio::mode_output
|
||||
if ( ( _mode == audio::orchestra::mode_output
|
||||
&& (_channels+_firstChannel) > (uint32_t) outputChannels)
|
||||
|| ( _mode == airtaudio::mode_input
|
||||
|| ( _mode == audio::orchestra::mode_input
|
||||
&& (_channels+_firstChannel) > (uint32_t) inputChannels)) {
|
||||
drivers.removeCurrentDriver();
|
||||
ATA_ERROR("driver (" << driverName << ") does not support requested channel count (" << _channels << ") + offset (" << _firstChannel << ").");
|
||||
@ -302,7 +304,7 @@ bool airtaudio::api::Asio::probeDeviceOpen(uint32_t _device,
|
||||
// Determine the driver data type.
|
||||
ASIOChannelInfo channelInfo;
|
||||
channelInfo.channel = 0;
|
||||
if (_mode == airtaudio::mode_output) {
|
||||
if (_mode == audio::orchestra::mode_output) {
|
||||
channelInfo.isInput = false;
|
||||
} else {
|
||||
channelInfo.isInput = true;
|
||||
@ -398,8 +400,8 @@ bool airtaudio::api::Asio::probeDeviceOpen(uint32_t _device,
|
||||
// Set to an even multiple of granularity, rounding up.
|
||||
*_bufferSize = (*_bufferSize + granularity-1) / granularity * granularity;
|
||||
}
|
||||
if ( _mode == airtaudio::mode_input
|
||||
&& m_mode == airtaudio::mode_output
|
||||
if ( _mode == audio::orchestra::mode_input
|
||||
&& m_mode == audio::orchestra::mode_output
|
||||
&& m_bufferSize != *_bufferSize) {
|
||||
drivers.removeCurrentDriver();
|
||||
ATA_ERROR("input/output buffersize discrepancy!");
|
||||
@ -419,8 +421,8 @@ bool airtaudio::api::Asio::probeDeviceOpen(uint32_t _device,
|
||||
// and output separately, we'll have to dispose of previously
|
||||
// created output buffers for a duplex stream.
|
||||
long inputLatency, outputLatency;
|
||||
if ( _mode == airtaudio::mode_input
|
||||
&& m_mode == airtaudio::mode_output) {
|
||||
if ( _mode == audio::orchestra::mode_input
|
||||
&& m_mode == audio::orchestra::mode_output) {
|
||||
ASIODisposeBuffers();
|
||||
if (m_private->bufferInfos == nullptr) {
|
||||
free(m_private->bufferInfos);
|
||||
@ -478,8 +480,8 @@ bool airtaudio::api::Asio::probeDeviceOpen(uint32_t _device,
|
||||
if (m_doConvertBuffer[modeToIdTable(_mode)]) {
|
||||
bool makeBuffer = true;
|
||||
bufferBytes = m_nDeviceChannels[modeToIdTable(_mode)] * audio::getFormatBytes(m_deviceFormat[modeToIdTable(_mode)]);
|
||||
if (_mode == airtaudio::mode_input) {
|
||||
if (m_mode == airtaudio::mode_output && m_deviceBuffer) {
|
||||
if (_mode == audio::orchestra::mode_input) {
|
||||
if (m_mode == audio::orchestra::mode_output && m_deviceBuffer) {
|
||||
uint64_t bytesOut = m_nDeviceChannels[0] * audio::getFormatBytes(m_deviceFormat[0]);
|
||||
if (bufferBytes <= bytesOut) {
|
||||
makeBuffer = false;
|
||||
@ -501,11 +503,11 @@ bool airtaudio::api::Asio::probeDeviceOpen(uint32_t _device,
|
||||
}
|
||||
m_sampleRate = _sampleRate;
|
||||
m_device[modeToIdTable(_mode)] = _device;
|
||||
m_state = airtaudio::state_stopped;
|
||||
if ( _mode == airtaudio::mode_output
|
||||
&& _mode == airtaudio::mode_input) {
|
||||
m_state = audio::orchestra::state_stopped;
|
||||
if ( _mode == audio::orchestra::mode_output
|
||||
&& _mode == audio::orchestra::mode_input) {
|
||||
// We had already set up an output stream.
|
||||
m_mode = airtaudio::mode_duplex;
|
||||
m_mode = audio::orchestra::mode_duplex;
|
||||
} else {
|
||||
m_mode = _mode;
|
||||
}
|
||||
@ -547,13 +549,13 @@ error:
|
||||
return false;
|
||||
}
|
||||
|
||||
enum airtaudio::error airtaudio::api::Asio::closeStream() {
|
||||
if (m_state == airtaudio::state_closed) {
|
||||
enum audio::orchestra::error audio::orchestra::api::Asio::closeStream() {
|
||||
if (m_state == audio::orchestra::state_closed) {
|
||||
ATA_ERROR("no open stream to close!");
|
||||
return airtaudio::error_warning;
|
||||
return audio::orchestra::error_warning;
|
||||
}
|
||||
if (m_state == airtaudio::state_running) {
|
||||
m_state = airtaudio::state_stopped;
|
||||
if (m_state == audio::orchestra::state_running) {
|
||||
m_state = audio::orchestra::state_stopped;
|
||||
ASIOStop();
|
||||
}
|
||||
ASIODisposeBuffers();
|
||||
@ -572,22 +574,22 @@ enum airtaudio::error airtaudio::api::Asio::closeStream() {
|
||||
free(m_deviceBuffer);
|
||||
m_deviceBuffer = 0;
|
||||
}
|
||||
m_mode = airtaudio::mode_unknow;
|
||||
m_state = airtaudio::state_closed;
|
||||
return airtaudio::error_none;
|
||||
m_mode = audio::orchestra::mode_unknow;
|
||||
m_state = audio::orchestra::state_closed;
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
bool stopThreadCalled = false;
|
||||
|
||||
enum airtaudio::error airtaudio::api::Asio::startStream() {
|
||||
enum audio::orchestra::error audio::orchestra::api::Asio::startStream() {
|
||||
// TODO : Check return ...
|
||||
airtaudio::Api::startStream();
|
||||
if (verifyStream() != airtaudio::error_none) {
|
||||
return airtaudio::error_fail;
|
||||
audio::orchestra::Api::startStream();
|
||||
if (verifyStream() != audio::orchestra::error_none) {
|
||||
return audio::orchestra::error_fail;
|
||||
}
|
||||
if (m_state == airtaudio::state_running) {
|
||||
if (m_state == audio::orchestra::state_running) {
|
||||
ATA_ERROR("the stream is already running!");
|
||||
return airtaudio::error_warning;
|
||||
return audio::orchestra::error_warning;
|
||||
}
|
||||
ASIOError result = ASIOStart();
|
||||
if (result != ASE_OK) {
|
||||
@ -597,48 +599,48 @@ enum airtaudio::error airtaudio::api::Asio::startStream() {
|
||||
m_private->drainCounter = 0;
|
||||
m_private->internalDrain = false;
|
||||
ResetEvent(m_private->condition);
|
||||
m_state = airtaudio::state_running;
|
||||
m_state = audio::orchestra::state_running;
|
||||
asioXRun = false;
|
||||
unlock:
|
||||
stopThreadCalled = false;
|
||||
if (result == ASE_OK) {
|
||||
return airtaudio::error_none;
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
return airtaudio::error_systemError;
|
||||
return audio::orchestra::error_systemError;
|
||||
}
|
||||
|
||||
enum airtaudio::error airtaudio::api::Asio::stopStream() {
|
||||
if (verifyStream() != airtaudio::error_none) {
|
||||
return airtaudio::error_fail;
|
||||
enum audio::orchestra::error audio::orchestra::api::Asio::stopStream() {
|
||||
if (verifyStream() != audio::orchestra::error_none) {
|
||||
return audio::orchestra::error_fail;
|
||||
}
|
||||
if (m_state == airtaudio::state_stopped) {
|
||||
if (m_state == audio::orchestra::state_stopped) {
|
||||
ATA_ERROR("the stream is already stopped!");
|
||||
return airtaudio::error_warning;
|
||||
return audio::orchestra::error_warning;
|
||||
}
|
||||
if (m_mode == airtaudio::mode_output || m_mode == airtaudio::mode_duplex) {
|
||||
if (m_mode == audio::orchestra::mode_output || m_mode == audio::orchestra::mode_duplex) {
|
||||
if (m_private->drainCounter == 0) {
|
||||
m_private->drainCounter = 2;
|
||||
WaitForSingleObject(m_private->condition, INFINITE); // block until signaled
|
||||
}
|
||||
}
|
||||
m_state = airtaudio::state_stopped;
|
||||
m_state = audio::orchestra::state_stopped;
|
||||
ASIOError result = ASIOStop();
|
||||
if (result != ASE_OK) {
|
||||
ATA_ERROR("error (" << getAsioErrorString(result) << ") stopping device.");
|
||||
}
|
||||
if (result == ASE_OK) {
|
||||
return airtaudio::error_none;
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
return airtaudio::error_systemError;
|
||||
return audio::orchestra::error_systemError;
|
||||
}
|
||||
|
||||
enum airtaudio::error airtaudio::api::Asio::abortStream() {
|
||||
if (verifyStream() != airtaudio::error_none) {
|
||||
return airtaudio::error_fail;
|
||||
enum audio::orchestra::error audio::orchestra::api::Asio::abortStream() {
|
||||
if (verifyStream() != audio::orchestra::error_none) {
|
||||
return audio::orchestra::error_fail;
|
||||
}
|
||||
if (m_state == airtaudio::state_stopped) {
|
||||
if (m_state == audio::orchestra::state_stopped) {
|
||||
ATA_ERROR("the stream is already stopped!");
|
||||
error(airtaudio::error_warning);
|
||||
error(audio::orchestra::error_warning);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -663,19 +665,19 @@ static unsigned __stdcall asioStopStream(void *_ptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool airtaudio::api::Asio::callbackEvent(long bufferIndex) {
|
||||
if ( m_state == airtaudio::state_stopped
|
||||
|| m_state == airtaudio::state_stopping) {
|
||||
bool audio::orchestra::api::Asio::callbackEvent(long bufferIndex) {
|
||||
if ( m_state == audio::orchestra::state_stopped
|
||||
|| m_state == audio::orchestra::state_stopping) {
|
||||
return true;
|
||||
}
|
||||
if (m_state == airtaudio::state_closed) {
|
||||
if (m_state == audio::orchestra::state_closed) {
|
||||
ATA_ERROR("the stream is closed ... this shouldn't happen!");
|
||||
return false;
|
||||
}
|
||||
CallbackInfo *info = (CallbackInfo *) &m_callbackInfo;
|
||||
// Check if we were draining the stream and signal if finished.
|
||||
if (m_private->drainCounter > 3) {
|
||||
m_state = airtaudio::state_stopping;
|
||||
m_state = audio::orchestra::state_stopping;
|
||||
if (m_private->internalDrain == false) {
|
||||
SetEvent(m_private->condition);
|
||||
} else { // spawn a thread to stop the stream
|
||||
@ -693,13 +695,13 @@ bool airtaudio::api::Asio::callbackEvent(long bufferIndex) {
|
||||
// draining stream.
|
||||
if (m_private->drainCounter == 0) {
|
||||
std11::chrono::system_clock::time_point streamTime = getStreamTime();
|
||||
std::vector<enum airtaudio::status status;
|
||||
if (m_mode != airtaudio::mode_input && asioXRun == true) {
|
||||
status.push_back(airtaudio::status_underflow);
|
||||
std::vector<enum audio::orchestra::status status;
|
||||
if (m_mode != audio::orchestra::mode_input && asioXRun == true) {
|
||||
status.push_back(audio::orchestra::status_underflow);
|
||||
asioXRun = false;
|
||||
}
|
||||
if (m_mode != airtaudio::mode_output && asioXRun == true) {
|
||||
status.push_back(airtaudio::status_underflow;
|
||||
if (m_mode != audio::orchestra::mode_output && asioXRun == true) {
|
||||
status.push_back(audio::orchestra::status_underflow;
|
||||
asioXRun = false;
|
||||
}
|
||||
int32_t cbReturnValue = info->callback(m_userBuffer[1],
|
||||
@ -709,7 +711,7 @@ bool airtaudio::api::Asio::callbackEvent(long bufferIndex) {
|
||||
m_bufferSize,
|
||||
status);
|
||||
if (cbReturnValue == 2) {
|
||||
m_state = airtaudio::state_stopping;
|
||||
m_state = audio::orchestra::state_stopping;
|
||||
m_private->drainCounter = 2;
|
||||
unsigned threadId;
|
||||
m_callbackInfo.thread = _beginthreadex(nullptr,
|
||||
@ -726,8 +728,8 @@ bool airtaudio::api::Asio::callbackEvent(long bufferIndex) {
|
||||
}
|
||||
uint32_t nChannels, bufferBytes, i, j;
|
||||
nChannels = m_nDeviceChannels[0] + m_nDeviceChannels[1];
|
||||
if ( m_mode == airtaudio::mode_output
|
||||
|| m_mode == airtaudio::mode_duplex) {
|
||||
if ( m_mode == audio::orchestra::mode_output
|
||||
|| m_mode == audio::orchestra::mode_duplex) {
|
||||
bufferBytes = m_bufferSize * audio::getFormatBytes(m_deviceFormat[0]);
|
||||
if (m_private->drainCounter > 1) { // write zeros to the output stream
|
||||
for (i=0, j=0; i<nChannels; i++) {
|
||||
@ -768,8 +770,8 @@ bool airtaudio::api::Asio::callbackEvent(long bufferIndex) {
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
if ( m_mode == airtaudio::mode_input
|
||||
|| m_mode == airtaudio::mode_duplex) {
|
||||
if ( m_mode == audio::orchestra::mode_input
|
||||
|| m_mode == audio::orchestra::mode_duplex) {
|
||||
bufferBytes = m_bufferSize * audio::getFormatBytes(m_deviceFormat[1]);
|
||||
if (m_doConvertBuffer[1]) {
|
||||
// Always interleave ASIO input data.
|
||||
@ -808,7 +810,7 @@ unlock:
|
||||
// documentation indicates it should not be required, some device
|
||||
// drivers apparently do not function correctly without it.
|
||||
ASIOOutputReady();
|
||||
airtaudio::Api::tickStreamTime();
|
||||
audio::orchestra::Api::tickStreamTime();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -819,8 +821,8 @@ static void sampleRateChanged(ASIOSampleRate _sRate) {
|
||||
// sample rate status of an AES/EBU or S/PDIF digital input at the
|
||||
// audio device.
|
||||
RtApi* object = (RtApi*)asioCallbackInfo->object;
|
||||
enum airtaudio::error ret = object->stopStream()
|
||||
if (ret != airtaudio::error_none) {
|
||||
enum audio::orchestra::error ret = object->stopStream()
|
||||
if (ret != audio::orchestra::error_none) {
|
||||
ATA_ERROR("error stop stream!");
|
||||
} else {
|
||||
ATA_ERROR("driver reports sample rate changed to " << _sRate << " ... stream stopped!!!");
|
54
audio/orchestra/api/Asio.h
Normal file
54
audio/orchestra/api/Asio.h
Normal file
@ -0,0 +1,54 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#if !defined(__AUDIO_ORCHESTRA_API_ASIO_H__) && defined(ORCHESTRA_BUILD_ASIO)
|
||||
#define __AUDIO_ORCHESTRA_API_ASIO_H__
|
||||
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
namespace api {
|
||||
class AsioPrivate:
|
||||
class Asio: public audio::orchestra::Api {
|
||||
public:
|
||||
static audio::orchestra::Api* Create();
|
||||
public:
|
||||
Asio();
|
||||
virtual ~Asio();
|
||||
enum audio::orchestra::type getCurrentApi() {
|
||||
return audio::orchestra::WINDOWS_ASIO;
|
||||
}
|
||||
uint32_t getDeviceCount();
|
||||
audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _device);
|
||||
enum audio::orchestra::error closeStream();
|
||||
enum audio::orchestra::error startStream();
|
||||
enum audio::orchestra::error stopStream();
|
||||
enum audio::orchestra::error abortStream();
|
||||
long getStreamLatency();
|
||||
// This function is intended for internal use only. It must be
|
||||
// public because it is called by the internal callback handler,
|
||||
// which is not a member of RtAudio. External use of this function
|
||||
// will most likely produce highly undesireable results!
|
||||
bool callbackEvent(long _bufferIndex);
|
||||
private:
|
||||
std::shared_ptr<AsioPrivate> m_private;
|
||||
std::vector<audio::orchestra::DeviceInfo> m_devices;
|
||||
void saveDeviceInfo();
|
||||
bool m_coInitialized;
|
||||
bool probeDeviceOpen(uint32_t _device,
|
||||
audio::orchestra::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const audio::orchestra::StreamOptions& _options);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -12,50 +12,52 @@
|
||||
//
|
||||
// *************************************************** //
|
||||
|
||||
#if defined(__MACOSX_CORE__) || defined(__IOS_CORE__)
|
||||
#if defined(__MACOSX_CORE__) || defined(ORCHESTRA_BUILD_IOS_CORE)
|
||||
|
||||
#include <airtaudio/Interface.h>
|
||||
#include <airtaudio/debug.h>
|
||||
#include <audio/orchestra/Interface.h>
|
||||
#include <audio/orchestra/debug.h>
|
||||
|
||||
airtaudio::Api* airtaudio::api::Core::Create() {
|
||||
return new airtaudio::api::Core();
|
||||
audio::orchestra::Api* audio::orchestra::api::Core::Create() {
|
||||
return new audio::orchestra::api::Core();
|
||||
}
|
||||
|
||||
#undef __class__
|
||||
#define __class__ "api::Core"
|
||||
|
||||
namespace airtaudio {
|
||||
namespace api {
|
||||
class CorePrivate {
|
||||
public:
|
||||
AudioDeviceID id[2]; // device ids
|
||||
#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
|
||||
AudioDeviceIOProcID procId[2];
|
||||
#endif
|
||||
uint32_t iStream[2]; // device stream index (or first if using multiple)
|
||||
uint32_t nStreams[2]; // number of streams to use
|
||||
bool xrun[2];
|
||||
char *deviceBuffer;
|
||||
std11::condition_variable condition;
|
||||
int32_t drainCounter; // Tracks callback counts when draining
|
||||
bool internalDrain; // Indicates if stop is initiated from callback or not.
|
||||
CorePrivate() :
|
||||
deviceBuffer(0),
|
||||
drainCounter(0),
|
||||
internalDrain(false) {
|
||||
nStreams[0] = 1;
|
||||
nStreams[1] = 1;
|
||||
id[0] = 0;
|
||||
id[1] = 0;
|
||||
xrun[0] = false;
|
||||
xrun[1] = false;
|
||||
}
|
||||
};
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
namespace api {
|
||||
class CorePrivate {
|
||||
public:
|
||||
AudioDeviceID id[2]; // device ids
|
||||
#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
|
||||
AudioDeviceIOProcID procId[2];
|
||||
#endif
|
||||
uint32_t iStream[2]; // device stream index (or first if using multiple)
|
||||
uint32_t nStreams[2]; // number of streams to use
|
||||
bool xrun[2];
|
||||
char *deviceBuffer;
|
||||
std11::condition_variable condition;
|
||||
int32_t drainCounter; // Tracks callback counts when draining
|
||||
bool internalDrain; // Indicates if stop is initiated from callback or not.
|
||||
CorePrivate() :
|
||||
deviceBuffer(0),
|
||||
drainCounter(0),
|
||||
internalDrain(false) {
|
||||
nStreams[0] = 1;
|
||||
nStreams[1] = 1;
|
||||
id[0] = 0;
|
||||
id[1] = 0;
|
||||
xrun[0] = false;
|
||||
xrun[1] = false;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
airtaudio::api::Core::Core() :
|
||||
m_private(new airtaudio::api::CorePrivate()) {
|
||||
audio::orchestra::api::Core::Core() :
|
||||
m_private(new audio::orchestra::api::CorePrivate()) {
|
||||
#if defined(AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER)
|
||||
// This is a largely undocumented but absolutely necessary
|
||||
// requirement starting with OS-X 10.6. If not called, queries and
|
||||
@ -79,16 +81,16 @@ airtaudio::api::Core::Core() :
|
||||
#endif
|
||||
}
|
||||
|
||||
airtaudio::api::Core::~Core() {
|
||||
audio::orchestra::api::Core::~Core() {
|
||||
// The subclass destructor gets called before the base class
|
||||
// destructor, so close an existing stream before deallocating
|
||||
// apiDeviceId memory.
|
||||
if (m_state != airtaudio::state_closed) {
|
||||
if (m_state != audio::orchestra::state_closed) {
|
||||
closeStream();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t airtaudio::api::Core::getDeviceCount() {
|
||||
uint32_t audio::orchestra::api::Core::getDeviceCount() {
|
||||
// Find out how many audio devices there are, if any.
|
||||
uint32_t dataSize;
|
||||
AudioObjectPropertyAddress propertyAddress = {
|
||||
@ -104,7 +106,7 @@ uint32_t airtaudio::api::Core::getDeviceCount() {
|
||||
return dataSize / sizeof(AudioDeviceID);
|
||||
}
|
||||
|
||||
uint32_t airtaudio::api::Core::getDefaultInputDevice() {
|
||||
uint32_t audio::orchestra::api::Core::getDefaultInputDevice() {
|
||||
uint32_t nDevices = getDeviceCount();
|
||||
if (nDevices <= 1) {
|
||||
return 0;
|
||||
@ -148,7 +150,7 @@ uint32_t airtaudio::api::Core::getDefaultInputDevice() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t airtaudio::api::Core::getDefaultOutputDevice() {
|
||||
uint32_t audio::orchestra::api::Core::getDefaultOutputDevice() {
|
||||
uint32_t nDevices = getDeviceCount();
|
||||
if (nDevices <= 1) {
|
||||
return 0;
|
||||
@ -192,8 +194,8 @@ uint32_t airtaudio::api::Core::getDefaultOutputDevice() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
airtaudio::DeviceInfo airtaudio::api::Core::getDeviceInfo(uint32_t _device) {
|
||||
airtaudio::DeviceInfo info;
|
||||
audio::orchestra::DeviceInfo audio::orchestra::api::Core::getDeviceInfo(uint32_t _device) {
|
||||
audio::orchestra::DeviceInfo info;
|
||||
info.probed = false;
|
||||
// Get device ID
|
||||
uint32_t nDevices = getDeviceCount();
|
||||
@ -346,7 +348,7 @@ airtaudio::DeviceInfo airtaudio::api::Core::getDeviceInfo(uint32_t _device) {
|
||||
}
|
||||
}
|
||||
info.sampleRates.clear();
|
||||
for (auto &it : airtaudio::genericSampleRate()) {
|
||||
for (auto &it : audio::orchestra::genericSampleRate()) {
|
||||
if ( it >= minimumRate
|
||||
&& it <= maximumRate) {
|
||||
info.sampleRates.push_back(it);
|
||||
@ -374,14 +376,14 @@ airtaudio::DeviceInfo airtaudio::api::Core::getDeviceInfo(uint32_t _device) {
|
||||
return info;
|
||||
}
|
||||
|
||||
OSStatus airtaudio::api::Core::callbackEvent(AudioDeviceID _inDevice,
|
||||
OSStatus audio::orchestra::api::Core::callbackEvent(AudioDeviceID _inDevice,
|
||||
const AudioTimeStamp* _inNow,
|
||||
const AudioBufferList* _inInputData,
|
||||
const AudioTimeStamp* _inInputTime,
|
||||
AudioBufferList* _outOutputData,
|
||||
const AudioTimeStamp* _inOutputTime,
|
||||
void* _userData) {
|
||||
airtaudio::api::Core* myClass = reinterpret_cast<airtaudio::api::Core*>(_userData);
|
||||
audio::orchestra::api::Core* myClass = reinterpret_cast<audio::orchestra::api::Core*>(_userData);
|
||||
if (myClass->callbackEvent(_inDevice, _inInputData, _outOutputData) == false) {
|
||||
return kAudioHardwareUnspecifiedError;
|
||||
} else {
|
||||
@ -389,11 +391,11 @@ OSStatus airtaudio::api::Core::callbackEvent(AudioDeviceID _inDevice,
|
||||
}
|
||||
}
|
||||
|
||||
OSStatus airtaudio::api::Core::xrunListener(AudioObjectID _inDevice,
|
||||
OSStatus audio::orchestra::api::Core::xrunListener(AudioObjectID _inDevice,
|
||||
uint32_t _nAddresses,
|
||||
const AudioObjectPropertyAddress _properties[],
|
||||
void* _userData) {
|
||||
airtaudio::api::Core* myClass = reinterpret_cast<airtaudio::api::Core*>(_userData);
|
||||
audio::orchestra::api::Core* myClass = reinterpret_cast<audio::orchestra::api::Core*>(_userData);
|
||||
for (uint32_t i=0; i<_nAddresses; i++) {
|
||||
if (_properties[i].mSelector == kAudioDeviceProcessorOverload) {
|
||||
if (_properties[i].mScope == kAudioDevicePropertyScopeInput) {
|
||||
@ -421,14 +423,14 @@ static OSStatus rateListener(AudioObjectID _inDevice,
|
||||
return kAudioHardwareNoError;
|
||||
}
|
||||
|
||||
bool airtaudio::api::Core::probeDeviceOpen(uint32_t _device,
|
||||
airtaudio::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const airtaudio.::StreamOptions& _options) {
|
||||
bool audio::orchestra::api::Core::probeDeviceOpen(uint32_t _device,
|
||||
audio::orchestra::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const audio::orchestra::StreamOptions& _options) {
|
||||
// Get device ID
|
||||
uint32_t nDevices = getDeviceCount();
|
||||
if (nDevices == 0) {
|
||||
@ -461,7 +463,7 @@ bool airtaudio::api::Core::probeDeviceOpen(uint32_t _device,
|
||||
AudioDeviceID id = deviceList[ _device ];
|
||||
// Setup for stream mode.
|
||||
bool isInput = false;
|
||||
if (_mode == airtaudio::mode_input) {
|
||||
if (_mode == audio::orchestra::mode_input) {
|
||||
isInput = true;
|
||||
property.mScope = kAudioDevicePropertyScopeInput;
|
||||
} else {
|
||||
@ -585,8 +587,8 @@ bool airtaudio::api::Core::probeDeviceOpen(uint32_t _device,
|
||||
// If attempting to setup a duplex stream, the bufferSize parameter
|
||||
// MUST be the same in both directions!
|
||||
*_bufferSize = theSize;
|
||||
if ( m_mode == airtaudio::mode_output
|
||||
&& _mode == airtaudio::mode_input
|
||||
if ( m_mode == audio::orchestra::mode_output
|
||||
&& _mode == audio::orchestra::mode_input
|
||||
&& *_bufferSize != m_bufferSize) {
|
||||
ATA_ERROR("system error setting buffer size for duplex stream on device (" << _device << ").");
|
||||
return false;
|
||||
@ -791,8 +793,8 @@ bool airtaudio::api::Core::probeDeviceOpen(uint32_t _device,
|
||||
&& m_private->nStreams[modeToIdTable(_mode)] > 1) {
|
||||
bool makeBuffer = true;
|
||||
bufferBytes = m_nDeviceChannels[modeToIdTable(_mode)] * audio::getFormatBytes(m_deviceFormat[modeToIdTable(_mode)]);
|
||||
if (_mode == airtaudio::mode_input) {
|
||||
if ( m_mode == airtaudio::mode_output
|
||||
if (_mode == audio::orchestra::mode_input) {
|
||||
if ( m_mode == audio::orchestra::mode_output
|
||||
&& m_deviceBuffer) {
|
||||
uint64_t bytesOut = m_nDeviceChannels[0] * audio::getFormatBytes(m_deviceFormat[0]);
|
||||
if (bufferBytes <= bytesOut) {
|
||||
@ -815,7 +817,7 @@ bool airtaudio::api::Core::probeDeviceOpen(uint32_t _device,
|
||||
}
|
||||
m_sampleRate = _sampleRate;
|
||||
m_device[modeToIdTable(_mode)] = _device;
|
||||
m_state = airtaudio::state_stopped;
|
||||
m_state = audio::orchestra::state_stopped;
|
||||
ATA_VERBOSE("Set state as stopped");
|
||||
// Setup the buffer conversion information structure.
|
||||
if (m_doConvertBuffer[modeToIdTable(_mode)]) {
|
||||
@ -825,32 +827,32 @@ bool airtaudio::api::Core::probeDeviceOpen(uint32_t _device,
|
||||
setConvertInfo(_mode, channelOffset);
|
||||
}
|
||||
}
|
||||
if ( _mode == airtaudio::mode_input
|
||||
&& m_mode == airtaudio::mode_output
|
||||
if ( _mode == audio::orchestra::mode_input
|
||||
&& m_mode == audio::orchestra::mode_output
|
||||
&& m_device[0] == _device) {
|
||||
// Only one callback procedure per device.
|
||||
m_mode = airtaudio::mode_duplex;
|
||||
m_mode = audio::orchestra::mode_duplex;
|
||||
} else {
|
||||
#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
|
||||
result = AudioDeviceCreateIOProcID(id, &airtaudio::api::Core::callbackEvent, this, &m_private->procId[modeToIdTable(_mode)]);
|
||||
result = AudioDeviceCreateIOProcID(id, &audio::orchestra::api::Core::callbackEvent, this, &m_private->procId[modeToIdTable(_mode)]);
|
||||
#else
|
||||
// deprecated in favor of AudioDeviceCreateIOProcID()
|
||||
result = AudioDeviceAddIOProc(id, &airtaudio::api::Core::callbackEvent, this);
|
||||
result = AudioDeviceAddIOProc(id, &audio::orchestra::api::Core::callbackEvent, this);
|
||||
#endif
|
||||
if (result != noErr) {
|
||||
ATA_ERROR("system error setting callback for device (" << _device << ").");
|
||||
goto error;
|
||||
}
|
||||
if ( m_mode == airtaudio::mode_output
|
||||
&& _mode == airtaudio::mode_input) {
|
||||
m_mode = airtaudio::mode_duplex;
|
||||
if ( m_mode == audio::orchestra::mode_output
|
||||
&& _mode == audio::orchestra::mode_input) {
|
||||
m_mode = audio::orchestra::mode_duplex;
|
||||
} else {
|
||||
m_mode = _mode;
|
||||
}
|
||||
}
|
||||
// Setup the device property listener for over/underload.
|
||||
property.mSelector = kAudioDeviceProcessorOverload;
|
||||
result = AudioObjectAddPropertyListener(id, &property, &airtaudio::api::Core::xrunListener, this);
|
||||
result = AudioObjectAddPropertyListener(id, &property, &audio::orchestra::api::Core::xrunListener, this);
|
||||
return true;
|
||||
error:
|
||||
m_userBuffer[0].clear();
|
||||
@ -859,39 +861,39 @@ error:
|
||||
free(m_deviceBuffer);
|
||||
m_deviceBuffer = 0;
|
||||
}
|
||||
m_state = airtaudio::state_closed;
|
||||
m_state = audio::orchestra::state_closed;
|
||||
ATA_VERBOSE("Set state as closed");
|
||||
return false;
|
||||
}
|
||||
|
||||
enum airtaudio::error airtaudio::api::Core::closeStream() {
|
||||
if (m_state == airtaudio::state_closed) {
|
||||
enum audio::orchestra::error audio::orchestra::api::Core::closeStream() {
|
||||
if (m_state == audio::orchestra::state_closed) {
|
||||
ATA_ERROR("no open stream to close!");
|
||||
return airtaudio::error_warning;
|
||||
return audio::orchestra::error_warning;
|
||||
}
|
||||
if ( m_mode == airtaudio::mode_output
|
||||
|| m_mode == airtaudio::mode_duplex) {
|
||||
if (m_state == airtaudio::state_running) {
|
||||
AudioDeviceStop(m_private->id[0], &airtaudio::api::Core::callbackEvent);
|
||||
if ( m_mode == audio::orchestra::mode_output
|
||||
|| m_mode == audio::orchestra::mode_duplex) {
|
||||
if (m_state == audio::orchestra::state_running) {
|
||||
AudioDeviceStop(m_private->id[0], &audio::orchestra::api::Core::callbackEvent);
|
||||
}
|
||||
#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
|
||||
AudioDeviceDestroyIOProcID(m_private->id[0], m_private->procId[0]);
|
||||
#else
|
||||
// deprecated in favor of AudioDeviceDestroyIOProcID()
|
||||
AudioDeviceRemoveIOProc(m_private->id[0], &airtaudio::api::Core::callbackEvent);
|
||||
AudioDeviceRemoveIOProc(m_private->id[0], &audio::orchestra::api::Core::callbackEvent);
|
||||
#endif
|
||||
}
|
||||
if ( m_mode == airtaudio::mode_input
|
||||
|| ( m_mode == airtaudio::mode_duplex
|
||||
if ( m_mode == audio::orchestra::mode_input
|
||||
|| ( m_mode == audio::orchestra::mode_duplex
|
||||
&& m_device[0] != m_device[1])) {
|
||||
if (m_state == airtaudio::state_running) {
|
||||
AudioDeviceStop(m_private->id[1], &airtaudio::api::Core::callbackEvent);
|
||||
if (m_state == audio::orchestra::state_running) {
|
||||
AudioDeviceStop(m_private->id[1], &audio::orchestra::api::Core::callbackEvent);
|
||||
}
|
||||
#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
|
||||
AudioDeviceDestroyIOProcID(m_private->id[1], m_private->procId[1]);
|
||||
#else
|
||||
// deprecated in favor of AudioDeviceDestroyIOProcID()
|
||||
AudioDeviceRemoveIOProc(m_private->id[1], &airtaudio::api::Core::callbackEvent);
|
||||
AudioDeviceRemoveIOProc(m_private->id[1], &audio::orchestra::api::Core::callbackEvent);
|
||||
#endif
|
||||
}
|
||||
m_userBuffer[0].clear();
|
||||
@ -900,35 +902,35 @@ enum airtaudio::error airtaudio::api::Core::closeStream() {
|
||||
free(m_deviceBuffer);
|
||||
m_deviceBuffer = nullptr;
|
||||
}
|
||||
m_mode = airtaudio::mode_unknow;
|
||||
m_state = airtaudio::state_closed;
|
||||
m_mode = audio::orchestra::mode_unknow;
|
||||
m_state = audio::orchestra::state_closed;
|
||||
ATA_VERBOSE("Set state as closed");
|
||||
return airtaudio::error_none;
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
enum airtaudio::error airtaudio::api::Core::startStream() {
|
||||
enum audio::orchestra::error audio::orchestra::api::Core::startStream() {
|
||||
// TODO : Check return ...
|
||||
airtaudio::Api::startStream();
|
||||
if (verifyStream() != airtaudio::error_none) {
|
||||
return airtaudio::error_fail;
|
||||
audio::orchestra::Api::startStream();
|
||||
if (verifyStream() != audio::orchestra::error_none) {
|
||||
return audio::orchestra::error_fail;
|
||||
}
|
||||
if (m_state == airtaudio::state_running) {
|
||||
if (m_state == audio::orchestra::state_running) {
|
||||
ATA_ERROR("the stream is already running!");
|
||||
return airtaudio::error_warning;
|
||||
return audio::orchestra::error_warning;
|
||||
}
|
||||
OSStatus result = noErr;
|
||||
if ( m_mode == airtaudio::mode_output
|
||||
|| m_mode == airtaudio::mode_duplex) {
|
||||
result = AudioDeviceStart(m_private->id[0], &airtaudio::api::Core::callbackEvent);
|
||||
if ( m_mode == audio::orchestra::mode_output
|
||||
|| m_mode == audio::orchestra::mode_duplex) {
|
||||
result = AudioDeviceStart(m_private->id[0], &audio::orchestra::api::Core::callbackEvent);
|
||||
if (result != noErr) {
|
||||
ATA_ERROR("system error (" << getErrorCode(result) << ") starting callback procedure on device (" << m_device[0] << ").");
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
if ( m_mode == airtaudio::mode_input
|
||||
|| ( m_mode == airtaudio::mode_duplex
|
||||
if ( m_mode == audio::orchestra::mode_input
|
||||
|| ( m_mode == audio::orchestra::mode_duplex
|
||||
&& m_device[0] != m_device[1])) {
|
||||
result = AudioDeviceStart(m_private->id[1], &airtaudio::api::Core::callbackEvent);
|
||||
result = AudioDeviceStart(m_private->id[1], &audio::orchestra::api::Core::callbackEvent);
|
||||
if (result != noErr) {
|
||||
ATA_ERROR("system error starting input callback procedure on device (" << m_device[1] << ").");
|
||||
goto unlock;
|
||||
@ -936,62 +938,62 @@ enum airtaudio::error airtaudio::api::Core::startStream() {
|
||||
}
|
||||
m_private->drainCounter = 0;
|
||||
m_private->internalDrain = false;
|
||||
m_state = airtaudio::state_running;
|
||||
m_state = audio::orchestra::state_running;
|
||||
ATA_VERBOSE("Set state as running");
|
||||
unlock:
|
||||
if (result == noErr) {
|
||||
return airtaudio::error_none;
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
return airtaudio::error_systemError;
|
||||
return audio::orchestra::error_systemError;
|
||||
}
|
||||
|
||||
enum airtaudio::error airtaudio::api::Core::stopStream() {
|
||||
if (verifyStream() != airtaudio::error_none) {
|
||||
return airtaudio::error_fail;
|
||||
enum audio::orchestra::error audio::orchestra::api::Core::stopStream() {
|
||||
if (verifyStream() != audio::orchestra::error_none) {
|
||||
return audio::orchestra::error_fail;
|
||||
}
|
||||
if (m_state == airtaudio::state_stopped) {
|
||||
if (m_state == audio::orchestra::state_stopped) {
|
||||
ATA_ERROR("the stream is already stopped!");
|
||||
return airtaudio::error_warning;
|
||||
return audio::orchestra::error_warning;
|
||||
}
|
||||
OSStatus result = noErr;
|
||||
if ( m_mode == airtaudio::mode_output
|
||||
|| m_mode == airtaudio::mode_duplex) {
|
||||
if ( m_mode == audio::orchestra::mode_output
|
||||
|| m_mode == audio::orchestra::mode_duplex) {
|
||||
if (m_private->drainCounter == 0) {
|
||||
std11::unique_lock<std11::mutex> lck(m_mutex);
|
||||
m_private->drainCounter = 2;
|
||||
m_private->condition.wait(lck);
|
||||
}
|
||||
result = AudioDeviceStop(m_private->id[0], &airtaudio::api::Core::callbackEvent);
|
||||
result = AudioDeviceStop(m_private->id[0], &audio::orchestra::api::Core::callbackEvent);
|
||||
if (result != noErr) {
|
||||
ATA_ERROR("system error (" << getErrorCode(result) << ") stopping callback procedure on device (" << m_device[0] << ").");
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
if ( m_mode == airtaudio::mode_input
|
||||
|| ( m_mode == airtaudio::mode_duplex
|
||||
if ( m_mode == audio::orchestra::mode_input
|
||||
|| ( m_mode == audio::orchestra::mode_duplex
|
||||
&& m_device[0] != m_device[1])) {
|
||||
result = AudioDeviceStop(m_private->id[1], &airtaudio::api::Core::callbackEvent);
|
||||
result = AudioDeviceStop(m_private->id[1], &audio::orchestra::api::Core::callbackEvent);
|
||||
if (result != noErr) {
|
||||
ATA_ERROR("system error (" << getErrorCode(result) << ") stopping input callback procedure on device (" << m_device[1] << ").");
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
m_state = airtaudio::state_stopped;
|
||||
m_state = audio::orchestra::state_stopped;
|
||||
ATA_VERBOSE("Set state as stopped");
|
||||
unlock:
|
||||
if (result == noErr) {
|
||||
return airtaudio::error_none;
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
return airtaudio::error_systemError;
|
||||
return audio::orchestra::error_systemError;
|
||||
}
|
||||
|
||||
enum airtaudio::error airtaudio::api::Core::abortStream() {
|
||||
if (verifyStream() != airtaudio::error_none) {
|
||||
return airtaudio::error_fail;
|
||||
enum audio::orchestra::error audio::orchestra::api::Core::abortStream() {
|
||||
if (verifyStream() != audio::orchestra::error_none) {
|
||||
return audio::orchestra::error_fail;
|
||||
}
|
||||
if (m_state == airtaudio::state_stopped) {
|
||||
if (m_state == audio::orchestra::state_stopped) {
|
||||
ATA_ERROR("the stream is already stopped!");
|
||||
return airtaudio::error_warning;
|
||||
return audio::orchestra::error_warning;
|
||||
}
|
||||
m_private->drainCounter = 2;
|
||||
return stopStream();
|
||||
@ -1002,31 +1004,31 @@ enum airtaudio::error airtaudio::api::Core::abortStream() {
|
||||
// aborted. It is better to handle it this way because the
|
||||
// callbackEvent() function probably should return before the AudioDeviceStop()
|
||||
// function is called.
|
||||
void airtaudio::api::Core::coreStopStream(void *_userData) {
|
||||
void audio::orchestra::api::Core::coreStopStream(void *_userData) {
|
||||
etk::thread::setName("CoreAudio_stopStream");
|
||||
airtaudio::api::Core* myClass = reinterpret_cast<airtaudio::api::Core*>(_userData);
|
||||
audio::orchestra::api::Core* myClass = reinterpret_cast<audio::orchestra::api::Core*>(_userData);
|
||||
myClass->stopStream();
|
||||
}
|
||||
|
||||
bool airtaudio::api::Core::callbackEvent(AudioDeviceID _deviceId,
|
||||
bool audio::orchestra::api::Core::callbackEvent(AudioDeviceID _deviceId,
|
||||
const AudioBufferList *_inBufferList,
|
||||
const std11::chrono::system_clock::time_point& _inTime,
|
||||
const AudioBufferList *_outBufferList,
|
||||
const std11::chrono::system_clock::time_point& _outTime) {
|
||||
if ( m_state == airtaudio::state_stopped
|
||||
|| m_state == airtaudio::state_stopping) {
|
||||
if ( m_state == audio::orchestra::state_stopped
|
||||
|| m_state == audio::orchestra::state_stopping) {
|
||||
return true;
|
||||
}
|
||||
if (m_state == airtaudio::state_closed) {
|
||||
if (m_state == audio::orchestra::state_closed) {
|
||||
ATA_ERROR("the stream is closed ... this shouldn't happen!");
|
||||
return false;
|
||||
}
|
||||
// Check if we were draining the stream and signal is finished.
|
||||
if (m_private->drainCounter > 3) {
|
||||
m_state = airtaudio::state_stopping;
|
||||
m_state = audio::orchestra::state_stopping;
|
||||
ATA_VERBOSE("Set state as stopping");
|
||||
if (m_private->internalDrain == true) {
|
||||
new std11::thread(&airtaudio::api::Core::coreStopStream, this);
|
||||
new std11::thread(&audio::orchestra::api::Core::coreStopStream, this);
|
||||
} else {
|
||||
// external call to stopStream()
|
||||
m_private->condition.notify_one();
|
||||
@ -1037,16 +1039,16 @@ bool airtaudio::api::Core::callbackEvent(AudioDeviceID _deviceId,
|
||||
// Invoke user callback to get fresh output data UNLESS we are
|
||||
// draining stream or duplex mode AND the input/output devices are
|
||||
// different AND this function is called for the input device.
|
||||
if (m_private->drainCounter == 0 && (m_mode != airtaudio::mode_duplex || _deviceId == outputDevice)) {
|
||||
std::vector<enum airtaudio::status> status;
|
||||
if ( m_mode != airtaudio::mode_input
|
||||
if (m_private->drainCounter == 0 && (m_mode != audio::orchestra::mode_duplex || _deviceId == outputDevice)) {
|
||||
std::vector<enum audio::orchestra::status> status;
|
||||
if ( m_mode != audio::orchestra::mode_input
|
||||
&& m_private->xrun[0] == true) {
|
||||
status.push_back(airtaudio::status_underflow);
|
||||
status.push_back(audio::orchestra::status_underflow);
|
||||
m_private->xrun[0] = false;
|
||||
}
|
||||
if ( m_mode != airtaudio::mode_output
|
||||
if ( m_mode != audio::orchestra::mode_output
|
||||
&& m_private->xrun[1] == true) {
|
||||
status.push_back(airtaudio::status_overflow);
|
||||
status.push_back(audio::orchestra::status_overflow);
|
||||
m_private->xrun[1] = false;
|
||||
}
|
||||
int32_t cbReturnValue = m_callback(&m_userBuffer[1][0],
|
||||
@ -1056,7 +1058,7 @@ bool airtaudio::api::Core::callbackEvent(AudioDeviceID _deviceId,
|
||||
m_bufferSize,
|
||||
status);
|
||||
if (cbReturnValue == 2) {
|
||||
m_state = airtaudio::state_stopping;
|
||||
m_state = audio::orchestra::state_stopping;
|
||||
ATA_VERBOSE("Set state as stopping");
|
||||
m_private->drainCounter = 2;
|
||||
abortStream();
|
||||
@ -1066,8 +1068,8 @@ bool airtaudio::api::Core::callbackEvent(AudioDeviceID _deviceId,
|
||||
m_private->internalDrain = true;
|
||||
}
|
||||
}
|
||||
if ( m_mode == airtaudio::mode_output
|
||||
|| ( m_mode == airtaudio::mode_duplex
|
||||
if ( m_mode == audio::orchestra::mode_output
|
||||
|| ( m_mode == audio::orchestra::mode_duplex
|
||||
&& _deviceId == outputDevice)) {
|
||||
if (m_private->drainCounter > 1) {
|
||||
// write zeros to the output stream
|
||||
@ -1167,8 +1169,8 @@ bool airtaudio::api::Core::callbackEvent(AudioDeviceID _deviceId,
|
||||
}
|
||||
AudioDeviceID inputDevice;
|
||||
inputDevice = m_private->id[1];
|
||||
if ( m_mode == airtaudio::mode_input
|
||||
|| ( m_mode == airtaudio::mode_duplex
|
||||
if ( m_mode == audio::orchestra::mode_input
|
||||
|| ( m_mode == audio::orchestra::mode_duplex
|
||||
&& _deviceId == inputDevice)) {
|
||||
if (m_private->nStreams[1] == 1) {
|
||||
if (m_doConvertBuffer[1]) {
|
||||
@ -1254,11 +1256,11 @@ bool airtaudio::api::Core::callbackEvent(AudioDeviceID _deviceId,
|
||||
|
||||
unlock:
|
||||
//m_mutex.unlock();
|
||||
airtaudio::Api::tickStreamTime();
|
||||
audio::orchestra::Api::tickStreamTime();
|
||||
return true;
|
||||
}
|
||||
|
||||
const char* airtaudio::api::Core::getErrorCode(OSStatus _code) {
|
||||
const char* audio::orchestra::api::Core::getErrorCode(OSStatus _code) {
|
||||
switch(_code) {
|
||||
case kAudioHardwareNotRunningError:
|
||||
return "kAudioHardwareNotRunningError";
|
69
audio/orchestra/api/Core.h
Normal file
69
audio/orchestra/api/Core.h
Normal file
@ -0,0 +1,69 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#if !defined(__AUDIO_ORCHESTRA_API_CORE_H__) && defined(ORCHESTRA_BUILD_MACOSX_CORE)
|
||||
#define __AUDIO_ORCHESTRA_API_CORE_H__
|
||||
|
||||
#include <CoreAudio/AudioHardware.h>
|
||||
|
||||
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
namespace api {
|
||||
class CorePrivate;
|
||||
class Core: public audio::orchestra::Api {
|
||||
public:
|
||||
static audio::orchestra::Api* Create();
|
||||
public:
|
||||
Core();
|
||||
virtual ~Core();
|
||||
enum audio::orchestra::type getCurrentApi() {
|
||||
return audio::orchestra::type_coreOSX;
|
||||
}
|
||||
uint32_t getDeviceCount();
|
||||
audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _device);
|
||||
uint32_t getDefaultOutputDevice();
|
||||
uint32_t getDefaultInputDevice();
|
||||
enum audio::orchestra::error closeStream();
|
||||
enum audio::orchestra::error startStream();
|
||||
enum audio::orchestra::error stopStream();
|
||||
enum audio::orchestra::error abortStream();
|
||||
long getStreamLatency();
|
||||
bool callbackEvent(AudioDeviceID _deviceId,
|
||||
const AudioBufferList *_inBufferList,
|
||||
const std11::chrono::system_clock::time_point& _inTime,
|
||||
const AudioBufferList *_outBufferList,
|
||||
const std11::chrono::system_clock::time_point& _outTime);
|
||||
static OSStatus callbackEvent(AudioDeviceID _inDevice,
|
||||
const AudioTimeStamp* _inNow,
|
||||
const AudioBufferList* _inInputData,
|
||||
const AudioTimeStamp* _inInputTime,
|
||||
AudioBufferList* _outOutputData,
|
||||
const AudioTimeStamp* _inOutputTime,
|
||||
void* _infoPointer);
|
||||
static void coreStopStream(void *_userData);
|
||||
private:
|
||||
std::shared_ptr<CorePrivate> m_private;
|
||||
bool probeDeviceOpen(uint32_t _device,
|
||||
audio::orchestra::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const audio::orchestra::StreamOptions& _options);
|
||||
static const char* getErrorCode(OSStatus _code);
|
||||
static OSStatus xrunListener(AudioObjectID _inDevice,
|
||||
uint32_t _nAddresses,
|
||||
const AudioObjectPropertyAddress _properties[],
|
||||
void* _userData);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
57
audio/orchestra/api/CoreIos.h
Normal file
57
audio/orchestra/api/CoreIos.h
Normal file
@ -0,0 +1,57 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#if !defined(__AUDIO_ORCHESTRA_API_CORE_IOS_H__) && defined(ORCHESTRA_BUILD_IOS_CORE)
|
||||
#define __AUDIO_ORCHESTRA_API_CORE_IOS_H__
|
||||
|
||||
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
namespace api {
|
||||
class CoreIosPrivate;
|
||||
class CoreIos: public audio::orchestra::Api {
|
||||
public:
|
||||
static audio::orchestra::Api* Create();
|
||||
public:
|
||||
CoreIos();
|
||||
virtual ~CoreIos();
|
||||
enum audio::orchestra::type getCurrentApi() {
|
||||
return audio::orchestra::type_coreIOS;
|
||||
}
|
||||
uint32_t getDeviceCount();
|
||||
audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _device);
|
||||
enum audio::orchestra::error closeStream();
|
||||
enum audio::orchestra::error startStream();
|
||||
enum audio::orchestra::error stopStream();
|
||||
enum audio::orchestra::error abortStream();
|
||||
// This function is intended for internal use only. It must be
|
||||
// public because it is called by the internal callback handler,
|
||||
// which is not a member of RtAudio. External use of this function
|
||||
// will most likely produce highly undesireable results!
|
||||
void callbackEvent();
|
||||
private:
|
||||
std::vector<audio::orchestra::DeviceInfo> m_devices;
|
||||
void saveDeviceInfo();
|
||||
bool probeDeviceOpen(uint32_t _device,
|
||||
audio::orchestra::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const audio::orchestra::StreamOptions& _options);
|
||||
public:
|
||||
void callBackEvent(void* _data,
|
||||
int32_t _frameRate);
|
||||
public:
|
||||
std11::shared_ptr<CoreIosPrivate> m_private;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -5,44 +5,46 @@
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#ifdef __IOS_CORE__
|
||||
#ifdef ORCHESTRA_BUILD_IOS_CORE
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <AudioToolbox/AudioToolbox.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <airtaudio/Interface.h>
|
||||
#include <airtaudio/debug.h>
|
||||
#include <audio/orchestra/Interface.h>
|
||||
#include <audio/orchestra/debug.h>
|
||||
#include <limits.h>
|
||||
|
||||
#undef __class__
|
||||
#define __class__ "api::CoreIos"
|
||||
|
||||
airtaudio::Api* airtaudio::api::CoreIos::Create(void) {
|
||||
audio::orchestra::Api* audio::orchestra::api::CoreIos::Create(void) {
|
||||
ATA_INFO("Create CoreIos device ... ");
|
||||
return new airtaudio::api::CoreIos();
|
||||
return new audio::orchestra::api::CoreIos();
|
||||
}
|
||||
|
||||
#define kOutputBus 0
|
||||
#define kInputBus 1
|
||||
|
||||
namespace airtaudio {
|
||||
namespace api {
|
||||
class CoreIosPrivate {
|
||||
public:
|
||||
AudioComponentInstance audioUnit;
|
||||
};
|
||||
};
|
||||
};
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
namespace api {
|
||||
class CoreIosPrivate {
|
||||
public:
|
||||
AudioComponentInstance audioUnit;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
airtaudio::api::CoreIos::CoreIos(void) :
|
||||
m_private(new airtaudio::api::CoreIosPrivate()) {
|
||||
audio::orchestra::api::CoreIos::CoreIos(void) :
|
||||
m_private(new audio::orchestra::api::CoreIosPrivate()) {
|
||||
ATA_INFO("new CoreIos");
|
||||
int32_t deviceCount = 2;
|
||||
ATA_ERROR("Get count devices : " << 2);
|
||||
airtaudio::DeviceInfo tmp;
|
||||
audio::orchestra::DeviceInfo tmp;
|
||||
// Add default output format :
|
||||
tmp.name = "out";
|
||||
tmp.sampleRates.push_back(48000);
|
||||
@ -66,51 +68,51 @@ airtaudio::api::CoreIos::CoreIos(void) :
|
||||
ATA_INFO("Create CoreIOs interface (end)");
|
||||
}
|
||||
|
||||
airtaudio::api::CoreIos::~CoreIos(void) {
|
||||
audio::orchestra::api::CoreIos::~CoreIos(void) {
|
||||
ATA_INFO("Destroy CoreIOs interface");
|
||||
AudioUnitUninitialize(m_private->audioUnit);
|
||||
}
|
||||
|
||||
uint32_t airtaudio::api::CoreIos::getDeviceCount(void) {
|
||||
uint32_t audio::orchestra::api::CoreIos::getDeviceCount(void) {
|
||||
//ATA_INFO("Get device count:"<< m_devices.size());
|
||||
return m_devices.size();
|
||||
}
|
||||
|
||||
airtaudio::DeviceInfo airtaudio::api::CoreIos::getDeviceInfo(uint32_t _device) {
|
||||
audio::orchestra::DeviceInfo audio::orchestra::api::CoreIos::getDeviceInfo(uint32_t _device) {
|
||||
//ATA_INFO("Get device info ...");
|
||||
return m_devices[_device];
|
||||
}
|
||||
|
||||
enum airtaudio::error airtaudio::api::CoreIos::closeStream(void) {
|
||||
enum audio::orchestra::error audio::orchestra::api::CoreIos::closeStream(void) {
|
||||
ATA_INFO("Close Stream");
|
||||
// Can not close the stream now...
|
||||
return airtaudio::error_none;
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
enum airtaudio::error airtaudio::api::CoreIos::startStream(void) {
|
||||
enum audio::orchestra::error audio::orchestra::api::CoreIos::startStream(void) {
|
||||
ATA_INFO("Start Stream");
|
||||
// TODO : Check return ...
|
||||
airtaudio::Api::startStream();
|
||||
audio::orchestra::Api::startStream();
|
||||
OSStatus status = AudioOutputUnitStart(m_private->audioUnit);
|
||||
// Can not close the stream now...
|
||||
return airtaudio::error_none;
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
enum airtaudio::error airtaudio::api::CoreIos::stopStream(void) {
|
||||
enum audio::orchestra::error audio::orchestra::api::CoreIos::stopStream(void) {
|
||||
ATA_INFO("Stop stream");
|
||||
OSStatus status = AudioOutputUnitStop(m_private->audioUnit);
|
||||
// Can not close the stream now...
|
||||
return airtaudio::error_none;
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
enum airtaudio::error airtaudio::api::CoreIos::abortStream(void) {
|
||||
enum audio::orchestra::error audio::orchestra::api::CoreIos::abortStream(void) {
|
||||
ATA_INFO("Abort Stream");
|
||||
OSStatus status = AudioOutputUnitStop(m_private->audioUnit);
|
||||
// Can not close the stream now...
|
||||
return airtaudio::error_none;
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
void airtaudio::api::CoreIos::callBackEvent(void* _data,
|
||||
void audio::orchestra::api::CoreIos::callBackEvent(void* _data,
|
||||
int32_t _nbChunk) {
|
||||
|
||||
#if 0
|
||||
@ -128,15 +130,15 @@ void airtaudio::api::CoreIos::callBackEvent(void* _data,
|
||||
#endif
|
||||
int32_t doStopStream = 0;
|
||||
std11::chrono::system_clock::time_point streamTime = getStreamTime();
|
||||
std::vector<enum airtaudio::status> status;
|
||||
if (m_doConvertBuffer[modeToIdTable(airtaudio::mode_output)] == true) {
|
||||
std::vector<enum audio::orchestra::status> status;
|
||||
if (m_doConvertBuffer[modeToIdTable(audio::orchestra::mode_output)] == true) {
|
||||
doStopStream = m_callback(nullptr,
|
||||
streamTime,
|
||||
&m_userBuffer[modeToIdTable(airtaudio::mode_output)][0],
|
||||
&m_userBuffer[modeToIdTable(audio::orchestra::mode_output)][0],
|
||||
streamTime,
|
||||
_nbChunk,
|
||||
status);
|
||||
convertBuffer((char*)_data, &m_userBuffer[modeToIdTable(airtaudio::mode_output)][0], m_convertInfo[modeToIdTable(airtaudio::mode_output)]);
|
||||
convertBuffer((char*)_data, &m_userBuffer[modeToIdTable(audio::orchestra::mode_output)][0], m_convertInfo[modeToIdTable(audio::orchestra::mode_output)]);
|
||||
} else {
|
||||
doStopStream = m_callback(_data,
|
||||
streamTime,
|
||||
@ -149,7 +151,7 @@ void airtaudio::api::CoreIos::callBackEvent(void* _data,
|
||||
abortStream();
|
||||
return;
|
||||
}
|
||||
airtaudio::Api::tickStreamTime();
|
||||
audio::orchestra::Api::tickStreamTime();
|
||||
}
|
||||
|
||||
|
||||
@ -163,7 +165,7 @@ static OSStatus playbackCallback(void *_userData,
|
||||
ATA_ERROR("callback event ... nullptr pointer");
|
||||
return -1;
|
||||
}
|
||||
airtaudio::api::CoreIos* myClass = static_cast<airtaudio::api::CoreIos*>(_userData);
|
||||
audio::orchestra::api::CoreIos* myClass = static_cast<audio::orchestra::api::CoreIos*>(_userData);
|
||||
// get all requested buffer :
|
||||
for (int32_t iii=0; iii < _ioData->mNumberBuffers; iii++) {
|
||||
AudioBuffer buffer = _ioData->mBuffers[iii];
|
||||
@ -175,16 +177,16 @@ static OSStatus playbackCallback(void *_userData,
|
||||
}
|
||||
|
||||
|
||||
bool airtaudio::api::CoreIos::probeDeviceOpen(uint32_t _device,
|
||||
airtaudio::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const airtaudio.::StreamOptions& _options) {
|
||||
bool audio::orchestra::api::CoreIos::probeDeviceOpen(uint32_t _device,
|
||||
audio::orchestra::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const audio::orchestra::StreamOptions& _options) {
|
||||
ATA_INFO("Probe : device=" << _device << " channels=" << _channels << " firstChannel=" << _firstChannel << " sampleRate=" << _sampleRate);
|
||||
if (_mode != airtaudio::mode_output) {
|
||||
if (_mode != audio::orchestra::mode_output) {
|
||||
ATA_ERROR("Can not start a device input or duplex for CoreIos ...");
|
||||
return false;
|
||||
}
|
@ -6,15 +6,15 @@
|
||||
*/
|
||||
|
||||
// Windows DirectSound API
|
||||
#if defined(__WINDOWS_DS__)
|
||||
#include <airtaudio/Interface.h>
|
||||
#include <airtaudio/debug.h>
|
||||
#if defined(ORCHESTRA_BUILD_DS)
|
||||
#include <audio/orchestra/Interface.h>
|
||||
#include <audio/orchestra/debug.h>
|
||||
|
||||
#undef __class__
|
||||
#define __class__ "api::Ds"
|
||||
|
||||
airtaudio::Api* airtaudio::api::Ds::Create() {
|
||||
return new airtaudio::api::Ds();
|
||||
audio::orchestra::Api* audio::orchestra::api::Ds::Create() {
|
||||
return new audio::orchestra::api::Ds();
|
||||
}
|
||||
|
||||
|
||||
@ -70,36 +70,38 @@ class DsDevice {
|
||||
}
|
||||
};
|
||||
|
||||
namespace airtaudio {
|
||||
namespace api {
|
||||
class DsPrivate {
|
||||
public:
|
||||
std11::shared_ptr<std11::thread> thread;
|
||||
bool threadRunning;
|
||||
uint32_t drainCounter; // Tracks callback counts when draining
|
||||
bool internalDrain; // Indicates if stop is initiated from callback or not.
|
||||
void *id[2];
|
||||
void *buffer[2];
|
||||
bool xrun[2];
|
||||
UINT bufferPointer[2];
|
||||
DWORD dsBufferSize[2];
|
||||
DWORD dsPointerLeadTime[2]; // the number of bytes ahead of the safe pointer to lead by.
|
||||
HANDLE condition;
|
||||
std::vector<DsDevice> dsDevices;
|
||||
DsPrivate() :
|
||||
threadRunning(false),
|
||||
drainCounter(0),
|
||||
internalDrain(false) {
|
||||
id[0] = 0;
|
||||
id[1] = 0;
|
||||
buffer[0] = 0;
|
||||
buffer[1] = 0;
|
||||
xrun[0] = false;
|
||||
xrun[1] = false;
|
||||
bufferPointer[0] = 0;
|
||||
bufferPointer[1] = 0;
|
||||
}
|
||||
};
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
namespace api {
|
||||
class DsPrivate {
|
||||
public:
|
||||
std11::shared_ptr<std11::thread> thread;
|
||||
bool threadRunning;
|
||||
uint32_t drainCounter; // Tracks callback counts when draining
|
||||
bool internalDrain; // Indicates if stop is initiated from callback or not.
|
||||
void *id[2];
|
||||
void *buffer[2];
|
||||
bool xrun[2];
|
||||
UINT bufferPointer[2];
|
||||
DWORD dsBufferSize[2];
|
||||
DWORD dsPointerLeadTime[2]; // the number of bytes ahead of the safe pointer to lead by.
|
||||
HANDLE condition;
|
||||
std::vector<DsDevice> dsDevices;
|
||||
DsPrivate() :
|
||||
threadRunning(false),
|
||||
drainCounter(0),
|
||||
internalDrain(false) {
|
||||
id[0] = 0;
|
||||
id[1] = 0;
|
||||
buffer[0] = 0;
|
||||
buffer[1] = 0;
|
||||
xrun[0] = false;
|
||||
xrun[1] = false;
|
||||
bufferPointer[0] = 0;
|
||||
bufferPointer[1] = 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -117,8 +119,8 @@ struct DsProbeData {
|
||||
std::vector<DsDevice>* dsDevices;
|
||||
};
|
||||
|
||||
airtaudio::api::Ds::Ds() :
|
||||
m_private(new airtaudio::api::DsPrivate()) {
|
||||
audio::orchestra::api::Ds::Ds() :
|
||||
m_private(new audio::orchestra::api::DsPrivate()) {
|
||||
// Dsound will run both-threaded. If CoInitialize fails, then just
|
||||
// accept whatever the mainline chose for a threading model.
|
||||
m_coInitialized = false;
|
||||
@ -128,27 +130,27 @@ airtaudio::api::Ds::Ds() :
|
||||
}
|
||||
}
|
||||
|
||||
airtaudio::api::Ds::~Ds() {
|
||||
audio::orchestra::api::Ds::~Ds() {
|
||||
if (m_coInitialized) {
|
||||
CoUninitialize(); // balanced call.
|
||||
}
|
||||
if (m_state != airtaudio::state_closed) {
|
||||
if (m_state != audio::orchestra::state_closed) {
|
||||
closeStream();
|
||||
}
|
||||
}
|
||||
|
||||
// The DirectSound default output is always the first device.
|
||||
uint32_t airtaudio::api::Ds::getDefaultOutputDevice() {
|
||||
uint32_t audio::orchestra::api::Ds::getDefaultOutputDevice() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The DirectSound default input is always the first input device,
|
||||
// which is the first capture device enumerated.
|
||||
uint32_t airtaudio::api::Ds::getDefaultInputDevice() {
|
||||
uint32_t audio::orchestra::api::Ds::getDefaultInputDevice() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t airtaudio::api::Ds::getDeviceCount() {
|
||||
uint32_t audio::orchestra::api::Ds::getDeviceCount() {
|
||||
// Set query flag for previously found devices to false, so that we
|
||||
// can check for any devices that have disappeared.
|
||||
for (size_t iii=0; iii<m_private->dsDevices.size(); ++iii) {
|
||||
@ -184,8 +186,8 @@ uint32_t airtaudio::api::Ds::getDeviceCount() {
|
||||
return m_private->dsDevices.size();
|
||||
}
|
||||
|
||||
airtaudio::DeviceInfo airtaudio::api::Ds::getDeviceInfo(uint32_t _device) {
|
||||
airtaudio::DeviceInfo info;
|
||||
audio::orchestra::DeviceInfo audio::orchestra::api::Ds::getDeviceInfo(uint32_t _device) {
|
||||
audio::orchestra::DeviceInfo info;
|
||||
info.probed = false;
|
||||
if (m_private->dsDevices.size() == 0) {
|
||||
// Force a query of all devices
|
||||
@ -221,7 +223,7 @@ airtaudio::DeviceInfo airtaudio::api::Ds::getDeviceInfo(uint32_t _device) {
|
||||
info.outputChannels = (outCaps.dwFlags & DSCAPS_PRIMARYSTEREO) ? 2 : 1;
|
||||
// Get sample rate information.
|
||||
info.sampleRates.clear();
|
||||
for (auto &it : airtaudio::genericSampleRate()) {
|
||||
for (auto &it : audio::orchestra::genericSampleRate()) {
|
||||
if ( it >= outCaps.dwMinSecondarySampleRate
|
||||
&& it <= outCaps.dwMaxSecondarySampleRate) {
|
||||
info.sampleRates.push_back(it);
|
||||
@ -354,14 +356,14 @@ probeInput:
|
||||
return info;
|
||||
}
|
||||
|
||||
bool airtaudio::api::Ds::probeDeviceOpen(uint32_t _device,
|
||||
enum airtaudio::mode _mode,
|
||||
bool audio::orchestra::api::Ds::probeDeviceOpen(uint32_t _device,
|
||||
enum audio::orchestra::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
enum audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const airtaudio.::StreamOptions& _options) {
|
||||
const audio::orchestra::StreamOptions& _options) {
|
||||
if (_channels + _firstChannel > 2) {
|
||||
ATA_ERROR("DirectSound does not support more than 2 channels per device.");
|
||||
return false;
|
||||
@ -377,12 +379,12 @@ bool airtaudio::api::Ds::probeDeviceOpen(uint32_t _device,
|
||||
ATA_ERROR("device ID is invalid!");
|
||||
return false;
|
||||
}
|
||||
if (_mode == airtaudio::mode_output) {
|
||||
if (_mode == audio::orchestra::mode_output) {
|
||||
if (m_private->dsDevices[ _device ].validId[0] == false) {
|
||||
ATA_ERROR("device (" << _device << ") does not support output!");
|
||||
return false;
|
||||
}
|
||||
} else { // _mode == airtaudio::mode_input
|
||||
} else { // _mode == audio::orchestra::mode_input
|
||||
if (m_private->dsDevices[ _device ].validId[1] == false) {
|
||||
ATA_ERROR("device (" << _device << ") does not support input!");
|
||||
return false;
|
||||
@ -429,7 +431,7 @@ bool airtaudio::api::Ds::probeDeviceOpen(uint32_t _device,
|
||||
DWORD dsPointerLeadTime = 0;
|
||||
void *ohandle = 0, *bhandle = 0;
|
||||
HRESULT result;
|
||||
if (_mode == airtaudio::mode_output) {
|
||||
if (_mode == audio::orchestra::mode_output) {
|
||||
LPDIRECTSOUND output;
|
||||
result = DirectSoundCreate(m_private->dsDevices[ _device ].id[0], &output, nullptr);
|
||||
if (FAILED(result)) {
|
||||
@ -559,7 +561,7 @@ bool airtaudio::api::Ds::probeDeviceOpen(uint32_t _device,
|
||||
ohandle = (void *) output;
|
||||
bhandle = (void *) buffer;
|
||||
}
|
||||
if (_mode == airtaudio::mode_input) {
|
||||
if (_mode == audio::orchestra::mode_input) {
|
||||
LPDIRECTSOUNDCAPTURE input;
|
||||
result = DirectSoundCaptureCreate(m_private->dsDevices[ _device ].id[1], &input, nullptr);
|
||||
if (FAILED(result)) {
|
||||
@ -693,8 +695,8 @@ bool airtaudio::api::Ds::probeDeviceOpen(uint32_t _device,
|
||||
if (m_doConvertBuffer[modeToIdTable(_mode)]) {
|
||||
bool makeBuffer = true;
|
||||
bufferBytes = m_nDeviceChannels[modeToIdTable(_mode)] * audio::getFormatBytes(m_deviceFormat[modeToIdTable(_mode)]);
|
||||
if (_mode == airtaudio::mode_input) {
|
||||
if (m_mode == airtaudio::mode_output && m_deviceBuffer) {
|
||||
if (_mode == audio::orchestra::mode_input) {
|
||||
if (m_mode == audio::orchestra::mode_output && m_deviceBuffer) {
|
||||
uint64_t bytesOut = m_nDeviceChannels[0] * audio::getFormatBytes(m_deviceFormat[0]);
|
||||
if (bufferBytes <= (long) bytesOut) {
|
||||
makeBuffer = false;
|
||||
@ -723,11 +725,11 @@ bool airtaudio::api::Ds::probeDeviceOpen(uint32_t _device,
|
||||
m_private->dsBufferSize[modeToIdTable(_mode)] = dsBufferSize;
|
||||
m_private->dsPointerLeadTime[modeToIdTable(_mode)] = dsPointerLeadTime;
|
||||
m_device[modeToIdTable(_mode)] = _device;
|
||||
m_state = airtaudio::state_stopped;
|
||||
if ( m_mode == airtaudio::mode_output
|
||||
&& _mode == airtaudio::mode_input) {
|
||||
m_state = audio::orchestra::state_stopped;
|
||||
if ( m_mode == audio::orchestra::mode_output
|
||||
&& _mode == audio::orchestra::mode_input) {
|
||||
// We had already set up an output stream.
|
||||
m_mode = airtaudio::mode_duplex;
|
||||
m_mode = audio::orchestra::mode_duplex;
|
||||
} else {
|
||||
m_mode = _mode;
|
||||
}
|
||||
@ -740,7 +742,7 @@ bool airtaudio::api::Ds::probeDeviceOpen(uint32_t _device,
|
||||
// Setup the callback thread.
|
||||
if (m_private->threadRunning == false) {
|
||||
m_private->threadRunning = true;
|
||||
std11::shared_ptr<std11::thread> tmpThread(new std11::thread(&airtaudio::api::Ds::dsCallbackEvent, this));
|
||||
std11::shared_ptr<std11::thread> tmpThread(new std11::thread(&audio::orchestra::api::Ds::dsCallbackEvent, this));
|
||||
m_private->thread = std::move(tmpThread);
|
||||
if (m_private->thread == nullptr) {
|
||||
ATA_ERROR("error creating callback thread!");
|
||||
@ -775,14 +777,14 @@ error:
|
||||
free(m_deviceBuffer);
|
||||
m_deviceBuffer = 0;
|
||||
}
|
||||
m_state = airtaudio::state_closed;
|
||||
m_state = audio::orchestra::state_closed;
|
||||
return false;
|
||||
}
|
||||
|
||||
enum airtaudio::error airtaudio::api::Ds::closeStream() {
|
||||
if (m_state == airtaudio::state_closed) {
|
||||
enum audio::orchestra::error audio::orchestra::api::Ds::closeStream() {
|
||||
if (m_state == audio::orchestra::state_closed) {
|
||||
ATA_ERROR("no open stream to close!");
|
||||
return airtaudio::error_warning;
|
||||
return audio::orchestra::error_warning;
|
||||
}
|
||||
// Stop the callback thread.
|
||||
m_private->threadRunning = false;
|
||||
@ -814,19 +816,19 @@ enum airtaudio::error airtaudio::api::Ds::closeStream() {
|
||||
free(m_deviceBuffer);
|
||||
m_deviceBuffer = 0;
|
||||
}
|
||||
m_mode = airtaudio::mode_unknow;
|
||||
m_state = airtaudio::state_closed;
|
||||
m_mode = audio::orchestra::mode_unknow;
|
||||
m_state = audio::orchestra::state_closed;
|
||||
}
|
||||
|
||||
enum airtaudio::error airtaudio::api::Ds::startStream() {
|
||||
enum audio::orchestra::error audio::orchestra::api::Ds::startStream() {
|
||||
// TODO : Check return ...
|
||||
airtaudio::Api::startStream();
|
||||
if (verifyStream() != airtaudio::error_none) {
|
||||
return airtaudio::error_fail;
|
||||
audio::orchestra::Api::startStream();
|
||||
if (verifyStream() != audio::orchestra::error_none) {
|
||||
return audio::orchestra::error_fail;
|
||||
}
|
||||
if (m_state == airtaudio::state_running) {
|
||||
if (m_state == audio::orchestra::state_running) {
|
||||
ATA_ERROR("the stream is already running!");
|
||||
return airtaudio::error_warning;
|
||||
return audio::orchestra::error_warning;
|
||||
}
|
||||
// Increase scheduler frequency on lesser windows (a side-effect of
|
||||
// increasing timer accuracy). On greater windows (Win2K or later),
|
||||
@ -834,13 +836,13 @@ enum airtaudio::error airtaudio::api::Ds::startStream() {
|
||||
timeBeginPeriod(1);
|
||||
m_buffersRolling = false;
|
||||
m_duplexPrerollBytes = 0;
|
||||
if (m_mode == airtaudio::mode_duplex) {
|
||||
// 0.5 seconds of silence in airtaudio::mode_duplex mode while the devices spin up and synchronize.
|
||||
if (m_mode == audio::orchestra::mode_duplex) {
|
||||
// 0.5 seconds of silence in audio::orchestra::mode_duplex mode while the devices spin up and synchronize.
|
||||
m_duplexPrerollBytes = (int) (0.5 * m_sampleRate * audio::getFormatBytes(m_deviceFormat[1]) * m_nDeviceChannels[1]);
|
||||
}
|
||||
HRESULT result = 0;
|
||||
if ( m_mode == airtaudio::mode_output
|
||||
|| m_mode == airtaudio::mode_duplex) {
|
||||
if ( m_mode == audio::orchestra::mode_output
|
||||
|| m_mode == audio::orchestra::mode_duplex) {
|
||||
LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) m_private->buffer[0];
|
||||
result = buffer->Play(0, 0, DSBPLAY_LOOPING);
|
||||
if (FAILED(result)) {
|
||||
@ -848,8 +850,8 @@ enum airtaudio::error airtaudio::api::Ds::startStream() {
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
if ( m_mode == airtaudio::mode_input
|
||||
|| m_mode == airtaudio::mode_duplex) {
|
||||
if ( m_mode == audio::orchestra::mode_input
|
||||
|| m_mode == audio::orchestra::mode_duplex) {
|
||||
LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) m_private->buffer[1];
|
||||
result = buffer->Start(DSCBSTART_LOOPING);
|
||||
if (FAILED(result)) {
|
||||
@ -860,32 +862,32 @@ enum airtaudio::error airtaudio::api::Ds::startStream() {
|
||||
m_private->drainCounter = 0;
|
||||
m_private->internalDrain = false;
|
||||
ResetEvent(m_private->condition);
|
||||
m_state = airtaudio::state_running;
|
||||
m_state = audio::orchestra::state_running;
|
||||
unlock:
|
||||
if (FAILED(result)) {
|
||||
return airtaudio::error_systemError;
|
||||
return audio::orchestra::error_systemError;
|
||||
}
|
||||
return airtaudio::error_none;
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
enum airtaudio::error airtaudio::api::Ds::stopStream() {
|
||||
if (verifyStream() != airtaudio::error_none) {
|
||||
return airtaudio::error_fail;
|
||||
enum audio::orchestra::error audio::orchestra::api::Ds::stopStream() {
|
||||
if (verifyStream() != audio::orchestra::error_none) {
|
||||
return audio::orchestra::error_fail;
|
||||
}
|
||||
if (m_state == airtaudio::state_stopped) {
|
||||
if (m_state == audio::orchestra::state_stopped) {
|
||||
ATA_ERROR("the stream is already stopped!");
|
||||
return airtaudio::error_warning;
|
||||
return audio::orchestra::error_warning;
|
||||
}
|
||||
HRESULT result = 0;
|
||||
LPVOID audioPtr;
|
||||
DWORD dataLen;
|
||||
if ( m_mode == airtaudio::mode_output
|
||||
|| m_mode == airtaudio::mode_duplex) {
|
||||
if ( m_mode == audio::orchestra::mode_output
|
||||
|| m_mode == audio::orchestra::mode_duplex) {
|
||||
if (m_private->drainCounter == 0) {
|
||||
m_private->drainCounter = 2;
|
||||
WaitForSingleObject(m_private->condition, INFINITE); // block until signaled
|
||||
}
|
||||
m_state = airtaudio::state_stopped;
|
||||
m_state = audio::orchestra::state_stopped;
|
||||
// Stop the buffer and clear memory
|
||||
LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) m_private->buffer[0];
|
||||
result = buffer->Stop();
|
||||
@ -911,12 +913,12 @@ enum airtaudio::error airtaudio::api::Ds::stopStream() {
|
||||
// If we start playing again, we must begin at beginning of buffer.
|
||||
m_private->bufferPointer[0] = 0;
|
||||
}
|
||||
if ( m_mode == airtaudio::mode_input
|
||||
|| m_mode == airtaudio::mode_duplex) {
|
||||
if ( m_mode == audio::orchestra::mode_input
|
||||
|| m_mode == audio::orchestra::mode_duplex) {
|
||||
LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) m_private->buffer[1];
|
||||
audioPtr = nullptr;
|
||||
dataLen = 0;
|
||||
m_state = airtaudio::state_stopped;
|
||||
m_state = audio::orchestra::state_stopped;
|
||||
result = buffer->Stop();
|
||||
if (FAILED(result)) {
|
||||
ATA_ERROR("error (" << getErrorString(result) << ") stopping input buffer!");
|
||||
@ -943,35 +945,35 @@ enum airtaudio::error airtaudio::api::Ds::stopStream() {
|
||||
unlock:
|
||||
timeEndPeriod(1); // revert to normal scheduler frequency on lesser windows.
|
||||
if (FAILED(result)) {
|
||||
return airtaudio::error_systemError;
|
||||
return audio::orchestra::error_systemError;
|
||||
}
|
||||
return airtaudio::error_none;
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
enum airtaudio::error airtaudio::api::Ds::abortStream() {
|
||||
if (verifyStream() != airtaudio::error_none) {
|
||||
return airtaudio::error_fail;
|
||||
enum audio::orchestra::error audio::orchestra::api::Ds::abortStream() {
|
||||
if (verifyStream() != audio::orchestra::error_none) {
|
||||
return audio::orchestra::error_fail;
|
||||
}
|
||||
if (m_state == airtaudio::state_stopped) {
|
||||
if (m_state == audio::orchestra::state_stopped) {
|
||||
ATA_ERROR("the stream is already stopped!");
|
||||
return airtaudio::error_warning;
|
||||
return audio::orchestra::error_warning;
|
||||
}
|
||||
m_private->drainCounter = 2;
|
||||
return stopStream();
|
||||
}
|
||||
|
||||
void airtaudio::api::Ds::callbackEvent() {
|
||||
if (m_state == airtaudio::state_stopped || m_state == airtaudio::state_stopping) {
|
||||
void audio::orchestra::api::Ds::callbackEvent() {
|
||||
if (m_state == audio::orchestra::state_stopped || m_state == audio::orchestra::state_stopping) {
|
||||
Sleep(50); // sleep 50 milliseconds
|
||||
return;
|
||||
}
|
||||
if (m_state == airtaudio::state_closed) {
|
||||
if (m_state == audio::orchestra::state_closed) {
|
||||
ATA_ERROR("the stream is closed ... this shouldn't happen!");
|
||||
return;
|
||||
}
|
||||
// Check if we were draining the stream and signal is finished.
|
||||
if (m_private->drainCounter > m_nBuffers + 2) {
|
||||
m_state = airtaudio::state_stopping;
|
||||
m_state = audio::orchestra::state_stopping;
|
||||
if (m_private->internalDrain == false) {
|
||||
SetEvent(m_private->condition);
|
||||
} else {
|
||||
@ -983,15 +985,15 @@ void airtaudio::api::Ds::callbackEvent() {
|
||||
// draining stream.
|
||||
if (m_private->drainCounter == 0) {
|
||||
std11::chrono::system_clock::time_point streamTime = getStreamTime();
|
||||
airtaudio::status status = airtaudio::status_ok;
|
||||
if ( m_mode != airtaudio::mode_input
|
||||
audio::orchestra::status status = audio::orchestra::status_ok;
|
||||
if ( m_mode != audio::orchestra::mode_input
|
||||
&& m_private->xrun[0] == true) {
|
||||
status = airtaudio::status_underflow;
|
||||
status = audio::orchestra::status_underflow;
|
||||
m_private->xrun[0] = false;
|
||||
}
|
||||
if ( m_mode != airtaudio::mode_output
|
||||
if ( m_mode != audio::orchestra::mode_output
|
||||
&& m_private->xrun[1] == true) {
|
||||
status = airtaudio::status_overflow;
|
||||
status = audio::orchestra::status_overflow;
|
||||
m_private->xrun[1] = false;
|
||||
}
|
||||
int32_t cbReturnValue = info->callback(&m_userBuffer[1][0],
|
||||
@ -1001,7 +1003,7 @@ void airtaudio::api::Ds::callbackEvent() {
|
||||
m_bufferSize,
|
||||
status);
|
||||
if (cbReturnValue == 2) {
|
||||
m_state = airtaudio::state_stopping;
|
||||
m_state = audio::orchestra::state_stopping;
|
||||
m_private->drainCounter = 2;
|
||||
abortStream();
|
||||
return;
|
||||
@ -1021,7 +1023,7 @@ void airtaudio::api::Ds::callbackEvent() {
|
||||
char *buffer;
|
||||
long bufferBytes;
|
||||
if (m_buffersRolling == false) {
|
||||
if (m_mode == airtaudio::mode_duplex) {
|
||||
if (m_mode == audio::orchestra::mode_duplex) {
|
||||
//assert(m_private->dsBufferSize[0] == m_private->dsBufferSize[1]);
|
||||
// It takes a while for the devices to get rolling. As a result,
|
||||
// there's no guarantee that the capture and write device pointers
|
||||
@ -1071,7 +1073,7 @@ void airtaudio::api::Ds::callbackEvent() {
|
||||
m_private->bufferPointer[0] -= m_private->dsBufferSize[0];
|
||||
}
|
||||
m_private->bufferPointer[1] = safeReadPointer;
|
||||
} else if (m_mode == airtaudio::mode_output) {
|
||||
} else if (m_mode == audio::orchestra::mode_output) {
|
||||
// Set the proper nextWritePosition after initial startup.
|
||||
LPDIRECTSOUNDBUFFER dsWriteBuffer = (LPDIRECTSOUNDBUFFER) m_private->buffer[0];
|
||||
result = dsWriteBuffer->GetCurrentPosition(¤tWritePointer, &safeWritePointer);
|
||||
@ -1086,8 +1088,8 @@ void airtaudio::api::Ds::callbackEvent() {
|
||||
}
|
||||
m_buffersRolling = true;
|
||||
}
|
||||
if ( m_mode == airtaudio::mode_output
|
||||
|| m_mode == airtaudio::mode_duplex) {
|
||||
if ( m_mode == audio::orchestra::mode_output
|
||||
|| m_mode == audio::orchestra::mode_duplex) {
|
||||
LPDIRECTSOUNDBUFFER dsBuffer = (LPDIRECTSOUNDBUFFER) m_private->buffer[0];
|
||||
if (m_private->drainCounter > 1) { // write zeros to the output stream
|
||||
bufferBytes = m_bufferSize * m_nUserChannels[0];
|
||||
@ -1191,8 +1193,8 @@ void airtaudio::api::Ds::callbackEvent() {
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
if ( m_mode == airtaudio::mode_input
|
||||
|| m_mode == airtaudio::mode_duplex) {
|
||||
if ( m_mode == audio::orchestra::mode_input
|
||||
|| m_mode == audio::orchestra::mode_duplex) {
|
||||
// Setup parameters.
|
||||
if (m_doConvertBuffer[1]) {
|
||||
buffer = m_deviceBuffer;
|
||||
@ -1216,20 +1218,20 @@ void airtaudio::api::Ds::callbackEvent() {
|
||||
safeReadPointer += dsBufferSize; // unwrap offset
|
||||
}
|
||||
DWORD endRead = nextReadPointer + bufferBytes;
|
||||
// Handling depends on whether we are airtaudio::mode_input or airtaudio::mode_duplex.
|
||||
// If we're in airtaudio::mode_input mode then waiting is a good thing. If we're in airtaudio::mode_duplex mode,
|
||||
// Handling depends on whether we are audio::orchestra::mode_input or audio::orchestra::mode_duplex.
|
||||
// If we're in audio::orchestra::mode_input mode then waiting is a good thing. If we're in audio::orchestra::mode_duplex mode,
|
||||
// then a wait here will drag the write pointers into the forbidden zone.
|
||||
//
|
||||
// In airtaudio::mode_duplex mode, rather than wait, we will back off the read pointer until
|
||||
// In audio::orchestra::mode_duplex mode, rather than wait, we will back off the read pointer until
|
||||
// it's in a safe position. This causes dropouts, but it seems to be the only
|
||||
// practical way to sync up the read and write pointers reliably, given the
|
||||
// the very complex relationship between phase and increment of the read and write
|
||||
// pointers.
|
||||
//
|
||||
// In order to minimize audible dropouts in airtaudio::mode_duplex mode, we will
|
||||
// In order to minimize audible dropouts in audio::orchestra::mode_duplex mode, we will
|
||||
// provide a pre-roll period of 0.5 seconds in which we return
|
||||
// zeros from the read buffer while the pointers sync up.
|
||||
if (m_mode == airtaudio::mode_duplex) {
|
||||
if (m_mode == audio::orchestra::mode_duplex) {
|
||||
if (safeReadPointer < endRead) {
|
||||
if (m_duplexPrerollBytes <= 0) {
|
||||
// Pre-roll time over. Be more agressive.
|
||||
@ -1256,7 +1258,7 @@ void airtaudio::api::Ds::callbackEvent() {
|
||||
}
|
||||
endRead = nextReadPointer + bufferBytes;
|
||||
}
|
||||
} else { // _mode == airtaudio::mode_input
|
||||
} else { // _mode == audio::orchestra::mode_input
|
||||
while ( safeReadPointer < endRead
|
||||
&& m_private->threadRunning) {
|
||||
// See comments for playback.
|
||||
@ -1324,12 +1326,12 @@ void airtaudio::api::Ds::callbackEvent() {
|
||||
}
|
||||
}
|
||||
unlock:
|
||||
airtaudio::Api::tickStreamTime();
|
||||
audio::orchestra::Api::tickStreamTime();
|
||||
}
|
||||
|
||||
void airtaudio::api::Ds::dsCallbackEvent(void *_userData) {
|
||||
void audio::orchestra::api::Ds::dsCallbackEvent(void *_userData) {
|
||||
etk::thread::setName("DS IO-" + m_name);
|
||||
airtaudio::api::Ds* myClass = reinterpret_cast<airtaudio::api::Ds*>(_userData);
|
||||
audio::orchestra::api::Ds* myClass = reinterpret_cast<audio::orchestra::api::Ds*>(_userData);
|
||||
while (myClass->m_private->threadRunning == true) {
|
||||
myClass->callbackEvent();
|
||||
}
|
58
audio/orchestra/api/Ds.h
Normal file
58
audio/orchestra/api/Ds.h
Normal file
@ -0,0 +1,58 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#if !defined(__AUDIO_ORCHESTRA_API_DS_H__) && defined(ORCHESTRA_BUILD_DS)
|
||||
#define __AUDIO_ORCHESTRA_API_DS_H__
|
||||
|
||||
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
namespace api {
|
||||
class DsPrivate;
|
||||
class Ds: public audio::orchestra::Api {
|
||||
public:
|
||||
static audio::orchestra::Api* Create();
|
||||
public:
|
||||
Ds();
|
||||
virtual ~Ds();
|
||||
enum audio::orchestra::type getCurrentApi() {
|
||||
return audio::orchestra::type_ds;
|
||||
}
|
||||
uint32_t getDeviceCount();
|
||||
uint32_t getDefaultOutputDevice();
|
||||
uint32_t getDefaultInputDevice();
|
||||
audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _device);
|
||||
enum audio::orchestra::error closeStream();
|
||||
enum audio::orchestra::error startStream();
|
||||
enum audio::orchestra::error stopStream();
|
||||
enum audio::orchestra::error abortStream();
|
||||
long getStreamLatency();
|
||||
// This function is intended for internal use only. It must be
|
||||
// public because it is called by the internal callback handler,
|
||||
// which is not a member of RtAudio. External use of this function
|
||||
// will most likely produce highly undesireable results!
|
||||
void callbackEvent();
|
||||
private:
|
||||
static void dsCallbackEvent(void *_userData);
|
||||
std11::shared_ptr<DsPrivate> m_private;
|
||||
bool m_coInitialized;
|
||||
bool m_buffersRolling;
|
||||
long m_duplexPrerollBytes;
|
||||
bool probeDeviceOpen(uint32_t _device,
|
||||
enum audio::orchestra::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
enum audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const audio::orchestra::StreamOptions& _options);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
63
audio/orchestra/api/Dummy.cpp
Normal file
63
audio/orchestra/api/Dummy.cpp
Normal file
@ -0,0 +1,63 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#if defined(__DUMMY__)
|
||||
#include <audio/orchestra/api/Dummy.h>
|
||||
#include <audio/orchestra/debug.h>
|
||||
|
||||
#undef __class__
|
||||
#define __class__ "api::Dummy"
|
||||
|
||||
audio::orchestra::Api* audio::orchestra::api::Dummy::Create() {
|
||||
return new audio::orchestra::api::Dummy();
|
||||
}
|
||||
|
||||
|
||||
audio::orchestra::api::Dummy::Dummy() {
|
||||
ATA_WARNING("This class provides no functionality.");
|
||||
}
|
||||
|
||||
uint32_t audio::orchestra::api::Dummy::getDeviceCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
audio::orchestra::DeviceInfo audio::orchestra::api::Dummy::getDeviceInfo(uint32_t _device) {
|
||||
(void)_device;
|
||||
return audio::orchestra::DeviceInfo();
|
||||
}
|
||||
|
||||
enum audio::orchestra::error audio::orchestra::api::Dummy::closeStream() {
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
enum audio::orchestra::error audio::orchestra::api::Dummy::startStream() {
|
||||
// TODO : Check return ...
|
||||
audio::orchestra::Api::startStream();
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
enum audio::orchestra::error audio::orchestra::api::Dummy::stopStream() {
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
enum audio::orchestra::error audio::orchestra::api::Dummy::abortStream() {
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
bool audio::orchestra::api::Dummy::probeDeviceOpen(uint32_t _device,
|
||||
audio::orchestra::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const audio::orchestra::StreamOptions& _options) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
45
audio/orchestra/api/Dummy.h
Normal file
45
audio/orchestra/api/Dummy.h
Normal file
@ -0,0 +1,45 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#if !defined(__AUDIO_ORCHESTRA_DUMMY__) && defined(ORCHESTRA_BUILD_DUMMY)
|
||||
#define __AUDIO_ORCHESTRA_DUMMY__
|
||||
|
||||
#include <audio/orchestra/Interface.h>
|
||||
|
||||
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
namespace api {
|
||||
class Dummy: public audio::orchestra::Api {
|
||||
public:
|
||||
static audio::orchestra::Api* Create();
|
||||
public:
|
||||
Dummy();
|
||||
enum audio::orchestra::type getCurrentApi() {
|
||||
return audio::orchestra::type_dummy;
|
||||
}
|
||||
uint32_t getDeviceCount();
|
||||
audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _device);
|
||||
enum audio::orchestra::error closeStream();
|
||||
enum audio::orchestra::error startStream();
|
||||
enum audio::orchestra::error stopStream();
|
||||
enum audio::orchestra::error abortStream();
|
||||
private:
|
||||
bool probeDeviceOpen(uint32_t _device,
|
||||
audio::orchestra::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const audio::orchestra::StreamOptions& _options);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -6,19 +6,20 @@
|
||||
*/
|
||||
|
||||
// must run before :
|
||||
#if defined(__UNIX_JACK__)
|
||||
#if defined(ORCHESTRA_BUILD_JACK)
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#include <iostream>
|
||||
#include <airtaudio/Interface.h>
|
||||
#include <airtaudio/debug.h>
|
||||
#include <audio/orchestra/Interface.h>
|
||||
#include <audio/orchestra/debug.h>
|
||||
#include <string.h>
|
||||
#include <etk/thread/tools.h>
|
||||
|
||||
#undef __class__
|
||||
#define __class__ "api::Jack"
|
||||
|
||||
airtaudio::Api* airtaudio::api::Jack::Create() {
|
||||
return new airtaudio::api::Jack();
|
||||
audio::orchestra::Api* audio::orchestra::api::Jack::Create() {
|
||||
return new audio::orchestra::api::Jack();
|
||||
}
|
||||
|
||||
|
||||
@ -47,7 +48,7 @@ airtaudio::Api* airtaudio::api::Jack::Create() {
|
||||
// specified in the command-line, the JACK server uses default values.
|
||||
//
|
||||
// The JACK server does not have to be running when an instance of
|
||||
// airtaudio::Jack is created, though the function getDeviceCount() will
|
||||
// audio::orchestra::Jack is created, though the function getDeviceCount() will
|
||||
// report 0 devices found until JACK has been started. When no
|
||||
// devices are available (i.e., the JACK server is not running), a
|
||||
// stream cannot be opened.
|
||||
@ -57,47 +58,49 @@ airtaudio::Api* airtaudio::api::Jack::Create() {
|
||||
#include <cstdio>
|
||||
|
||||
|
||||
namespace airtaudio {
|
||||
namespace api {
|
||||
class JackPrivate {
|
||||
public:
|
||||
jack_client_t *client;
|
||||
jack_port_t **ports[2];
|
||||
std::string deviceName[2];
|
||||
bool xrun[2];
|
||||
std11::condition_variable condition;
|
||||
int32_t drainCounter; // Tracks callback counts when draining
|
||||
bool internalDrain; // Indicates if stop is initiated from callback or not.
|
||||
|
||||
JackPrivate() :
|
||||
client(0),
|
||||
drainCounter(0),
|
||||
internalDrain(false) {
|
||||
ports[0] = 0;
|
||||
ports[1] = 0;
|
||||
xrun[0] = false;
|
||||
xrun[1] = false;
|
||||
}
|
||||
};
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
namespace api {
|
||||
class JackPrivate {
|
||||
public:
|
||||
jack_client_t *client;
|
||||
jack_port_t **ports[2];
|
||||
std::string deviceName[2];
|
||||
bool xrun[2];
|
||||
std11::condition_variable condition;
|
||||
int32_t drainCounter; // Tracks callback counts when draining
|
||||
bool internalDrain; // Indicates if stop is initiated from callback or not.
|
||||
|
||||
JackPrivate() :
|
||||
client(0),
|
||||
drainCounter(0),
|
||||
internalDrain(false) {
|
||||
ports[0] = 0;
|
||||
ports[1] = 0;
|
||||
xrun[0] = false;
|
||||
xrun[1] = false;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
airtaudio::api::Jack::Jack() :
|
||||
m_private(new airtaudio::api::JackPrivate()) {
|
||||
audio::orchestra::api::Jack::Jack() :
|
||||
m_private(new audio::orchestra::api::JackPrivate()) {
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
airtaudio::api::Jack::~Jack() {
|
||||
if (m_state != airtaudio::state_closed) {
|
||||
audio::orchestra::api::Jack::~Jack() {
|
||||
if (m_state != audio::orchestra::state_closed) {
|
||||
closeStream();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t airtaudio::api::Jack::getDeviceCount() {
|
||||
uint32_t audio::orchestra::api::Jack::getDeviceCount() {
|
||||
// See if we can become a jack client.
|
||||
jack_options_t options = (jack_options_t) (JackNoStartServer); //JackNullOption;
|
||||
jack_status_t *status = nullptr;
|
||||
jack_client_t *client = jack_client_open("airtaudioJackCount", options, status);
|
||||
jack_client_t *client = jack_client_open("orchestraJackCount", options, status);
|
||||
if (client == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
@ -125,15 +128,15 @@ uint32_t airtaudio::api::Jack::getDeviceCount() {
|
||||
return nDevices;
|
||||
}
|
||||
|
||||
airtaudio::DeviceInfo airtaudio::api::Jack::getDeviceInfo(uint32_t _device) {
|
||||
airtaudio::DeviceInfo info;
|
||||
audio::orchestra::DeviceInfo audio::orchestra::api::Jack::getDeviceInfo(uint32_t _device) {
|
||||
audio::orchestra::DeviceInfo info;
|
||||
info.probed = false;
|
||||
jack_options_t options = (jack_options_t) (JackNoStartServer); //JackNullOption
|
||||
jack_status_t *status = nullptr;
|
||||
jack_client_t *client = jack_client_open("airtaudioJackInfo", options, status);
|
||||
jack_client_t *client = jack_client_open("orchestraJackInfo", options, status);
|
||||
if (client == nullptr) {
|
||||
ATA_ERROR("Jack server not found or connection error!");
|
||||
// TODO : airtaudio::error_warning;
|
||||
// TODO : audio::orchestra::error_warning;
|
||||
return info;
|
||||
}
|
||||
const char **ports;
|
||||
@ -162,7 +165,7 @@ airtaudio::DeviceInfo airtaudio::api::Jack::getDeviceInfo(uint32_t _device) {
|
||||
if (_device >= nDevices) {
|
||||
jack_client_close(client);
|
||||
ATA_ERROR("device ID is invalid!");
|
||||
// TODO : airtaudio::error_invalidUse;
|
||||
// TODO : audio::orchestra::error_invalidUse;
|
||||
return info;
|
||||
}
|
||||
// Get the current jack server sample rate.
|
||||
@ -192,7 +195,7 @@ airtaudio::DeviceInfo airtaudio::api::Jack::getDeviceInfo(uint32_t _device) {
|
||||
if (info.outputChannels == 0 && info.inputChannels == 0) {
|
||||
jack_client_close(client);
|
||||
ATA_ERROR("error determining Jack input/output channels!");
|
||||
// TODO : airtaudio::error_warning;
|
||||
// TODO : audio::orchestra::error_warning;
|
||||
return info;
|
||||
}
|
||||
// If device opens for both playback and capture, we determine the channels.
|
||||
@ -215,9 +218,9 @@ airtaudio::DeviceInfo airtaudio::api::Jack::getDeviceInfo(uint32_t _device) {
|
||||
return info;
|
||||
}
|
||||
|
||||
int32_t airtaudio::api::Jack::jackCallbackHandler(jack_nframes_t _nframes, void* _userData) {
|
||||
int32_t audio::orchestra::api::Jack::jackCallbackHandler(jack_nframes_t _nframes, void* _userData) {
|
||||
ATA_VERBOSE("Jack callback: [BEGIN] " << uint64_t(_userData));
|
||||
airtaudio::api::Jack* myClass = reinterpret_cast<airtaudio::api::Jack*>(_userData);
|
||||
audio::orchestra::api::Jack* myClass = reinterpret_cast<audio::orchestra::api::Jack*>(_userData);
|
||||
if (myClass->callbackEvent((uint64_t)_nframes) == false) {
|
||||
ATA_VERBOSE("Jack callback: [END] 1");
|
||||
return 1;
|
||||
@ -230,28 +233,28 @@ int32_t airtaudio::api::Jack::jackCallbackHandler(jack_nframes_t _nframes, void*
|
||||
// server signals that it is shutting down. It is necessary to handle
|
||||
// it this way because the jackShutdown() function must return before
|
||||
// the jack_deactivate() function (in closeStream()) will return.
|
||||
void airtaudio::api::Jack::jackCloseStream(void* _userData) {
|
||||
void audio::orchestra::api::Jack::jackCloseStream(void* _userData) {
|
||||
etk::thread::setName("Jack_closeStream");
|
||||
airtaudio::api::Jack* myClass = reinterpret_cast<airtaudio::api::Jack*>(_userData);
|
||||
audio::orchestra::api::Jack* myClass = reinterpret_cast<audio::orchestra::api::Jack*>(_userData);
|
||||
myClass->closeStream();
|
||||
}
|
||||
|
||||
void airtaudio::api::Jack::jackShutdown(void* _userData) {
|
||||
airtaudio::api::Jack* myClass = reinterpret_cast<airtaudio::api::Jack*>(_userData);
|
||||
void audio::orchestra::api::Jack::jackShutdown(void* _userData) {
|
||||
audio::orchestra::api::Jack* myClass = reinterpret_cast<audio::orchestra::api::Jack*>(_userData);
|
||||
// Check current stream state. If stopped, then we'll assume this
|
||||
// was called as a result of a call to airtaudio::api::Jack::stopStream (the
|
||||
// was called as a result of a call to audio::orchestra::api::Jack::stopStream (the
|
||||
// deactivation of a client handle causes this function to be called).
|
||||
// If not, we'll assume the Jack server is shutting down or some
|
||||
// other problem occurred and we should close the stream.
|
||||
if (myClass->isStreamRunning() == false) {
|
||||
return;
|
||||
}
|
||||
new std11::thread(&airtaudio::api::Jack::jackCloseStream, _userData);
|
||||
new std11::thread(&audio::orchestra::api::Jack::jackCloseStream, _userData);
|
||||
ATA_ERROR("The Jack server is shutting down this client ... stream stopped and closed!!");
|
||||
}
|
||||
|
||||
int32_t airtaudio::api::Jack::jackXrun(void* _userData) {
|
||||
airtaudio::api::Jack* myClass = reinterpret_cast<airtaudio::api::Jack*>(_userData);
|
||||
int32_t audio::orchestra::api::Jack::jackXrun(void* _userData) {
|
||||
audio::orchestra::api::Jack* myClass = reinterpret_cast<audio::orchestra::api::Jack*>(_userData);
|
||||
if (myClass->m_private->ports[0]) {
|
||||
myClass->m_private->xrun[0] = true;
|
||||
}
|
||||
@ -261,25 +264,25 @@ int32_t airtaudio::api::Jack::jackXrun(void* _userData) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool airtaudio::api::Jack::probeDeviceOpen(uint32_t _device,
|
||||
airtaudio::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t* _bufferSize,
|
||||
const airtaudio.::StreamOptions& _options) {
|
||||
bool audio::orchestra::api::Jack::probeDeviceOpen(uint32_t _device,
|
||||
audio::orchestra::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t* _bufferSize,
|
||||
const audio::orchestra::StreamOptions& _options) {
|
||||
// Look for jack server and try to become a client (only do once per stream).
|
||||
jack_client_t *client = 0;
|
||||
if ( _mode == airtaudio::mode_output
|
||||
|| ( _mode == airtaudio::mode_input
|
||||
&& m_mode != airtaudio::mode_output)) {
|
||||
if ( _mode == audio::orchestra::mode_output
|
||||
|| ( _mode == audio::orchestra::mode_input
|
||||
&& m_mode != audio::orchestra::mode_output)) {
|
||||
jack_options_t jackoptions = (jack_options_t) (JackNoStartServer); //JackNullOption;
|
||||
jack_status_t *status = nullptr;
|
||||
if (!_options.streamName.empty()) {
|
||||
client = jack_client_open(_options.streamName.c_str(), jackoptions, status);
|
||||
} else {
|
||||
client = jack_client_open("airtaudioJack", jackoptions, status);
|
||||
client = jack_client_open("orchestraJack", jackoptions, status);
|
||||
}
|
||||
if (client == 0) {
|
||||
ATA_ERROR("Jack server not found or connection error!");
|
||||
@ -320,7 +323,7 @@ bool airtaudio::api::Jack::probeDeviceOpen(uint32_t _device,
|
||||
// channels. Jack "input ports" equal RtAudio output channels.
|
||||
uint32_t nChannels = 0;
|
||||
uint64_t flag = JackPortIsInput;
|
||||
if (_mode == airtaudio::mode_input) flag = JackPortIsOutput;
|
||||
if (_mode == audio::orchestra::mode_input) flag = JackPortIsOutput;
|
||||
ports = jack_get_ports(client, deviceName.c_str(), nullptr, flag);
|
||||
if (ports) {
|
||||
while (ports[ nChannels ]) {
|
||||
@ -345,7 +348,7 @@ bool airtaudio::api::Jack::probeDeviceOpen(uint32_t _device,
|
||||
ports = jack_get_ports(client, deviceName.c_str(), nullptr, flag);
|
||||
if (ports[ _firstChannel ]) {
|
||||
// Added by Ge Wang
|
||||
jack_latency_callback_mode_t cbmode = (_mode == airtaudio::mode_input ? JackCaptureLatency : JackPlaybackLatency);
|
||||
jack_latency_callback_mode_t cbmode = (_mode == audio::orchestra::mode_input ? JackCaptureLatency : JackPlaybackLatency);
|
||||
// the range (usually the min and max are equal)
|
||||
jack_latency_range_t latrange; latrange.min = latrange.max = 0;
|
||||
// get the latency range
|
||||
@ -393,11 +396,11 @@ bool airtaudio::api::Jack::probeDeviceOpen(uint32_t _device,
|
||||
}
|
||||
if (m_doConvertBuffer[modeToIdTable(_mode)]) {
|
||||
bool makeBuffer = true;
|
||||
if (_mode == airtaudio::mode_output) {
|
||||
if (_mode == audio::orchestra::mode_output) {
|
||||
bufferBytes = m_nDeviceChannels[0] * audio::getFormatBytes(m_deviceFormat[0]);
|
||||
} else { // _mode == airtaudio::mode_input
|
||||
} else { // _mode == audio::orchestra::mode_input
|
||||
bufferBytes = m_nDeviceChannels[1] * audio::getFormatBytes(m_deviceFormat[1]);
|
||||
if (m_mode == airtaudio::mode_output && m_deviceBuffer) {
|
||||
if (m_mode == audio::orchestra::mode_output && m_deviceBuffer) {
|
||||
uint64_t bytesOut = m_nDeviceChannels[0] * audio::getFormatBytes(m_deviceFormat[0]);
|
||||
if (bufferBytes < bytesOut) {
|
||||
makeBuffer = false;
|
||||
@ -422,20 +425,20 @@ bool airtaudio::api::Jack::probeDeviceOpen(uint32_t _device,
|
||||
}
|
||||
m_device[modeToIdTable(_mode)] = _device;
|
||||
m_channelOffset[modeToIdTable(_mode)] = _firstChannel;
|
||||
m_state = airtaudio::state_stopped;
|
||||
if ( m_mode == airtaudio::mode_output
|
||||
&& _mode == airtaudio::mode_input) {
|
||||
m_state = audio::orchestra::state_stopped;
|
||||
if ( m_mode == audio::orchestra::mode_output
|
||||
&& _mode == audio::orchestra::mode_input) {
|
||||
// We had already set up the stream for output.
|
||||
m_mode = airtaudio::mode_duplex;
|
||||
m_mode = audio::orchestra::mode_duplex;
|
||||
} else {
|
||||
m_mode = _mode;
|
||||
jack_set_process_callback(m_private->client, &airtaudio::api::Jack::jackCallbackHandler, this);
|
||||
jack_set_xrun_callback(m_private->client, &airtaudio::api::Jack::jackXrun, this);
|
||||
jack_on_shutdown(m_private->client, &airtaudio::api::Jack::jackShutdown, this);
|
||||
jack_set_process_callback(m_private->client, &audio::orchestra::api::Jack::jackCallbackHandler, this);
|
||||
jack_set_xrun_callback(m_private->client, &audio::orchestra::api::Jack::jackXrun, this);
|
||||
jack_on_shutdown(m_private->client, &audio::orchestra::api::Jack::jackShutdown, this);
|
||||
}
|
||||
// Register our ports.
|
||||
char label[64];
|
||||
if (_mode == airtaudio::mode_output) {
|
||||
if (_mode == audio::orchestra::mode_output) {
|
||||
for (uint32_t i=0; i<m_nUserChannels[0]; i++) {
|
||||
snprintf(label, 64, "outport %d", i);
|
||||
m_private->ports[0][i] = jack_port_register(m_private->client,
|
||||
@ -481,13 +484,13 @@ error:
|
||||
return false;
|
||||
}
|
||||
|
||||
enum airtaudio::error airtaudio::api::Jack::closeStream() {
|
||||
if (m_state == airtaudio::state_closed) {
|
||||
enum audio::orchestra::error audio::orchestra::api::Jack::closeStream() {
|
||||
if (m_state == audio::orchestra::state_closed) {
|
||||
ATA_ERROR("no open stream to close!");
|
||||
return airtaudio::error_warning;
|
||||
return audio::orchestra::error_warning;
|
||||
}
|
||||
if (m_private != nullptr) {
|
||||
if (m_state == airtaudio::state_running) {
|
||||
if (m_state == audio::orchestra::state_running) {
|
||||
jack_deactivate(m_private->client);
|
||||
}
|
||||
jack_client_close(m_private->client);
|
||||
@ -507,20 +510,20 @@ enum airtaudio::error airtaudio::api::Jack::closeStream() {
|
||||
free(m_deviceBuffer);
|
||||
m_deviceBuffer = nullptr;
|
||||
}
|
||||
m_mode = airtaudio::mode_unknow;
|
||||
m_state = airtaudio::state_closed;
|
||||
return airtaudio::error_none;
|
||||
m_mode = audio::orchestra::mode_unknow;
|
||||
m_state = audio::orchestra::state_closed;
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
enum airtaudio::error airtaudio::api::Jack::startStream() {
|
||||
enum audio::orchestra::error audio::orchestra::api::Jack::startStream() {
|
||||
// TODO : Check return ...
|
||||
airtaudio::Api::startStream();
|
||||
if (verifyStream() != airtaudio::error_none) {
|
||||
return airtaudio::error_fail;
|
||||
audio::orchestra::Api::startStream();
|
||||
if (verifyStream() != audio::orchestra::error_none) {
|
||||
return audio::orchestra::error_fail;
|
||||
}
|
||||
if (m_state == airtaudio::state_running) {
|
||||
if (m_state == audio::orchestra::state_running) {
|
||||
ATA_ERROR("the stream is already running!");
|
||||
return airtaudio::error_warning;
|
||||
return audio::orchestra::error_warning;
|
||||
}
|
||||
int32_t result = jack_activate(m_private->client);
|
||||
if (result) {
|
||||
@ -529,8 +532,8 @@ enum airtaudio::error airtaudio::api::Jack::startStream() {
|
||||
}
|
||||
const char **ports;
|
||||
// Get the list of available ports.
|
||||
if ( m_mode == airtaudio::mode_output
|
||||
|| m_mode == airtaudio::mode_duplex) {
|
||||
if ( m_mode == audio::orchestra::mode_output
|
||||
|| m_mode == audio::orchestra::mode_duplex) {
|
||||
result = 1;
|
||||
ports = jack_get_ports(m_private->client, m_private->deviceName[0].c_str(), nullptr, JackPortIsInput);
|
||||
if (ports == nullptr) {
|
||||
@ -552,8 +555,8 @@ enum airtaudio::error airtaudio::api::Jack::startStream() {
|
||||
}
|
||||
free(ports);
|
||||
}
|
||||
if ( m_mode == airtaudio::mode_input
|
||||
|| m_mode == airtaudio::mode_duplex) {
|
||||
if ( m_mode == audio::orchestra::mode_input
|
||||
|| m_mode == audio::orchestra::mode_duplex) {
|
||||
result = 1;
|
||||
ports = jack_get_ports(m_private->client, m_private->deviceName[1].c_str(), nullptr, JackPortIsOutput);
|
||||
if (ports == nullptr) {
|
||||
@ -576,24 +579,24 @@ enum airtaudio::error airtaudio::api::Jack::startStream() {
|
||||
}
|
||||
m_private->drainCounter = 0;
|
||||
m_private->internalDrain = false;
|
||||
m_state = airtaudio::state_running;
|
||||
m_state = audio::orchestra::state_running;
|
||||
unlock:
|
||||
if (result == 0) {
|
||||
return airtaudio::error_none;
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
return airtaudio::error_systemError;
|
||||
return audio::orchestra::error_systemError;
|
||||
}
|
||||
|
||||
enum airtaudio::error airtaudio::api::Jack::stopStream() {
|
||||
if (verifyStream() != airtaudio::error_none) {
|
||||
return airtaudio::error_fail;
|
||||
enum audio::orchestra::error audio::orchestra::api::Jack::stopStream() {
|
||||
if (verifyStream() != audio::orchestra::error_none) {
|
||||
return audio::orchestra::error_fail;
|
||||
}
|
||||
if (m_state == airtaudio::state_stopped) {
|
||||
if (m_state == audio::orchestra::state_stopped) {
|
||||
ATA_ERROR("the stream is already stopped!");
|
||||
return airtaudio::error_warning;
|
||||
return audio::orchestra::error_warning;
|
||||
}
|
||||
if ( m_mode == airtaudio::mode_output
|
||||
|| m_mode == airtaudio::mode_duplex) {
|
||||
if ( m_mode == audio::orchestra::mode_output
|
||||
|| m_mode == audio::orchestra::mode_duplex) {
|
||||
if (m_private->drainCounter == 0) {
|
||||
m_private->drainCounter = 2;
|
||||
std11::unique_lock<std11::mutex> lck(m_mutex);
|
||||
@ -601,17 +604,17 @@ enum airtaudio::error airtaudio::api::Jack::stopStream() {
|
||||
}
|
||||
}
|
||||
jack_deactivate(m_private->client);
|
||||
m_state = airtaudio::state_stopped;
|
||||
return airtaudio::error_none;
|
||||
m_state = audio::orchestra::state_stopped;
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
enum airtaudio::error airtaudio::api::Jack::abortStream() {
|
||||
if (verifyStream() != airtaudio::error_none) {
|
||||
return airtaudio::error_fail;
|
||||
enum audio::orchestra::error audio::orchestra::api::Jack::abortStream() {
|
||||
if (verifyStream() != audio::orchestra::error_none) {
|
||||
return audio::orchestra::error_fail;
|
||||
}
|
||||
if (m_state == airtaudio::state_stopped) {
|
||||
if (m_state == audio::orchestra::state_stopped) {
|
||||
ATA_ERROR("the stream is already stopped!");
|
||||
return airtaudio::error_warning;
|
||||
return audio::orchestra::error_warning;
|
||||
}
|
||||
m_private->drainCounter = 2;
|
||||
return stopStream();
|
||||
@ -624,16 +627,16 @@ enum airtaudio::error airtaudio::api::Jack::abortStream() {
|
||||
// function will return.
|
||||
static void jackStopStream(void* _userData) {
|
||||
etk::thread::setName("Jack_stopStream");
|
||||
airtaudio::api::Jack* myClass = reinterpret_cast<airtaudio::api::Jack*>(_userData);
|
||||
audio::orchestra::api::Jack* myClass = reinterpret_cast<audio::orchestra::api::Jack*>(_userData);
|
||||
myClass->stopStream();
|
||||
}
|
||||
|
||||
bool airtaudio::api::Jack::callbackEvent(uint64_t _nframes) {
|
||||
if ( m_state == airtaudio::state_stopped
|
||||
|| m_state == airtaudio::state_stopping) {
|
||||
bool audio::orchestra::api::Jack::callbackEvent(uint64_t _nframes) {
|
||||
if ( m_state == audio::orchestra::state_stopped
|
||||
|| m_state == audio::orchestra::state_stopping) {
|
||||
return true;
|
||||
}
|
||||
if (m_state == airtaudio::state_closed) {
|
||||
if (m_state == audio::orchestra::state_closed) {
|
||||
ATA_ERROR("the stream is closed ... this shouldn't happen!");
|
||||
return false;
|
||||
}
|
||||
@ -643,7 +646,7 @@ bool airtaudio::api::Jack::callbackEvent(uint64_t _nframes) {
|
||||
}
|
||||
// Check if we were draining the stream and signal is finished.
|
||||
if (m_private->drainCounter > 3) {
|
||||
m_state = airtaudio::state_stopping;
|
||||
m_state = audio::orchestra::state_stopping;
|
||||
if (m_private->internalDrain == true) {
|
||||
new std11::thread(jackStopStream, this);
|
||||
} else {
|
||||
@ -654,13 +657,13 @@ bool airtaudio::api::Jack::callbackEvent(uint64_t _nframes) {
|
||||
// Invoke user callback first, to get fresh output data.
|
||||
if (m_private->drainCounter == 0) {
|
||||
std11::chrono::time_point<std11::chrono::system_clock> streamTime = getStreamTime();
|
||||
std::vector<enum airtaudio::status> status;
|
||||
if (m_mode != airtaudio::mode_input && m_private->xrun[0] == true) {
|
||||
status.push_back(airtaudio::status_underflow);
|
||||
std::vector<enum audio::orchestra::status> status;
|
||||
if (m_mode != audio::orchestra::mode_input && m_private->xrun[0] == true) {
|
||||
status.push_back(audio::orchestra::status_underflow);
|
||||
m_private->xrun[0] = false;
|
||||
}
|
||||
if (m_mode != airtaudio::mode_output && m_private->xrun[1] == true) {
|
||||
status.push_back(airtaudio::status_overflow);
|
||||
if (m_mode != audio::orchestra::mode_output && m_private->xrun[1] == true) {
|
||||
status.push_back(audio::orchestra::status_overflow);
|
||||
m_private->xrun[1] = false;
|
||||
}
|
||||
int32_t cbReturnValue = m_callback(&m_userBuffer[1][0],
|
||||
@ -670,7 +673,7 @@ bool airtaudio::api::Jack::callbackEvent(uint64_t _nframes) {
|
||||
m_bufferSize,
|
||||
status);
|
||||
if (cbReturnValue == 2) {
|
||||
m_state = airtaudio::state_stopping;
|
||||
m_state = audio::orchestra::state_stopping;
|
||||
m_private->drainCounter = 2;
|
||||
new std11::thread(jackStopStream, this);
|
||||
return true;
|
||||
@ -682,8 +685,8 @@ bool airtaudio::api::Jack::callbackEvent(uint64_t _nframes) {
|
||||
}
|
||||
jack_default_audio_sample_t *jackbuffer;
|
||||
uint64_t bufferBytes = _nframes * sizeof(jack_default_audio_sample_t);
|
||||
if ( m_mode == airtaudio::mode_output
|
||||
|| m_mode == airtaudio::mode_duplex) {
|
||||
if ( m_mode == audio::orchestra::mode_output
|
||||
|| m_mode == audio::orchestra::mode_duplex) {
|
||||
if (m_private->drainCounter > 1) { // write zeros to the output stream
|
||||
for (uint32_t i=0; i<m_nDeviceChannels[0]; i++) {
|
||||
jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer(m_private->ports[0][i], (jack_nframes_t) _nframes);
|
||||
@ -706,8 +709,8 @@ bool airtaudio::api::Jack::callbackEvent(uint64_t _nframes) {
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
if ( m_mode == airtaudio::mode_input
|
||||
|| m_mode == airtaudio::mode_duplex) {
|
||||
if ( m_mode == audio::orchestra::mode_input
|
||||
|| m_mode == audio::orchestra::mode_duplex) {
|
||||
if (m_doConvertBuffer[1]) {
|
||||
for (uint32_t i=0; i<m_nDeviceChannels[1]; i++) {
|
||||
jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer(m_private->ports[1][i], (jack_nframes_t) _nframes);
|
||||
@ -723,7 +726,7 @@ bool airtaudio::api::Jack::callbackEvent(uint64_t _nframes) {
|
||||
}
|
||||
}
|
||||
unlock:
|
||||
airtaudio::Api::tickStreamTime();
|
||||
audio::orchestra::Api::tickStreamTime();
|
||||
return true;
|
||||
}
|
||||
|
58
audio/orchestra/api/Jack.h
Normal file
58
audio/orchestra/api/Jack.h
Normal file
@ -0,0 +1,58 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#if !defined(__AUDIO_ORCHESTRA_API_JACK_H__) && defined(ORCHESTRA_BUILD_JACK)
|
||||
#define __AUDIO_ORCHESTRA_API_JACK_H__
|
||||
|
||||
#include <jack/jack.h>
|
||||
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
namespace api {
|
||||
class JackPrivate;
|
||||
class Jack: public audio::orchestra::Api {
|
||||
public:
|
||||
static audio::orchestra::Api* Create();
|
||||
public:
|
||||
Jack();
|
||||
virtual ~Jack();
|
||||
enum audio::orchestra::type getCurrentApi() {
|
||||
return audio::orchestra::type_jack;
|
||||
}
|
||||
uint32_t getDeviceCount();
|
||||
audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _device);
|
||||
enum audio::orchestra::error closeStream();
|
||||
enum audio::orchestra::error startStream();
|
||||
enum audio::orchestra::error stopStream();
|
||||
enum audio::orchestra::error abortStream();
|
||||
long getStreamLatency();
|
||||
// This function is intended for internal use only. It must be
|
||||
// public because it is called by the internal callback handler,
|
||||
// which is not a member of RtAudio. External use of this function
|
||||
// will most likely produce highly undesireable results!
|
||||
bool callbackEvent(uint64_t _nframes);
|
||||
private:
|
||||
static int32_t jackXrun(void* _userData);
|
||||
static void jackCloseStream(void* _userData);
|
||||
static void jackShutdown(void* _userData);
|
||||
static int32_t jackCallbackHandler(jack_nframes_t _nframes, void* _userData);
|
||||
private:
|
||||
std11::shared_ptr<JackPrivate> m_private;
|
||||
bool probeDeviceOpen(uint32_t _device,
|
||||
audio::orchestra::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const audio::orchestra::StreamOptions& _options);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -6,9 +6,9 @@
|
||||
*/
|
||||
|
||||
|
||||
#if defined(__LINUX_OSS__)
|
||||
#include <airtaudio/Interface.h>
|
||||
#include <airtaudio/debug.h>
|
||||
#if defined(ORCHESTRA_BUILD_OSS)
|
||||
#include <audio/orchestra/Interface.h>
|
||||
#include <audio/orchestra/debug.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
@ -21,47 +21,49 @@
|
||||
#undef __class__
|
||||
#define __class__ "api::Oss"
|
||||
|
||||
airtaudio::Api* airtaudio::api::Oss::Create() {
|
||||
return new airtaudio::api::Oss();
|
||||
audio::orchestra::Api* audio::orchestra::api::Oss::Create() {
|
||||
return new audio::orchestra::api::Oss();
|
||||
}
|
||||
|
||||
static void *ossCallbackHandler(void* _userData);
|
||||
|
||||
|
||||
namespace airtaudio {
|
||||
namespace api {
|
||||
class OssPrivate {
|
||||
public:
|
||||
int32_t id[2]; // device ids
|
||||
bool xrun[2];
|
||||
bool triggered;
|
||||
std11::condition_variable runnable;
|
||||
std11::shared_ptr<std11::thread> thread;
|
||||
bool threadRunning;
|
||||
OssPrivate():
|
||||
triggered(false),
|
||||
threadRunning(false) {
|
||||
id[0] = 0;
|
||||
id[1] = 0;
|
||||
xrun[0] = false;
|
||||
xrun[1] = false;
|
||||
}
|
||||
};
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
namespace api {
|
||||
class OssPrivate {
|
||||
public:
|
||||
int32_t id[2]; // device ids
|
||||
bool xrun[2];
|
||||
bool triggered;
|
||||
std11::condition_variable runnable;
|
||||
std11::shared_ptr<std11::thread> thread;
|
||||
bool threadRunning;
|
||||
OssPrivate():
|
||||
triggered(false),
|
||||
threadRunning(false) {
|
||||
id[0] = 0;
|
||||
id[1] = 0;
|
||||
xrun[0] = false;
|
||||
xrun[1] = false;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
airtaudio::api::Oss::Oss() :
|
||||
m_private(new airtaudio::api::OssPrivate()) {
|
||||
audio::orchestra::api::Oss::Oss() :
|
||||
m_private(new audio::orchestra::api::OssPrivate()) {
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
airtaudio::api::Oss::~Oss() {
|
||||
if (m_state != airtaudio::state_closed) {
|
||||
audio::orchestra::api::Oss::~Oss() {
|
||||
if (m_state != audio::orchestra::state_closed) {
|
||||
closeStream();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t airtaudio::api::Oss::getDeviceCount() {
|
||||
uint32_t audio::orchestra::api::Oss::getDeviceCount() {
|
||||
int32_t mixerfd = open("/dev/mixer", O_RDWR, 0);
|
||||
if (mixerfd == -1) {
|
||||
ATA_ERROR("error opening '/dev/mixer'.");
|
||||
@ -77,7 +79,7 @@ uint32_t airtaudio::api::Oss::getDeviceCount() {
|
||||
return sysinfo.numaudios;
|
||||
}
|
||||
|
||||
airtaudio::DeviceInfo airtaudio::api::Oss::getDeviceInfo(uint32_t _device) {
|
||||
audio::orchestra::DeviceInfo audio::orchestra::api::Oss::getDeviceInfo(uint32_t _device) {
|
||||
rtaudio::DeviceInfo info;
|
||||
info.probed = false;
|
||||
int32_t mixerfd = open("/dev/mixer", O_RDWR, 0);
|
||||
@ -109,20 +111,20 @@ airtaudio::DeviceInfo airtaudio::api::Oss::getDeviceInfo(uint32_t _device) {
|
||||
close(mixerfd);
|
||||
if (result == -1) {
|
||||
ATA_ERROR("error getting device (" << ainfo.name << ") info.");
|
||||
error(airtaudio::error_warning);
|
||||
error(audio::orchestra::error_warning);
|
||||
return info;
|
||||
}
|
||||
// Probe channels
|
||||
if (ainfo.caps & PCM_CAP_airtaudio::mode_output) {
|
||||
if (ainfo.caps & PCM_CAP_audio::orchestra::mode_output) {
|
||||
info.outputChannels = ainfo.max_channels;
|
||||
}
|
||||
if (ainfo.caps & PCM_CAP_airtaudio::mode_input) {
|
||||
if (ainfo.caps & PCM_CAP_audio::orchestra::mode_input) {
|
||||
info.inputChannels = ainfo.max_channels;
|
||||
}
|
||||
if (ainfo.caps & PCM_CAP_airtaudio::mode_duplex) {
|
||||
if (ainfo.caps & PCM_CAP_audio::orchestra::mode_duplex) {
|
||||
if ( info.outputChannels > 0
|
||||
&& info.inputChannels > 0
|
||||
&& ainfo.caps & PCM_CAP_airtaudio::mode_duplex) {
|
||||
&& ainfo.caps & PCM_CAP_audio::orchestra::mode_duplex) {
|
||||
info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels;
|
||||
}
|
||||
}
|
||||
@ -180,14 +182,14 @@ airtaudio::DeviceInfo airtaudio::api::Oss::getDeviceInfo(uint32_t _device) {
|
||||
return info;
|
||||
}
|
||||
|
||||
bool airtaudio::api::Oss::probeDeviceOpen(uint32_t _device,
|
||||
bool audio::orchestra::api::Oss::probeDeviceOpen(uint32_t _device,
|
||||
StreamMode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
rtaudio::format _format,
|
||||
uint32_t* _bufferSize,
|
||||
const airtaudio.::StreamOptions& _options) {
|
||||
const audio::orchestra::StreamOptions& _options) {
|
||||
int32_t mixerfd = open("/dev/mixer", O_RDWR, 0);
|
||||
if (mixerfd == -1) {
|
||||
ATA_ERROR("error opening '/dev/mixer'.");
|
||||
@ -222,11 +224,11 @@ bool airtaudio::api::Oss::probeDeviceOpen(uint32_t _device,
|
||||
return false;
|
||||
}
|
||||
// Check if device supports input or output
|
||||
if ( ( _mode == airtaudio::mode_output
|
||||
&& !(ainfo.caps & PCM_CAP_airtaudio::mode_output))
|
||||
|| ( _mode == airtaudio::mode_input
|
||||
&& !(ainfo.caps & PCM_CAP_airtaudio::mode_input))) {
|
||||
if (_mode == airtaudio::mode_output) {
|
||||
if ( ( _mode == audio::orchestra::mode_output
|
||||
&& !(ainfo.caps & PCM_CAP_audio::orchestra::mode_output))
|
||||
|| ( _mode == audio::orchestra::mode_input
|
||||
&& !(ainfo.caps & PCM_CAP_audio::orchestra::mode_input))) {
|
||||
if (_mode == audio::orchestra::mode_output) {
|
||||
ATA_ERROR("device (" << ainfo.name << ") does not support output.");
|
||||
} else {
|
||||
ATA_ERROR("device (" << ainfo.name << ") does not support input.");
|
||||
@ -234,15 +236,15 @@ bool airtaudio::api::Oss::probeDeviceOpen(uint32_t _device,
|
||||
return false;
|
||||
}
|
||||
int32_t flags = 0;
|
||||
if (_mode == airtaudio::mode_output) {
|
||||
if (_mode == audio::orchestra::mode_output) {
|
||||
flags |= O_WRONLY;
|
||||
} else { // _mode == airtaudio::mode_input
|
||||
if ( m_mode == airtaudio::mode_output
|
||||
} else { // _mode == audio::orchestra::mode_input
|
||||
if ( m_mode == audio::orchestra::mode_output
|
||||
&& m_device[0] == _device) {
|
||||
// We just set the same device for playback ... close and reopen for duplex (OSS only).
|
||||
close(m_private->id[0]);
|
||||
m_private->id[0] = 0;
|
||||
if (!(ainfo.caps & PCM_CAP_airtaudio::mode_duplex)) {
|
||||
if (!(ainfo.caps & PCM_CAP_audio::orchestra::mode_duplex)) {
|
||||
ATA_ERROR("device (" << ainfo.name << ") does not support duplex mode.");
|
||||
return false;
|
||||
}
|
||||
@ -274,7 +276,7 @@ bool airtaudio::api::Oss::probeDeviceOpen(uint32_t _device,
|
||||
// For duplex operation, specifically set this mode (this doesn't seem to work).
|
||||
/*
|
||||
if (flags | O_RDWR) {
|
||||
result = ioctl(fd, SNDCTL_DSP_SETairtaudio::mode_duplex, nullptr);
|
||||
result = ioctl(fd, SNDCTL_DSP_SETaudio::orchestra::mode_duplex, nullptr);
|
||||
if (result == -1) {
|
||||
m_errorStream << "error setting duplex mode for device (" << ainfo.name << ").";
|
||||
m_errorText = m_errorStream.str();
|
||||
@ -432,8 +434,8 @@ bool airtaudio::api::Oss::probeDeviceOpen(uint32_t _device,
|
||||
return false;
|
||||
}
|
||||
m_sampleRate = _sampleRate;
|
||||
if ( _mode == airtaudio::mode_input
|
||||
&& m__mode == airtaudio::mode_output
|
||||
if ( _mode == audio::orchestra::mode_input
|
||||
&& m__mode == audio::orchestra::mode_output
|
||||
&& m_device[0] == _device) {
|
||||
// We're doing duplex setup here.
|
||||
m_deviceFormat[0] = m_deviceFormat[1];
|
||||
@ -465,8 +467,8 @@ bool airtaudio::api::Oss::probeDeviceOpen(uint32_t _device,
|
||||
if (m_doConvertBuffer[modeToIdTable(_mode)]) {
|
||||
bool makeBuffer = true;
|
||||
bufferBytes = m_nDeviceChannels[modeToIdTable(_mode)] * audio::getFormatBytes(m_deviceFormat[modeToIdTable(_mode)]);
|
||||
if (_mode == airtaudio::mode_input) {
|
||||
if ( m__mode == airtaudio::mode_output
|
||||
if (_mode == audio::orchestra::mode_input) {
|
||||
if ( m__mode == audio::orchestra::mode_output
|
||||
&& m_deviceBuffer) {
|
||||
uint64_t bytesOut = m_nDeviceChannels[0] * audio::getFormatBytes(m_deviceFormat[0]);
|
||||
if (bufferBytes <= bytesOut) {
|
||||
@ -487,15 +489,15 @@ bool airtaudio::api::Oss::probeDeviceOpen(uint32_t _device,
|
||||
}
|
||||
}
|
||||
m_device[modeToIdTable(_mode)] = _device;
|
||||
m_state = airtaudio::state_stopped;
|
||||
m_state = audio::orchestra::state_stopped;
|
||||
// Setup the buffer conversion information structure.
|
||||
if (m_doConvertBuffer[modeToIdTable(_mode)]) {
|
||||
setConvertInfo(_mode, _firstChannel);
|
||||
}
|
||||
// Setup thread if necessary.
|
||||
if (m_mode == airtaudio::mode_output && _mode == airtaudio::mode_input) {
|
||||
if (m_mode == audio::orchestra::mode_output && _mode == audio::orchestra::mode_input) {
|
||||
// We had already set up an output stream.
|
||||
m_mode = airtaudio::mode_duplex;
|
||||
m_mode = audio::orchestra::mode_duplex;
|
||||
if (m_device[0] == _device) {
|
||||
m_private->id[0] = fd;
|
||||
}
|
||||
@ -533,25 +535,25 @@ error:
|
||||
return false;
|
||||
}
|
||||
|
||||
enum airtaudio::error airtaudio::api::Oss::closeStream() {
|
||||
if (m_state == airtaudio::state_closed) {
|
||||
enum audio::orchestra::error audio::orchestra::api::Oss::closeStream() {
|
||||
if (m_state == audio::orchestra::state_closed) {
|
||||
ATA_ERROR("no open stream to close!");
|
||||
return airtaudio::error_warning;
|
||||
return audio::orchestra::error_warning;
|
||||
}
|
||||
m_private->threadRunning = false;
|
||||
m_mutex.lock();
|
||||
if (m_state == airtaudio::state_stopped) {
|
||||
if (m_state == audio::orchestra::state_stopped) {
|
||||
m_private->runnable.notify_one();
|
||||
}
|
||||
m_mutex.unlock();
|
||||
m_private->thread->join();
|
||||
if (m_state == airtaudio::state_running) {
|
||||
if (m_mode == airtaudio::mode_output || m_mode == airtaudio::mode_duplex) {
|
||||
if (m_state == audio::orchestra::state_running) {
|
||||
if (m_mode == audio::orchestra::mode_output || m_mode == audio::orchestra::mode_duplex) {
|
||||
ioctl(m_private->id[0], SNDCTL_DSP_HALT, 0);
|
||||
} else {
|
||||
ioctl(m_private->id[1], SNDCTL_DSP_HALT, 0);
|
||||
}
|
||||
m_state = airtaudio::state_stopped;
|
||||
m_state = audio::orchestra::state_stopped;
|
||||
}
|
||||
if (m_private->id[0] != nullptr) {
|
||||
close(m_private->id[0]);
|
||||
@ -571,46 +573,46 @@ enum airtaudio::error airtaudio::api::Oss::closeStream() {
|
||||
free(m_deviceBuffer);
|
||||
m_deviceBuffer = 0;
|
||||
}
|
||||
m_mode = airtaudio::mode_unknow;
|
||||
m_state = airtaudio::state_closed;
|
||||
return airtaudio::error_none;
|
||||
m_mode = audio::orchestra::mode_unknow;
|
||||
m_state = audio::orchestra::state_closed;
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
enum airtaudio::error airtaudio::api::Oss::startStream() {
|
||||
enum audio::orchestra::error audio::orchestra::api::Oss::startStream() {
|
||||
// TODO : Check return ...
|
||||
airtaudio::Api::startStream();
|
||||
if (verifyStream() != airtaudio::error_none) {
|
||||
return airtaudio::error_fail;
|
||||
audio::orchestra::Api::startStream();
|
||||
if (verifyStream() != audio::orchestra::error_none) {
|
||||
return audio::orchestra::error_fail;
|
||||
}
|
||||
if (m_state == airtaudio::state_running) {
|
||||
if (m_state == audio::orchestra::state_running) {
|
||||
ATA_ERROR("the stream is already running!");
|
||||
return airtaudio::error_warning;
|
||||
return audio::orchestra::error_warning;
|
||||
}
|
||||
m_mutex.lock();
|
||||
m_state = airtaudio::state_running;
|
||||
m_state = audio::orchestra::state_running;
|
||||
// No need to do anything else here ... OSS automatically starts
|
||||
// when fed samples.
|
||||
m_mutex.unlock();
|
||||
m_private->runnable.notify_one();
|
||||
}
|
||||
|
||||
enum airtaudio::error airtaudio::api::Oss::stopStream() {
|
||||
if (verifyStream() != airtaudio::error_none) {
|
||||
return airtaudio::error_fail;
|
||||
enum audio::orchestra::error audio::orchestra::api::Oss::stopStream() {
|
||||
if (verifyStream() != audio::orchestra::error_none) {
|
||||
return audio::orchestra::error_fail;
|
||||
}
|
||||
if (m_state == airtaudio::state_stopped) {
|
||||
if (m_state == audio::orchestra::state_stopped) {
|
||||
ATA_ERROR("the stream is already stopped!");
|
||||
return;
|
||||
}
|
||||
m_mutex.lock();
|
||||
// The state might change while waiting on a mutex.
|
||||
if (m_state == airtaudio::state_stopped) {
|
||||
if (m_state == audio::orchestra::state_stopped) {
|
||||
m_mutex.unlock();
|
||||
return;
|
||||
}
|
||||
int32_t result = 0;
|
||||
if ( m_mode == airtaudio::mode_output
|
||||
|| m_mode == airtaudio::mode_duplex) {
|
||||
if ( m_mode == audio::orchestra::mode_output
|
||||
|| m_mode == audio::orchestra::mode_duplex) {
|
||||
// Flush the output with zeros a few times.
|
||||
char *buffer;
|
||||
int32_t samples;
|
||||
@ -629,7 +631,7 @@ enum airtaudio::error airtaudio::api::Oss::stopStream() {
|
||||
result = write(m_private->id[0], buffer, samples * audio::getFormatBytes(format));
|
||||
if (result == -1) {
|
||||
ATA_ERROR("audio write error.");
|
||||
return airtaudio::error_warning;
|
||||
return audio::orchestra::error_warning;
|
||||
}
|
||||
}
|
||||
result = ioctl(m_private->id[0], SNDCTL_DSP_HALT, 0);
|
||||
@ -639,8 +641,8 @@ enum airtaudio::error airtaudio::api::Oss::stopStream() {
|
||||
}
|
||||
m_private->triggered = false;
|
||||
}
|
||||
if ( m_mode == airtaudio::mode_input
|
||||
|| ( m_mode == airtaudio::mode_duplex
|
||||
if ( m_mode == audio::orchestra::mode_input
|
||||
|| ( m_mode == audio::orchestra::mode_duplex
|
||||
&& m_private->id[0] != m_private->id[1])) {
|
||||
result = ioctl(m_private->id[1], SNDCTL_DSP_HALT, 0);
|
||||
if (result == -1) {
|
||||
@ -649,30 +651,30 @@ enum airtaudio::error airtaudio::api::Oss::stopStream() {
|
||||
}
|
||||
}
|
||||
unlock:
|
||||
m_state = airtaudio::state_stopped;
|
||||
m_state = audio::orchestra::state_stopped;
|
||||
m_mutex.unlock();
|
||||
if (result != -1) {
|
||||
return airtaudio::error_none;
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
return airtaudio::error_systemError;
|
||||
return audio::orchestra::error_systemError;
|
||||
}
|
||||
|
||||
enum airtaudio::error airtaudio::api::Oss::abortStream() {
|
||||
if (verifyStream() != airtaudio::error_none) {
|
||||
return airtaudio::error_fail;
|
||||
enum audio::orchestra::error audio::orchestra::api::Oss::abortStream() {
|
||||
if (verifyStream() != audio::orchestra::error_none) {
|
||||
return audio::orchestra::error_fail;
|
||||
}
|
||||
if (m_state == airtaudio::state_stopped) {
|
||||
if (m_state == audio::orchestra::state_stopped) {
|
||||
ATA_ERROR("the stream is already stopped!");
|
||||
return airtaudio::error_warning;
|
||||
return audio::orchestra::error_warning;
|
||||
}
|
||||
m_mutex.lock();
|
||||
// The state might change while waiting on a mutex.
|
||||
if (m_state == airtaudio::state_stopped) {
|
||||
if (m_state == audio::orchestra::state_stopped) {
|
||||
m_mutex.unlock();
|
||||
return;
|
||||
}
|
||||
int32_t result = 0;
|
||||
if (m_mode == airtaudio::mode_output || m_mode == airtaudio::mode_duplex) {
|
||||
if (m_mode == audio::orchestra::mode_output || m_mode == audio::orchestra::mode_duplex) {
|
||||
result = ioctl(m_private->id[0], SNDCTL_DSP_HALT, 0);
|
||||
if (result == -1) {
|
||||
ATA_ERROR("system error stopping callback procedure on device (" << m_device[0] << ").");
|
||||
@ -680,7 +682,7 @@ enum airtaudio::error airtaudio::api::Oss::abortStream() {
|
||||
}
|
||||
m_private->triggered = false;
|
||||
}
|
||||
if (m_mode == airtaudio::mode_input || (m_mode == airtaudio::mode_duplex && m_private->id[0] != m_private->id[1])) {
|
||||
if (m_mode == audio::orchestra::mode_input || (m_mode == audio::orchestra::mode_duplex && m_private->id[0] != m_private->id[1])) {
|
||||
result = ioctl(m_private->id[1], SNDCTL_DSP_HALT, 0);
|
||||
if (result == -1) {
|
||||
ATA_ERROR("system error stopping input callback procedure on device (" << m_device[0] << ").");
|
||||
@ -688,38 +690,38 @@ enum airtaudio::error airtaudio::api::Oss::abortStream() {
|
||||
}
|
||||
}
|
||||
unlock:
|
||||
m_state = airtaudio::state_stopped;
|
||||
m_state = audio::orchestra::state_stopped;
|
||||
m_mutex.unlock();
|
||||
if (result != -1) {
|
||||
return airtaudio::error_none;
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
return airtaudio::error_systemError;
|
||||
return audio::orchestra::error_systemError;
|
||||
}
|
||||
|
||||
void airtaudio::api::Oss::callbackEvent() {
|
||||
if (m_state == airtaudio::state_stopped) {
|
||||
void audio::orchestra::api::Oss::callbackEvent() {
|
||||
if (m_state == audio::orchestra::state_stopped) {
|
||||
std11::unique_lock<std11::mutex> lck(m_mutex);
|
||||
m_private->runnable.wait(lck);
|
||||
if (m_state != airtaudio::state_running) {
|
||||
if (m_state != audio::orchestra::state_running) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (m_state == airtaudio::state_closed) {
|
||||
if (m_state == audio::orchestra::state_closed) {
|
||||
ATA_ERROR("the stream is closed ... this shouldn't happen!");
|
||||
return airtaudio::error_warning;
|
||||
return audio::orchestra::error_warning;
|
||||
}
|
||||
// Invoke user callback to get fresh output data.
|
||||
int32_t doStopStream = 0;
|
||||
std11::chrono::system_clock::time_point streamTime = getStreamTime();
|
||||
std::vector<enum airtaudio::status> status;
|
||||
if ( m_mode != airtaudio::mode_input
|
||||
std::vector<enum audio::orchestra::status> status;
|
||||
if ( m_mode != audio::orchestra::mode_input
|
||||
&& m_private->xrun[0] == true) {
|
||||
status.push_back(airtaudio::status_underflow);
|
||||
status.push_back(audio::orchestra::status_underflow);
|
||||
m_private->xrun[0] = false;
|
||||
}
|
||||
if ( m_mode != airtaudio::mode_output
|
||||
if ( m_mode != audio::orchestra::mode_output
|
||||
&& m_private->xrun[1] == true) {
|
||||
status.push_back(airtaudio::status_overflow);
|
||||
status.push_back(audio::orchestra::status_overflow);
|
||||
m_private->xrun[1] = false;
|
||||
}
|
||||
doStopStream = m_callback(m_userBuffer[1],
|
||||
@ -734,15 +736,15 @@ void airtaudio::api::Oss::callbackEvent() {
|
||||
}
|
||||
m_mutex.lock();
|
||||
// The state might change while waiting on a mutex.
|
||||
if (m_state == airtaudio::state_stopped) {
|
||||
if (m_state == audio::orchestra::state_stopped) {
|
||||
goto unlock;
|
||||
}
|
||||
int32_t result;
|
||||
char *buffer;
|
||||
int32_t samples;
|
||||
audio::format format;
|
||||
if ( m_mode == airtaudio::mode_output
|
||||
|| m_mode == airtaudio::mode_duplex) {
|
||||
if ( m_mode == audio::orchestra::mode_output
|
||||
|| m_mode == audio::orchestra::mode_duplex) {
|
||||
// Setup parameters and do buffer conversion if necessary.
|
||||
if (m_doConvertBuffer[0]) {
|
||||
buffer = m_deviceBuffer;
|
||||
@ -758,12 +760,12 @@ void airtaudio::api::Oss::callbackEvent() {
|
||||
if (m_doByteSwap[0]) {
|
||||
byteSwapBuffer(buffer, samples, format);
|
||||
}
|
||||
if ( m_mode == airtaudio::mode_duplex
|
||||
if ( m_mode == audio::orchestra::mode_duplex
|
||||
&& m_private->triggered == false) {
|
||||
int32_t trig = 0;
|
||||
ioctl(m_private->id[0], SNDCTL_DSP_SETTRIGGER, &trig);
|
||||
result = write(m_private->id[0], buffer, samples * audio::getFormatBytes(format));
|
||||
trig = PCM_ENABLE_airtaudio::mode_input|PCM_ENABLE_airtaudio::mode_output;
|
||||
trig = PCM_ENABLE_audio::orchestra::mode_input|PCM_ENABLE_audio::orchestra::mode_output;
|
||||
ioctl(m_private->id[0], SNDCTL_DSP_SETTRIGGER, &trig);
|
||||
m_private->triggered = true;
|
||||
} else {
|
||||
@ -775,12 +777,12 @@ void airtaudio::api::Oss::callbackEvent() {
|
||||
// specific means for determining that.
|
||||
m_private->xrun[0] = true;
|
||||
ATA_ERROR("audio write error.");
|
||||
//error(airtaudio::error_warning);
|
||||
//error(audio::orchestra::error_warning);
|
||||
// Continue on to input section.
|
||||
}
|
||||
}
|
||||
if ( m_mode == airtaudio::mode_input
|
||||
|| m_mode == airtaudio::mode_duplex) {
|
||||
if ( m_mode == audio::orchestra::mode_input
|
||||
|| m_mode == audio::orchestra::mode_duplex) {
|
||||
// Setup parameters.
|
||||
if (m_doConvertBuffer[1]) {
|
||||
buffer = m_deviceBuffer;
|
||||
@ -811,7 +813,7 @@ void airtaudio::api::Oss::callbackEvent() {
|
||||
}
|
||||
unlock:
|
||||
m_mutex.unlock();
|
||||
airtaudio::Api::tickStreamTime();
|
||||
audio::orchestra::Api::tickStreamTime();
|
||||
if (doStopStream == 1) {
|
||||
this->stopStream();
|
||||
}
|
||||
@ -819,7 +821,7 @@ unlock:
|
||||
|
||||
static void ossCallbackHandler(void* _userData) {
|
||||
etk::thread::setName("OSS callback-" + m_name);
|
||||
airtaudio::api::Alsa* myClass = reinterpret_cast<airtaudio::api::Oss*>(_userData);
|
||||
audio::orchestra::api::Alsa* myClass = reinterpret_cast<audio::orchestra::api::Oss*>(_userData);
|
||||
while (myClass->m_private->threadRunning == true) {
|
||||
myClass->callbackEvent();
|
||||
}
|
51
audio/orchestra/api/Oss.h
Normal file
51
audio/orchestra/api/Oss.h
Normal file
@ -0,0 +1,51 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#if !defined(__AUDIO_ORCHESTRA_API_OSS_H__) && defined(ORCHESTRA_BUILD_OSS)
|
||||
#define __AUDIO_ORCHESTRA_API_OSS_H__
|
||||
|
||||
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
namespace api {
|
||||
class OssPrivate;
|
||||
class Oss: public audio::orchestra::Api {
|
||||
public:
|
||||
static audio::orchestra::Api* Create();
|
||||
public:
|
||||
Oss();
|
||||
virtual ~Oss();
|
||||
enum audio::orchestra::type getCurrentApi() {
|
||||
return audio::orchestra::type_oss;
|
||||
}
|
||||
uint32_t getDeviceCount();
|
||||
audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _device);
|
||||
enum audio::orchestra::error closeStream();
|
||||
enum audio::orchestra::error startStream();
|
||||
enum audio::orchestra::error stopStream();
|
||||
enum audio::orchestra::error abortStream();
|
||||
// This function is intended for internal use only. It must be
|
||||
// public because it is called by the internal callback handler,
|
||||
// which is not a member of RtAudio. External use of this function
|
||||
// will most likely produce highly undesireable results!
|
||||
void callbackEvent();
|
||||
private:
|
||||
std11::shared_ptr<OssPrivate> m_private;
|
||||
bool probeDeviceOpen(uint32_t _device,
|
||||
audio::orchestra::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const audio::orchestra::StreamOptions& _options);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -6,21 +6,22 @@
|
||||
*/
|
||||
|
||||
|
||||
#if defined(__LINUX_PULSE__)
|
||||
#if defined(ORCHESTRA_BUILD_PULSE)
|
||||
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#include <airtaudio/Interface.h>
|
||||
#include <airtaudio/debug.h>
|
||||
#include <audio/orchestra/Interface.h>
|
||||
#include <audio/orchestra/debug.h>
|
||||
#include <pulse/error.h>
|
||||
#include <pulse/simple.h>
|
||||
#include <cstdio>
|
||||
#include <etk/thread/tools.h>
|
||||
|
||||
#undef __class__
|
||||
#define __class__ "api::Pulse"
|
||||
|
||||
airtaudio::Api* airtaudio::api::Pulse::Create() {
|
||||
return new airtaudio::api::Pulse();
|
||||
audio::orchestra::Api* audio::orchestra::api::Pulse::Create() {
|
||||
return new audio::orchestra::api::Pulse();
|
||||
}
|
||||
|
||||
|
||||
@ -47,43 +48,45 @@ static const rtaudio_pa_format_mapping_t supported_sampleformats[] = {
|
||||
{audio::format_unknow, PA_SAMPLE_INVALID}};
|
||||
|
||||
|
||||
namespace airtaudio {
|
||||
namespace api {
|
||||
class PulsePrivate {
|
||||
public:
|
||||
pa_simple *s_play;
|
||||
pa_simple *s_rec;
|
||||
std11::shared_ptr<std11::thread> thread;
|
||||
bool threadRunning;
|
||||
std11::condition_variable runnable_cv;
|
||||
bool runnable;
|
||||
PulsePrivate() :
|
||||
s_play(0),
|
||||
s_rec(0),
|
||||
threadRunning(false),
|
||||
runnable(false) {
|
||||
|
||||
}
|
||||
};
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
namespace api {
|
||||
class PulsePrivate {
|
||||
public:
|
||||
pa_simple *s_play;
|
||||
pa_simple *s_rec;
|
||||
std11::shared_ptr<std11::thread> thread;
|
||||
bool threadRunning;
|
||||
std11::condition_variable runnable_cv;
|
||||
bool runnable;
|
||||
PulsePrivate() :
|
||||
s_play(0),
|
||||
s_rec(0),
|
||||
threadRunning(false),
|
||||
runnable(false) {
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
airtaudio::api::Pulse::Pulse() :
|
||||
m_private(new airtaudio::api::PulsePrivate()) {
|
||||
audio::orchestra::api::Pulse::Pulse() :
|
||||
m_private(new audio::orchestra::api::PulsePrivate()) {
|
||||
|
||||
}
|
||||
|
||||
airtaudio::api::Pulse::~Pulse() {
|
||||
if (m_state != airtaudio::state_closed) {
|
||||
audio::orchestra::api::Pulse::~Pulse() {
|
||||
if (m_state != audio::orchestra::state_closed) {
|
||||
closeStream();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t airtaudio::api::Pulse::getDeviceCount() {
|
||||
uint32_t audio::orchestra::api::Pulse::getDeviceCount() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
airtaudio::DeviceInfo airtaudio::api::Pulse::getDeviceInfo(uint32_t _device) {
|
||||
airtaudio::DeviceInfo info;
|
||||
audio::orchestra::DeviceInfo audio::orchestra::api::Pulse::getDeviceInfo(uint32_t _device) {
|
||||
audio::orchestra::DeviceInfo info;
|
||||
info.probed = true;
|
||||
info.name = "PulseAudio";
|
||||
info.outputChannels = 2;
|
||||
@ -101,21 +104,21 @@ airtaudio::DeviceInfo airtaudio::api::Pulse::getDeviceInfo(uint32_t _device) {
|
||||
}
|
||||
|
||||
static void pulseaudio_callback(void* _userData) {
|
||||
airtaudio::api::Pulse* myClass = reinterpret_cast<airtaudio::api::Pulse*>(_userData);
|
||||
audio::orchestra::api::Pulse* myClass = reinterpret_cast<audio::orchestra::api::Pulse*>(_userData);
|
||||
myClass->callbackEvent();
|
||||
}
|
||||
|
||||
void airtaudio::api::Pulse::callbackEvent() {
|
||||
void audio::orchestra::api::Pulse::callbackEvent() {
|
||||
etk::thread::setName("Pulse IO-" + m_name);
|
||||
while (m_private->threadRunning == true) {
|
||||
callbackEventOneCycle();
|
||||
}
|
||||
}
|
||||
|
||||
enum airtaudio::error airtaudio::api::Pulse::closeStream() {
|
||||
enum audio::orchestra::error audio::orchestra::api::Pulse::closeStream() {
|
||||
m_private->threadRunning = false;
|
||||
m_mutex.lock();
|
||||
if (m_state == airtaudio::state_stopped) {
|
||||
if (m_state == audio::orchestra::state_stopped) {
|
||||
m_private->runnable = true;
|
||||
m_private->runnable_cv.notify_one();;
|
||||
}
|
||||
@ -130,31 +133,31 @@ enum airtaudio::error airtaudio::api::Pulse::closeStream() {
|
||||
}
|
||||
m_userBuffer[0].clear();
|
||||
m_userBuffer[1].clear();
|
||||
m_state = airtaudio::state_closed;
|
||||
m_mode = airtaudio::mode_unknow;
|
||||
return airtaudio::error_none;
|
||||
m_state = audio::orchestra::state_closed;
|
||||
m_mode = audio::orchestra::mode_unknow;
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
void airtaudio::api::Pulse::callbackEventOneCycle() {
|
||||
if (m_state == airtaudio::state_stopped) {
|
||||
void audio::orchestra::api::Pulse::callbackEventOneCycle() {
|
||||
if (m_state == audio::orchestra::state_stopped) {
|
||||
std11::unique_lock<std11::mutex> lck(m_mutex);
|
||||
while (!m_private->runnable) {
|
||||
m_private->runnable_cv.wait(lck);
|
||||
}
|
||||
if (m_state != airtaudio::state_running) {
|
||||
if (m_state != audio::orchestra::state_running) {
|
||||
m_mutex.unlock();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (m_state == airtaudio::state_closed) {
|
||||
if (m_state == audio::orchestra::state_closed) {
|
||||
ATA_ERROR("the stream is closed ... this shouldn't happen!");
|
||||
return;
|
||||
}
|
||||
std11::chrono::system_clock::time_point streamTime = getStreamTime();
|
||||
std::vector<enum airtaudio::status> status;
|
||||
int32_t doStopStream = m_callback(&m_userBuffer[airtaudio::modeToIdTable(airtaudio::mode_input)][0],
|
||||
std::vector<enum audio::orchestra::status> status;
|
||||
int32_t doStopStream = m_callback(&m_userBuffer[audio::orchestra::modeToIdTable(audio::orchestra::mode_input)][0],
|
||||
streamTime,
|
||||
&m_userBuffer[airtaudio::modeToIdTable(airtaudio::mode_output)][0],
|
||||
&m_userBuffer[audio::orchestra::modeToIdTable(audio::orchestra::mode_output)][0],
|
||||
streamTime,
|
||||
m_bufferSize,
|
||||
status);
|
||||
@ -163,47 +166,47 @@ void airtaudio::api::Pulse::callbackEventOneCycle() {
|
||||
return;
|
||||
}
|
||||
m_mutex.lock();
|
||||
void *pulse_in = m_doConvertBuffer[airtaudio::modeToIdTable(airtaudio::mode_input)] ? m_deviceBuffer : &m_userBuffer[airtaudio::modeToIdTable(airtaudio::mode_input)][0];
|
||||
void *pulse_out = m_doConvertBuffer[airtaudio::modeToIdTable(airtaudio::mode_output)] ? m_deviceBuffer : &m_userBuffer[airtaudio::modeToIdTable(airtaudio::mode_output)][0];
|
||||
if (m_state != airtaudio::state_running) {
|
||||
void *pulse_in = m_doConvertBuffer[audio::orchestra::modeToIdTable(audio::orchestra::mode_input)] ? m_deviceBuffer : &m_userBuffer[audio::orchestra::modeToIdTable(audio::orchestra::mode_input)][0];
|
||||
void *pulse_out = m_doConvertBuffer[audio::orchestra::modeToIdTable(audio::orchestra::mode_output)] ? m_deviceBuffer : &m_userBuffer[audio::orchestra::modeToIdTable(audio::orchestra::mode_output)][0];
|
||||
if (m_state != audio::orchestra::state_running) {
|
||||
goto unlock;
|
||||
}
|
||||
int32_t pa_error;
|
||||
size_t bytes;
|
||||
if ( m_mode == airtaudio::mode_output
|
||||
|| m_mode == airtaudio::mode_duplex) {
|
||||
if (m_doConvertBuffer[airtaudio::modeToIdTable(airtaudio::mode_output)]) {
|
||||
if ( m_mode == audio::orchestra::mode_output
|
||||
|| m_mode == audio::orchestra::mode_duplex) {
|
||||
if (m_doConvertBuffer[audio::orchestra::modeToIdTable(audio::orchestra::mode_output)]) {
|
||||
convertBuffer(m_deviceBuffer,
|
||||
&m_userBuffer[airtaudio::modeToIdTable(airtaudio::mode_output)][0],
|
||||
m_convertInfo[airtaudio::modeToIdTable(airtaudio::mode_output)]);
|
||||
bytes = m_nDeviceChannels[airtaudio::modeToIdTable(airtaudio::mode_output)] * m_bufferSize * audio::getFormatBytes(m_deviceFormat[airtaudio::modeToIdTable(airtaudio::mode_output)]);
|
||||
&m_userBuffer[audio::orchestra::modeToIdTable(audio::orchestra::mode_output)][0],
|
||||
m_convertInfo[audio::orchestra::modeToIdTable(audio::orchestra::mode_output)]);
|
||||
bytes = m_nDeviceChannels[audio::orchestra::modeToIdTable(audio::orchestra::mode_output)] * m_bufferSize * audio::getFormatBytes(m_deviceFormat[audio::orchestra::modeToIdTable(audio::orchestra::mode_output)]);
|
||||
} else {
|
||||
bytes = m_nUserChannels[airtaudio::modeToIdTable(airtaudio::mode_output)] * m_bufferSize * audio::getFormatBytes(m_userFormat);
|
||||
bytes = m_nUserChannels[audio::orchestra::modeToIdTable(audio::orchestra::mode_output)] * m_bufferSize * audio::getFormatBytes(m_userFormat);
|
||||
}
|
||||
if (pa_simple_write(m_private->s_play, pulse_out, bytes, &pa_error) < 0) {
|
||||
ATA_ERROR("audio write error, " << pa_strerror(pa_error) << ".");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (m_mode == airtaudio::mode_input || m_mode == airtaudio::mode_duplex) {
|
||||
if (m_doConvertBuffer[airtaudio::modeToIdTable(airtaudio::mode_input)]) {
|
||||
bytes = m_nDeviceChannels[airtaudio::modeToIdTable(airtaudio::mode_input)] * m_bufferSize * audio::getFormatBytes(m_deviceFormat[airtaudio::modeToIdTable(airtaudio::mode_input)]);
|
||||
if (m_mode == audio::orchestra::mode_input || m_mode == audio::orchestra::mode_duplex) {
|
||||
if (m_doConvertBuffer[audio::orchestra::modeToIdTable(audio::orchestra::mode_input)]) {
|
||||
bytes = m_nDeviceChannels[audio::orchestra::modeToIdTable(audio::orchestra::mode_input)] * m_bufferSize * audio::getFormatBytes(m_deviceFormat[audio::orchestra::modeToIdTable(audio::orchestra::mode_input)]);
|
||||
} else {
|
||||
bytes = m_nUserChannels[airtaudio::modeToIdTable(airtaudio::mode_input)] * m_bufferSize * audio::getFormatBytes(m_userFormat);
|
||||
bytes = m_nUserChannels[audio::orchestra::modeToIdTable(audio::orchestra::mode_input)] * m_bufferSize * audio::getFormatBytes(m_userFormat);
|
||||
}
|
||||
if (pa_simple_read(m_private->s_rec, pulse_in, bytes, &pa_error) < 0) {
|
||||
ATA_ERROR("audio read error, " << pa_strerror(pa_error) << ".");
|
||||
return;
|
||||
}
|
||||
if (m_doConvertBuffer[airtaudio::modeToIdTable(airtaudio::mode_input)]) {
|
||||
convertBuffer(&m_userBuffer[airtaudio::modeToIdTable(airtaudio::mode_input)][0],
|
||||
if (m_doConvertBuffer[audio::orchestra::modeToIdTable(audio::orchestra::mode_input)]) {
|
||||
convertBuffer(&m_userBuffer[audio::orchestra::modeToIdTable(audio::orchestra::mode_input)][0],
|
||||
m_deviceBuffer,
|
||||
m_convertInfo[airtaudio::modeToIdTable(airtaudio::mode_input)]);
|
||||
m_convertInfo[audio::orchestra::modeToIdTable(audio::orchestra::mode_input)]);
|
||||
}
|
||||
}
|
||||
unlock:
|
||||
m_mutex.unlock();
|
||||
airtaudio::Api::tickStreamTime();
|
||||
audio::orchestra::Api::tickStreamTime();
|
||||
if (doStopStream == 1) {
|
||||
stopStream();
|
||||
return;
|
||||
@ -211,87 +214,87 @@ unlock:
|
||||
return;
|
||||
}
|
||||
|
||||
enum airtaudio::error airtaudio::api::Pulse::startStream() {
|
||||
enum audio::orchestra::error audio::orchestra::api::Pulse::startStream() {
|
||||
// TODO : Check return ...
|
||||
airtaudio::Api::startStream();
|
||||
if (m_state == airtaudio::state_closed) {
|
||||
audio::orchestra::Api::startStream();
|
||||
if (m_state == audio::orchestra::state_closed) {
|
||||
ATA_ERROR("the stream is not open!");
|
||||
return airtaudio::error_invalidUse;
|
||||
return audio::orchestra::error_invalidUse;
|
||||
}
|
||||
if (m_state == airtaudio::state_running) {
|
||||
if (m_state == audio::orchestra::state_running) {
|
||||
ATA_ERROR("the stream is already running!");
|
||||
return airtaudio::error_warning;
|
||||
return audio::orchestra::error_warning;
|
||||
}
|
||||
m_mutex.lock();
|
||||
m_state = airtaudio::state_running;
|
||||
m_state = audio::orchestra::state_running;
|
||||
m_private->runnable = true;
|
||||
m_private->runnable_cv.notify_one();
|
||||
m_mutex.unlock();
|
||||
return airtaudio::error_none;
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
enum airtaudio::error airtaudio::api::Pulse::stopStream() {
|
||||
if (m_state == airtaudio::state_closed) {
|
||||
enum audio::orchestra::error audio::orchestra::api::Pulse::stopStream() {
|
||||
if (m_state == audio::orchestra::state_closed) {
|
||||
ATA_ERROR("the stream is not open!");
|
||||
return airtaudio::error_invalidUse;
|
||||
return audio::orchestra::error_invalidUse;
|
||||
}
|
||||
if (m_state == airtaudio::state_stopped) {
|
||||
if (m_state == audio::orchestra::state_stopped) {
|
||||
ATA_ERROR("the stream is already stopped!");
|
||||
return airtaudio::error_warning;
|
||||
return audio::orchestra::error_warning;
|
||||
}
|
||||
m_state = airtaudio::state_stopped;
|
||||
m_state = audio::orchestra::state_stopped;
|
||||
m_mutex.lock();
|
||||
if (m_private->s_play) {
|
||||
int32_t pa_error;
|
||||
if (pa_simple_drain(m_private->s_play, &pa_error) < 0) {
|
||||
ATA_ERROR("error draining output device, " << pa_strerror(pa_error) << ".");
|
||||
m_mutex.unlock();
|
||||
return airtaudio::error_systemError;
|
||||
return audio::orchestra::error_systemError;
|
||||
}
|
||||
}
|
||||
m_state = airtaudio::state_stopped;
|
||||
m_state = audio::orchestra::state_stopped;
|
||||
m_mutex.unlock();
|
||||
return airtaudio::error_none;
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
enum airtaudio::error airtaudio::api::Pulse::abortStream() {
|
||||
if (m_state == airtaudio::state_closed) {
|
||||
enum audio::orchestra::error audio::orchestra::api::Pulse::abortStream() {
|
||||
if (m_state == audio::orchestra::state_closed) {
|
||||
ATA_ERROR("the stream is not open!");
|
||||
return airtaudio::error_invalidUse;
|
||||
return audio::orchestra::error_invalidUse;
|
||||
}
|
||||
if (m_state == airtaudio::state_stopped) {
|
||||
if (m_state == audio::orchestra::state_stopped) {
|
||||
ATA_ERROR("the stream is already stopped!");
|
||||
return airtaudio::error_warning;
|
||||
return audio::orchestra::error_warning;
|
||||
}
|
||||
m_state = airtaudio::state_stopped;
|
||||
m_state = audio::orchestra::state_stopped;
|
||||
m_mutex.lock();
|
||||
if (m_private && m_private->s_play) {
|
||||
int32_t pa_error;
|
||||
if (pa_simple_flush(m_private->s_play, &pa_error) < 0) {
|
||||
ATA_ERROR("error flushing output device, " << pa_strerror(pa_error) << ".");
|
||||
m_mutex.unlock();
|
||||
return airtaudio::error_systemError;
|
||||
return audio::orchestra::error_systemError;
|
||||
}
|
||||
}
|
||||
m_state = airtaudio::state_stopped;
|
||||
m_state = audio::orchestra::state_stopped;
|
||||
m_mutex.unlock();
|
||||
return airtaudio::error_none;
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
bool airtaudio::api::Pulse::probeDeviceOpen(uint32_t _device,
|
||||
airtaudio::mode _mode,
|
||||
bool audio::orchestra::api::Pulse::probeDeviceOpen(uint32_t _device,
|
||||
audio::orchestra::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const airtaudio.::StreamOptions& _options) {
|
||||
const audio::orchestra::StreamOptions& _options) {
|
||||
uint64_t bufferBytes = 0;
|
||||
pa_sample_spec ss;
|
||||
if (_device != 0) {
|
||||
return false;
|
||||
}
|
||||
if (_mode != airtaudio::mode_input && _mode != airtaudio::mode_output) {
|
||||
if (_mode != audio::orchestra::mode_input && _mode != audio::orchestra::mode_output) {
|
||||
return false;
|
||||
}
|
||||
if (_channels != 1 && _channels != 2) {
|
||||
@ -349,8 +352,8 @@ bool airtaudio::api::Pulse::probeDeviceOpen(uint32_t _device,
|
||||
if (m_doConvertBuffer[modeToIdTable(_mode)]) {
|
||||
bool makeBuffer = true;
|
||||
bufferBytes = m_nDeviceChannels[modeToIdTable(_mode)] * audio::getFormatBytes(m_deviceFormat[modeToIdTable(_mode)]);
|
||||
if (_mode == airtaudio::mode_input) {
|
||||
if (m_mode == airtaudio::mode_output && m_deviceBuffer) {
|
||||
if (_mode == audio::orchestra::mode_input) {
|
||||
if (m_mode == audio::orchestra::mode_output && m_deviceBuffer) {
|
||||
uint64_t bytesOut = m_nDeviceChannels[0] * audio::getFormatBytes(m_deviceFormat[0]);
|
||||
if (bufferBytes <= bytesOut) makeBuffer = false;
|
||||
}
|
||||
@ -372,15 +375,15 @@ bool airtaudio::api::Pulse::probeDeviceOpen(uint32_t _device,
|
||||
}
|
||||
int32_t error;
|
||||
switch (_mode) {
|
||||
case airtaudio::mode_input:
|
||||
m_private->s_rec = pa_simple_new(nullptr, "airtAudio", PA_STREAM_RECORD, nullptr, "Record", &ss, nullptr, nullptr, &error);
|
||||
case audio::orchestra::mode_input:
|
||||
m_private->s_rec = pa_simple_new(nullptr, "orchestra", PA_STREAM_RECORD, nullptr, "Record", &ss, nullptr, nullptr, &error);
|
||||
if (!m_private->s_rec) {
|
||||
ATA_ERROR("error connecting input to PulseAudio server.");
|
||||
goto error;
|
||||
}
|
||||
break;
|
||||
case airtaudio::mode_output:
|
||||
m_private->s_play = pa_simple_new(nullptr, "airtAudio", PA_STREAM_PLAYBACK, nullptr, "Playback", &ss, nullptr, nullptr, &error);
|
||||
case audio::orchestra::mode_output:
|
||||
m_private->s_play = pa_simple_new(nullptr, "orchestra", PA_STREAM_PLAYBACK, nullptr, "Playback", &ss, nullptr, nullptr, &error);
|
||||
if (!m_private->s_play) {
|
||||
ATA_ERROR("error connecting output to PulseAudio server.");
|
||||
goto error;
|
||||
@ -389,12 +392,12 @@ bool airtaudio::api::Pulse::probeDeviceOpen(uint32_t _device,
|
||||
default:
|
||||
goto error;
|
||||
}
|
||||
if (m_mode == airtaudio::mode_unknow) {
|
||||
if (m_mode == audio::orchestra::mode_unknow) {
|
||||
m_mode = _mode;
|
||||
} else if (m_mode == _mode) {
|
||||
goto error;
|
||||
}else {
|
||||
m_mode = airtaudio::mode_duplex;
|
||||
m_mode = audio::orchestra::mode_duplex;
|
||||
}
|
||||
if (!m_private->threadRunning) {
|
||||
m_private->threadRunning = true;
|
||||
@ -405,7 +408,7 @@ bool airtaudio::api::Pulse::probeDeviceOpen(uint32_t _device,
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
m_state = airtaudio::state_stopped;
|
||||
m_state = audio::orchestra::state_stopped;
|
||||
return true;
|
||||
error:
|
||||
for (int32_t i=0; i<2; i++) {
|
54
audio/orchestra/api/Pulse.h
Normal file
54
audio/orchestra/api/Pulse.h
Normal file
@ -0,0 +1,54 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#if !defined(__AUDIO_ORCHESTRA_API_PULSE_H__) && defined(ORCHESTRA_BUILD_PULSE)
|
||||
#define __AUDIO_ORCHESTRA_API_PULSE_H__
|
||||
|
||||
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
namespace api {
|
||||
class PulsePrivate;
|
||||
class Pulse: public audio::orchestra::Api {
|
||||
public:
|
||||
static audio::orchestra::Api* Create();
|
||||
public:
|
||||
Pulse();
|
||||
virtual ~Pulse();
|
||||
enum audio::orchestra::type getCurrentApi() {
|
||||
return audio::orchestra::type_pulse;
|
||||
}
|
||||
uint32_t getDeviceCount();
|
||||
audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _device);
|
||||
enum audio::orchestra::error closeStream();
|
||||
enum audio::orchestra::error startStream();
|
||||
enum audio::orchestra::error stopStream();
|
||||
enum audio::orchestra::error abortStream();
|
||||
// This function is intended for internal use only. It must be
|
||||
// public because it is called by the internal callback handler,
|
||||
// which is not a member of RtAudio. External use of this function
|
||||
// will most likely produce highly undesireable results!
|
||||
void callbackEventOneCycle();
|
||||
void callbackEvent();
|
||||
private:
|
||||
std11::shared_ptr<PulsePrivate> m_private;
|
||||
std::vector<audio::orchestra::DeviceInfo> m_devices;
|
||||
void saveDeviceInfo();
|
||||
bool probeDeviceOpen(uint32_t _device,
|
||||
audio::orchestra::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const audio::orchestra::StreamOptions& _options);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -5,8 +5,8 @@
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#ifndef __AIRTAUDIO_CB_H__
|
||||
#define __AIRTAUDIO_CB_H__
|
||||
#ifndef __AUDIO_ORCHESTRA_CB_H__
|
||||
#define __AUDIO_ORCHESTRA_CB_H__
|
||||
#include <etk/thread.h>
|
||||
#include <etk/condition_variable.h>
|
||||
#include <etk/mutex.h>
|
||||
@ -15,14 +15,14 @@
|
||||
#include <etk/memory.h>
|
||||
#include <audio/channel.h>
|
||||
#include <audio/format.h>
|
||||
#include <airtaudio/error.h>
|
||||
#include <airtaudio/status.h>
|
||||
#include <airtaudio/Flags.h>
|
||||
#include <audio/orchestra/error.h>
|
||||
#include <audio/orchestra/status.h>
|
||||
#include <audio/orchestra/Flags.h>
|
||||
|
||||
#include <airtaudio/CallbackInfo.h>
|
||||
#include <airtaudio/DeviceInfo.h>
|
||||
#include <airtaudio/StreamOptions.h>
|
||||
#include <airtaudio/StreamParameters.h>
|
||||
#include <audio/orchestra/CallbackInfo.h>
|
||||
#include <audio/orchestra/DeviceInfo.h>
|
||||
#include <audio/orchestra/StreamOptions.h>
|
||||
#include <audio/orchestra/StreamParameters.h>
|
||||
|
||||
|
||||
#endif
|
@ -5,9 +5,9 @@
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#include <airtaudio/debug.h>
|
||||
#include <audio/orchestra/debug.h>
|
||||
|
||||
int32_t airtaudio::getLogId() {
|
||||
static int32_t g_val = etk::log::registerInstance("airtaudio");
|
||||
int32_t audio::orchestra::getLogId() {
|
||||
static int32_t g_val = etk::log::registerInstance("audio-orchestra");
|
||||
return g_val;
|
||||
}
|
@ -5,15 +5,17 @@
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#ifndef __AIRTAUDIO_DEBUG_H__
|
||||
#define __AIRTAUDIO_DEBUG_H__
|
||||
#ifndef __AUDIO_ORCHESTRA_DEBUG_H__
|
||||
#define __AUDIO_ORCHESTRA_DEBUG_H__
|
||||
|
||||
#include <etk/log.h>
|
||||
|
||||
namespace airtaudio {
|
||||
int32_t getLogId();
|
||||
};
|
||||
#define ATA_BASE(info,data) TK_LOG_BASE(airtaudio::getLogId(),info,data)
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
int32_t getLogId();
|
||||
}
|
||||
}
|
||||
#define ATA_BASE(info,data) TK_LOG_BASE(audio::orchestra::getLogId(),info,data)
|
||||
|
||||
#define ATA_CRITICAL(data) ATA_BASE(1, data)
|
||||
#define ATA_ERROR(data) ATA_BASE(2, data)
|
@ -5,5 +5,5 @@
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#include <airtaudio/error.h>
|
||||
#include <airtaudio/debug.h>
|
||||
#include <audio/orchestra/error.h>
|
||||
#include <audio/orchestra/debug.h>
|
26
audio/orchestra/error.h
Normal file
26
audio/orchestra/error.h
Normal file
@ -0,0 +1,26 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#ifndef __AUDIO_ORCHESTRA_ERROR_H__
|
||||
#define __AUDIO_ORCHESTRA_ERROR_H__
|
||||
|
||||
#include <etk/types.h>
|
||||
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
enum error {
|
||||
error_none, //!< No error
|
||||
error_fail, //!< An error occure in the operation
|
||||
error_warning, //!< A non-critical error.
|
||||
error_inputNull, //!< null input or internal errror
|
||||
error_invalidUse, //!< The function was called incorrectly.
|
||||
error_systemError //!< A system error occured.
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -5,10 +5,10 @@
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#include <airtaudio/mode.h>
|
||||
#include <airtaudio/debug.h>
|
||||
#include <audio/orchestra/mode.h>
|
||||
#include <audio/orchestra/debug.h>
|
||||
|
||||
int32_t airtaudio::modeToIdTable(enum mode _mode) {
|
||||
int32_t audio::orchestra::modeToIdTable(enum mode _mode) {
|
||||
switch (_mode) {
|
||||
case mode_unknow:
|
||||
case mode_duplex:
|
26
audio/orchestra/mode.h
Normal file
26
audio/orchestra/mode.h
Normal file
@ -0,0 +1,26 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#ifndef __AUDIO_ORCHESTRA_MODE_H__
|
||||
#define __AUDIO_ORCHESTRA_MODE_H__
|
||||
|
||||
#include <etk/types.h>
|
||||
|
||||
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
enum mode {
|
||||
mode_unknow,
|
||||
mode_output,
|
||||
mode_input,
|
||||
mode_duplex
|
||||
};
|
||||
int32_t modeToIdTable(enum mode _mode);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
25
audio/orchestra/state.h
Normal file
25
audio/orchestra/state.h
Normal file
@ -0,0 +1,25 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#ifndef __AUDIO_ORCHESTRA_STATE_H__
|
||||
#define __AUDIO_ORCHESTRA_STATE_H__
|
||||
|
||||
#include <etk/types.h>
|
||||
|
||||
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
enum state {
|
||||
state_closed,
|
||||
state_stopped,
|
||||
state_stopping,
|
||||
state_running
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -5,20 +5,20 @@
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#include <airtaudio/status.h>
|
||||
#include <airtaudio/debug.h>
|
||||
#include <audio/orchestra/status.h>
|
||||
#include <audio/orchestra/debug.h>
|
||||
static const char* listValue[] = {
|
||||
"ok",
|
||||
"overflow",
|
||||
"underflow"
|
||||
};
|
||||
|
||||
std::ostream& airtaudio::operator <<(std::ostream& _os, enum airtaudio::status _obj) {
|
||||
std::ostream& audio::orchestra::operator <<(std::ostream& _os, enum audio::orchestra::status _obj) {
|
||||
_os << listValue[_obj];
|
||||
return _os;
|
||||
}
|
||||
|
||||
std::ostream& airtaudio::operator <<(std::ostream& _os, const std::vector<enum airtaudio::status>& _obj) {
|
||||
std::ostream& audio::orchestra::operator <<(std::ostream& _os, const std::vector<enum audio::orchestra::status>& _obj) {
|
||||
_os << std::string("{");
|
||||
for (size_t iii=0; iii<_obj.size(); ++iii) {
|
||||
if (iii!=0) {
|
26
audio/orchestra/status.h
Normal file
26
audio/orchestra/status.h
Normal file
@ -0,0 +1,26 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#ifndef __AUDIO_ORCHESTRA_STATUS_H__
|
||||
#define __AUDIO_ORCHESTRA_STATUS_H__
|
||||
|
||||
#include <etk/types.h>
|
||||
|
||||
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
enum status {
|
||||
status_ok, //!< nothing...
|
||||
status_overflow, //!< Internal buffer has more data than they can accept
|
||||
status_underflow //!< The internal buffer is empty
|
||||
};
|
||||
std::ostream& operator <<(std::ostream& _os, enum audio::orchestra::status _obj);
|
||||
std::ostream& operator <<(std::ostream& _os, const std::vector<enum audio::orchestra::status>& _obj);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -5,8 +5,8 @@
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#include <airtaudio/type.h>
|
||||
#include <airtaudio/debug.h>
|
||||
#include <audio/orchestra/type.h>
|
||||
#include <audio/orchestra/debug.h>
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
@ -35,12 +35,12 @@ static const char* listType[] = {
|
||||
static int32_t listTypeSize = sizeof(listType)/sizeof(char*);
|
||||
|
||||
|
||||
std::ostream& airtaudio::operator <<(std::ostream& _os, const enum airtaudio::type& _obj) {
|
||||
std::ostream& audio::orchestra::operator <<(std::ostream& _os, const enum audio::orchestra::type& _obj) {
|
||||
_os << listType[_obj];
|
||||
return _os;
|
||||
}
|
||||
|
||||
std::ostream& airtaudio::operator <<(std::ostream& _os, const std::vector<enum airtaudio::type>& _obj) {
|
||||
std::ostream& audio::orchestra::operator <<(std::ostream& _os, const std::vector<enum audio::orchestra::type>& _obj) {
|
||||
_os << std::string("{");
|
||||
for (size_t iii=0; iii<_obj.size(); ++iii) {
|
||||
if (iii!=0) {
|
||||
@ -56,18 +56,18 @@ template <enum audio::format> std::string to_string(const enum audio::format& _v
|
||||
return listType[_value];
|
||||
}
|
||||
*/
|
||||
std::string airtaudio::getTypeString(enum airtaudio::type _value) {
|
||||
std::string audio::orchestra::getTypeString(enum audio::orchestra::type _value) {
|
||||
return listType[_value];
|
||||
}
|
||||
|
||||
enum airtaudio::type airtaudio::getTypeFromString(const std::string& _value) {
|
||||
enum audio::orchestra::type audio::orchestra::getTypeFromString(const std::string& _value) {
|
||||
for (int32_t iii=0; iii<listTypeSize; ++iii) {
|
||||
if (_value == listType[iii]) {
|
||||
return static_cast<enum airtaudio::type>(iii);
|
||||
return static_cast<enum audio::orchestra::type>(iii);
|
||||
}
|
||||
}
|
||||
if (_value == "auto") {
|
||||
return airtaudio::type_undefined;
|
||||
return audio::orchestra::type_undefined;
|
||||
}
|
||||
return airtaudio::type_undefined;
|
||||
return audio::orchestra::type_undefined;
|
||||
}
|
44
audio/orchestra/type.h
Normal file
44
audio/orchestra/type.h
Normal file
@ -0,0 +1,44 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#ifndef __AUDIO_ORCHESTRA_TYPE_H__
|
||||
#define __AUDIO_ORCHESTRA_TYPE_H__
|
||||
|
||||
#include <etk/types.h>
|
||||
#include <etk/stdTools.h>
|
||||
|
||||
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
/**
|
||||
* @brief Audio API specifier arguments.
|
||||
*/
|
||||
enum type {
|
||||
type_undefined, //!< Error API.
|
||||
type_alsa, //!< LINUX The Advanced Linux Sound Architecture.
|
||||
type_pulse, //!< LINUX The Linux PulseAudio.
|
||||
type_oss, //!< LINUX The Linux Open Sound System.
|
||||
type_jack, //!< UNIX The Jack Low-Latency Audio Server.
|
||||
type_coreOSX, //!< Macintosh OSX Core Audio.
|
||||
type_coreIOS, //!< Macintosh iOS Core Audio.
|
||||
type_asio, //!< WINDOWS The Steinberg Audio Stream I/O.
|
||||
type_ds, //!< WINDOWS The Microsoft Direct Sound.
|
||||
type_java, //!< ANDROID Interface.
|
||||
type_dummy, //!< Empty wrapper (non-functional).
|
||||
type_user1, //!< User interface 1.
|
||||
type_user2, //!< User interface 2.
|
||||
type_user3, //!< User interface 3.
|
||||
type_user4, //!< User interface 4.
|
||||
};
|
||||
std::ostream& operator <<(std::ostream& _os, const enum audio::orchestra::type& _obj);
|
||||
std::ostream& operator <<(std::ostream& _os, const std::vector<enum audio::orchestra::type>& _obj);
|
||||
std::string getTypeString(enum audio::orchestra::type _value);
|
||||
enum audio::orchestra::type getTypeFromString(const std::string& _value);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -1,83 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
import lutinModule as module
|
||||
import lutinTools as tools
|
||||
import lutinDebug as debug
|
||||
|
||||
def get_desc():
|
||||
return "airtaudio : Generic wrapper on all audio interface"
|
||||
|
||||
|
||||
def create(target):
|
||||
myModule = module.Module(__file__, 'airtaudio', 'LIBRARY')
|
||||
|
||||
myModule.add_src_file([
|
||||
'airtaudio/debug.cpp',
|
||||
'airtaudio/status.cpp',
|
||||
'airtaudio/type.cpp',
|
||||
'airtaudio/mode.cpp',
|
||||
'airtaudio/state.cpp',
|
||||
'airtaudio/error.cpp',
|
||||
'airtaudio/base.cpp',
|
||||
'airtaudio/Interface.cpp',
|
||||
'airtaudio/Flags.cpp',
|
||||
'airtaudio/Api.cpp',
|
||||
'airtaudio/DeviceInfo.cpp',
|
||||
'airtaudio/StreamOptions.cpp',
|
||||
'airtaudio/api/Dummy.cpp'
|
||||
])
|
||||
myModule.add_module_depend(['audio', 'etk'])
|
||||
# add all the time the dummy interface
|
||||
myModule.add_export_flag_CC(['-D__DUMMY__'])
|
||||
# TODO : Add a FILE interface:
|
||||
|
||||
if target.name=="Windows":
|
||||
myModule.add_src_file([
|
||||
'airtaudio/api/Asio.cpp',
|
||||
'airtaudio/api/Ds.cpp',
|
||||
])
|
||||
# load optionnal API:
|
||||
myModule.add_optionnal_module_depend('asio', "__WINDOWS_ASIO__")
|
||||
myModule.add_optionnal_module_depend('ds', "__WINDOWS_DS__")
|
||||
myModule.add_optionnal_module_depend('wasapi', "__WINDOWS_WASAPI__")
|
||||
elif target.name=="Linux":
|
||||
myModule.add_src_file([
|
||||
'airtaudio/api/Alsa.cpp',
|
||||
'airtaudio/api/Jack.cpp',
|
||||
'airtaudio/api/Pulse.cpp',
|
||||
'airtaudio/api/Oss.cpp'
|
||||
])
|
||||
myModule.add_optionnal_module_depend('alsa', "__LINUX_ALSA__")
|
||||
#myModule.add_optionnal_module_depend('jack', "__UNIX_JACK__")
|
||||
#myModule.add_optionnal_module_depend('pulse', "__LINUX_PULSE__")
|
||||
#myModule.add_optionnal_module_depend('oss', "__LINUX_OSS__")
|
||||
elif target.name=="MacOs":
|
||||
myModule.add_src_file([
|
||||
'airtaudio/api/Core.cpp',
|
||||
'airtaudio/api/Oss.cpp'
|
||||
])
|
||||
# MacOsX core
|
||||
myModule.add_optionnal_module_depend('CoreAudio', "__MACOSX_CORE__")
|
||||
#myModule.add_export_flag_CC(['-D__MACOSX_CORE__'])
|
||||
#myModule.add_export_flag_LD("-framework CoreAudio")
|
||||
elif target.name=="IOs":
|
||||
myModule.add_src_file('airtaudio/api/CoreIos.mm')
|
||||
# IOsX core
|
||||
myModule.add_optionnal_module_depend('CoreAudio', "__IOS_CORE__")
|
||||
#myModule.add_export_flag_CC(['-D__IOS_CORE__'])
|
||||
#myModule.add_export_flag_LD("-framework CoreAudio")
|
||||
#myModule.add_export_flag_LD("-framework AudioToolbox")
|
||||
elif target.name=="Android":
|
||||
myModule.add_src_file('airtaudio/api/Android.cpp')
|
||||
# specidic java interface for android:
|
||||
myModule.add_optionnal_module_depend('ewolAndroidAudio', "__ANDROID_JAVA__")
|
||||
#myModule.add_export_flag_CC(['-D__ANDROID_JAVA__'])
|
||||
#myModule.add_module_depend(['ewol'])
|
||||
else:
|
||||
debug.warning("unknow target for AIRTAudio : " + target.name);
|
||||
|
||||
myModule.add_export_path(tools.get_current_path(__file__))
|
||||
|
||||
# add the currrent module at the
|
||||
return myModule
|
||||
|
||||
|
77
lutin_audio_orchestra.py
Normal file
77
lutin_audio_orchestra.py
Normal file
@ -0,0 +1,77 @@
|
||||
#!/usr/bin/python
|
||||
import lutinModule as module
|
||||
import lutinTools as tools
|
||||
import lutinDebug as debug
|
||||
|
||||
def get_desc():
|
||||
return "audio_orchestra : Generic wrapper on all audio interface"
|
||||
|
||||
|
||||
def create(target):
|
||||
myModule = module.Module(__file__, 'audio_orchestra', 'LIBRARY')
|
||||
|
||||
myModule.add_src_file([
|
||||
'audio/orchestra/debug.cpp',
|
||||
'audio/orchestra/status.cpp',
|
||||
'audio/orchestra/type.cpp',
|
||||
'audio/orchestra/mode.cpp',
|
||||
'audio/orchestra/state.cpp',
|
||||
'audio/orchestra/error.cpp',
|
||||
'audio/orchestra/base.cpp',
|
||||
'audio/orchestra/Interface.cpp',
|
||||
'audio/orchestra/Flags.cpp',
|
||||
'audio/orchestra/Api.cpp',
|
||||
'audio/orchestra/DeviceInfo.cpp',
|
||||
'audio/orchestra/StreamOptions.cpp',
|
||||
'audio/orchestra/api/Dummy.cpp'
|
||||
])
|
||||
myModule.add_module_depend(['audio', 'etk'])
|
||||
# add all the time the dummy interface
|
||||
myModule.add_export_flag_CC(['-DORCHESTRA_BUILD_DUMMY'])
|
||||
# TODO : Add a FILE interface:
|
||||
|
||||
if target.name=="Windows":
|
||||
myModule.add_src_file([
|
||||
'audio/orchestra/api/Asio.cpp',
|
||||
'audio/orchestra/api/Ds.cpp',
|
||||
])
|
||||
# load optionnal API:
|
||||
myModule.add_optionnal_module_depend('asio', "ORCHESTRA_BUILD_ASIO")
|
||||
myModule.add_optionnal_module_depend('ds', "ORCHESTRA_BUILD_DS")
|
||||
myModule.add_optionnal_module_depend('wasapi', "ORCHESTRA_BUILD_WASAPI")
|
||||
elif target.name=="Linux":
|
||||
myModule.add_src_file([
|
||||
'audio/orchestra/api/Alsa.cpp',
|
||||
'audio/orchestra/api/Jack.cpp',
|
||||
'audio/orchestra/api/Pulse.cpp',
|
||||
'audio/orchestra/api/Oss.cpp'
|
||||
])
|
||||
myModule.add_optionnal_module_depend('alsa', "ORCHESTRA_BUILD_ALSA")
|
||||
myModule.add_optionnal_module_depend('jack', "ORCHESTRA_BUILD_JACK")
|
||||
myModule.add_optionnal_module_depend('pulse', "ORCHESTRA_BUILD_PULSE")
|
||||
myModule.add_optionnal_module_depend('oss', "ORCHESTRA_BUILD_OSS")
|
||||
elif target.name=="MacOs":
|
||||
myModule.add_src_file([
|
||||
'audio/orchestra/api/Core.cpp',
|
||||
'audio/orchestra/api/Oss.cpp'
|
||||
])
|
||||
# MacOsX core
|
||||
myModule.add_optionnal_module_depend('CoreAudio', "ORCHESTRA_BUILD_MACOSX_CORE")
|
||||
elif target.name=="IOs":
|
||||
myModule.add_src_file('audio/orchestra/api/CoreIos.mm')
|
||||
# IOsX core
|
||||
myModule.add_optionnal_module_depend('CoreAudio', "ORCHESTRA_BUILD_IOS_CORE")
|
||||
elif target.name=="Android":
|
||||
myModule.add_src_file('audio/orchestra/api/Android.cpp')
|
||||
# specidic java interface for android:
|
||||
myModule.add_optionnal_module_depend('ewolAndroidAudio', "ORCHESTRA_BUILD_JAVA")
|
||||
#myModule.add_module_depend(['ewol'])
|
||||
else:
|
||||
debug.warning("unknow target for audio_orchestra : " + target.name);
|
||||
|
||||
myModule.add_export_path(tools.get_current_path(__file__))
|
||||
|
||||
# add the currrent module at the
|
||||
return myModule
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user