[DEV] rework Airtaudio in audioo::orchestra

This commit is contained in:
Edouard DUPIN 2015-04-10 22:06:17 +02:00
parent d4c53a53bf
commit f5c3affccb
72 changed files with 2805 additions and 2732 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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];
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
View 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

View File

@ -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 << ", ";

View 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

View File

@ -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
View 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

View 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
View 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

View 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];
}
}

View 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

View 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

View File

@ -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;
}

View 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

View File

@ -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);
}

View 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

View File

@ -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!!!");

View 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

View File

@ -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";

View 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

View 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

View File

@ -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;
}

View File

@ -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(&currentWritePointer, &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
View 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

View 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

View 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

View File

@ -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;
}

View 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

View File

@ -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
View 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

View File

@ -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++) {

View 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

View File

@ -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

View File

@ -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;
}

View File

@ -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)

View File

@ -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
View 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

View File

@ -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
View 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
View 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

View File

@ -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
View 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

View File

@ -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
View 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

View File

@ -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
View 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