then = stream_.lastTickTimestamp;\r
return stream_.streamTime +\r
((now.tv_sec + 0.000001 * now.tv_usec) -\r
- (then.tv_sec + 0.000001 * then.tv_usec)); \r
+ (then.tv_sec + 0.000001 * then.tv_usec));\r
#else\r
return stream_.streamTime;\r
#endif\r
channelsLeft -= streamChannels;\r
}\r
}\r
- \r
+\r
if ( stream_.doConvertBuffer[1] ) { // convert from our internal "device" buffer\r
convertBuffer( stream_.userBuffer[1],\r
stream_.deviceBuffer,\r
// CoInitialize beforehand, but it must be for appartment threading\r
// (in which case, CoInitilialize will return S_FALSE here).\r
coInitialized_ = false;\r
- HRESULT hr = CoInitialize( NULL ); \r
+ HRESULT hr = CoInitialize( NULL );\r
if ( FAILED(hr) ) {\r
errorText_ = "RtApiAsio::ASIO requires a single-threaded appartment. Call CoInitializeEx(0,COINIT_APARTMENTTHREADED)";\r
error( RtAudioError::WARNING );\r
errorText_ = errorStream_.str();\r
goto error;\r
}\r
- buffersAllocated = true; \r
+ buffersAllocated = true;\r
stream_.state = STREAM_STOPPED;\r
\r
// Set flags for buffer conversion.\r
\r
static const char* getAsioErrorString( ASIOError result )\r
{\r
- struct Messages \r
+ struct Messages\r
{\r
ASIOError value;\r
const char*message;\r
};\r
\r
- static const Messages m[] = \r
+ static const Messages m[] =\r
{\r
{ ASE_NotPresent, "Hardware input or output is not present or available." },\r
{ ASE_HWMalfunction, "Hardware is malfunctioning." },\r
{\r
verifyStream();\r
RtApi::startStream();\r
- \r
+\r
if ( stream_.state == STREAM_RUNNING ) {\r
errorText_ = "RtApiWasapi::startStream: The stream is already running.";\r
error( RtAudioError::WARNING );\r
#if defined(__WINDOWS_DS__) // Windows DirectSound API\r
\r
// Modified by Robin Davies, October 2005\r
-// - Improvements to DirectX pointer chasing. \r
+// - Improvements to DirectX pointer chasing.\r
// - Bug fix for non-power-of-two Asio granularity used by Edirol PCR-A30.\r
// - Auto-call CoInitialize for DSOUND and ASIO platforms.\r
// Various revisions for RtAudio 4.0 by Gary Scavone, April 2007\r
void *id[2];\r
void *buffer[2];\r
bool xrun[2];\r
- UINT bufferPointer[2]; \r
+ UINT bufferPointer[2];\r
DWORD dsBufferSize[2];\r
DWORD dsPointerLeadTime[2]; // the number of bytes ahead of the safe pointer to lead by.\r
HANDLE condition;\r
{\r
verifyStream();\r
RtApi::startStream();\r
- \r
+\r
if ( stream_.state == STREAM_RUNNING ) {\r
errorText_ = "RtApiDs::startStream(): the stream is already running!";\r
error( RtAudioError::WARNING );\r
// Increase scheduler frequency on lesser windows (a side-effect of\r
// increasing timer accuracy). On greater windows (Win2K or later),\r
// this is already in effect.\r
- timeBeginPeriod( 1 ); \r
+ timeBeginPeriod( 1 );\r
\r
buffersRolling = false;\r
duplexPrerollBytes = 0;\r
}\r
\r
if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {\r
- \r
+\r
LPDIRECTSOUNDBUFFER dsBuffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];\r
\r
if ( handle->drainCounter > 1 ) { // write zeros to the output stream\r
}\r
\r
if ( dsPointerBetween( nextWritePointer, safeWritePointer, currentWritePointer, dsBufferSize )\r
- || dsPointerBetween( endWrite, safeWritePointer, currentWritePointer, dsBufferSize ) ) { \r
+ || dsPointerBetween( endWrite, safeWritePointer, currentWritePointer, dsBufferSize ) ) {\r
// We've strayed into the forbidden zone ... resync the read pointer.\r
handle->xrun[0] = true;\r
nextWritePointer = safeWritePointer + handle->dsPointerLeadTime[0] - bufferBytes;\r
if ( safeReadPointer < (DWORD)nextReadPointer ) safeReadPointer += dsBufferSize; // unwrap offset\r
DWORD endRead = nextReadPointer + bufferBytes;\r
\r
- // Handling depends on whether we are INPUT or DUPLEX. \r
+ // Handling depends on whether we are INPUT or DUPLEX.\r
// If we're in INPUT mode then waiting is a good thing. If we're in DUPLEX mode,\r
// then a wait here will drag the write pointers into the forbidden zone.\r
- // \r
- // In DUPLEX mode, rather than wait, we will back off the read pointer until \r
- // it's in a safe position. This causes dropouts, but it seems to be the only \r
- // practical way to sync up the read and write pointers reliably, given the \r
- // the very complex relationship between phase and increment of the read and write \r
+ //\r
+ // In DUPLEX mode, rather than wait, we will back off the read pointer until\r
+ // it's in a safe position. This causes dropouts, but it seems to be the only\r
+ // practical way to sync up the read and write pointers reliably, given the\r
+ // the very complex relationship between phase and increment of the read and write\r
// pointers.\r
//\r
// In order to minimize audible dropouts in DUPLEX mode, we will\r
error( RtAudioError::SYSTEM_ERROR );\r
return;\r
}\r
- \r
+\r
if ( safeReadPointer < (DWORD)nextReadPointer ) safeReadPointer += dsBufferSize; // unwrap offset\r
}\r
}\r
AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;\r
snd_pcm_t **handle = (snd_pcm_t **) apiInfo->handles;\r
if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {\r
- if ( apiInfo->synchronized ) \r
+ if ( apiInfo->synchronized )\r
result = snd_pcm_drop( handle[0] );\r
else\r
result = snd_pcm_drain( handle[0] );\r
\r
#include <pulse/error.h>\r
#include <pulse/simple.h>\r
+#include <pulse/pulseaudio.h>\r
#include <cstdio>\r
\r
static const unsigned int SUPPORTED_SAMPLERATES[] = { 8000, 16000, 22050, 32000,\r
return 1;\r
}\r
\r
+void RtApiPulse::sinkInfoCallback(pa_context*, const pa_sink_info* info, int, void* arg)\r
+{\r
+ RtApiPulse* api = (RtApiPulse *) arg;\r
+ if (info) {\r
+ api->channels_ = info->sample_spec.channels;\r
+ }\r
+ pa_threaded_mainloop_signal(api->mainloop_, 0);\r
+}\r
+\r
+void RtApiPulse::contextStateCallback(pa_context* c, void* arg)\r
+{\r
+ pa_threaded_mainloop* mainloop = (pa_threaded_mainloop*) arg;\r
+\r
+ switch (pa_context_get_state(c)) {\r
+ case PA_CONTEXT_READY:\r
+ case PA_CONTEXT_TERMINATED:\r
+ case PA_CONTEXT_FAILED:\r
+ pa_threaded_mainloop_signal(mainloop, 0);\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+}\r
+\r
RtAudio::DeviceInfo RtApiPulse::getDeviceInfo( unsigned int /*device*/ )\r
{\r
+ /* Set up some defaults in case we crash and burn */\r
RtAudio::DeviceInfo info;\r
info.probed = true;\r
info.name = "PulseAudio";\r
info.preferredSampleRate = 48000;\r
info.nativeFormats = RTAUDIO_SINT16 | RTAUDIO_SINT32 | RTAUDIO_FLOAT32;\r
\r
+ /* Get the number of output channels from pulseaudio. A simple task, you say?\r
+ "What is your mainloop?" */\r
+ mainloop_ = pa_threaded_mainloop_new();\r
+ if (!mainloop_) {\r
+ return info;\r
+ }\r
+\r
+ pa_threaded_mainloop_start(mainloop_);\r
+ pa_threaded_mainloop_lock(mainloop_);\r
+\r
+ /* "And what is your context?" */\r
+ pa_context* context = pa_context_new(pa_threaded_mainloop_get_api(mainloop_), "RtAudio");\r
+ if (!context) {\r
+ pa_threaded_mainloop_unlock(mainloop_);\r
+ pa_threaded_mainloop_stop(mainloop_);\r
+ pa_threaded_mainloop_free(mainloop_);\r
+ mainloop_ = 0;\r
+ return info;\r
+ }\r
+\r
+ pa_context_set_state_callback(context, contextStateCallback, mainloop_);\r
+\r
+ pa_context_connect(context, 0, (pa_context_flags_t) 0, 0);\r
+\r
+ /* "And what is your favourite colour?" */\r
+ int connected = 0;\r
+ pa_context_state_t state = pa_context_get_state(context);\r
+ for (; !connected; state = pa_context_get_state(context)) {\r
+ switch (state) {\r
+ case PA_CONTEXT_READY:\r
+ connected = 1;\r
+ continue;\r
+ case PA_CONTEXT_FAILED:\r
+ case PA_CONTEXT_TERMINATED:\r
+ /* Blue! No, I mean red! */\r
+ pa_threaded_mainloop_unlock(mainloop_);\r
+ pa_context_disconnect(context);\r
+ pa_context_unref(context);\r
+ pa_threaded_mainloop_stop(mainloop_);\r
+ pa_threaded_mainloop_free(mainloop_);\r
+ mainloop_ = 0;\r
+ return info;\r
+ default:\r
+ pa_threaded_mainloop_wait(mainloop_);\r
+ break;\r
+ }\r
+ }\r
+\r
+ pa_operation* op = pa_context_get_sink_info_by_index(context, 0, sinkInfoCallback, this);\r
+\r
+ if (op) {\r
+ pa_operation_unref(op);\r
+ }\r
+\r
+ pa_threaded_mainloop_wait(mainloop_);\r
+ pa_threaded_mainloop_unlock(mainloop_);\r
+\r
+ pa_context_disconnect(context);\r
+ pa_context_unref(context);\r
+\r
+ pa_threaded_mainloop_stop(mainloop_);\r
+ pa_threaded_mainloop_free(mainloop_);\r
+ mainloop_ = 0;\r
+\r
+ info.outputChannels = channels_;\r
+\r
return info;\r
}\r
\r
else\r
bytes = stream_.nUserChannels[INPUT] * stream_.bufferSize *\r
formatBytes( stream_.userFormat );\r
- \r
+\r
if ( pa_simple_read( pah->s_rec, pulse_in, bytes, &pa_error ) < 0 ) {\r
errorStream_ << "RtApiPulse::callbackEvent: audio read error, " <<\r
pa_strerror( pa_error ) << ".";\r
void RtApiPulse::startStream( void )\r
{\r
RtApi::startStream();\r
- \r
+\r
PulseAudioHandle *pah = static_cast<PulseAudioHandle *>( stream_.apiHandle );\r
\r
if ( stream_.state == STREAM_CLOSED ) {\r
\r
if ( device != 0 ) return false;\r
if ( mode != INPUT && mode != OUTPUT ) return false;\r
- if ( channels != 1 && channels != 2 ) {\r
- errorText_ = "RtApiPulse::probeDeviceOpen: unsupported number of channels.";\r
- return false;\r
- }\r
ss.channels = channels;\r
\r
if ( firstChannel != 0 ) return false;\r
\r
stream_.state = STREAM_STOPPED;\r
return true;\r
- \r
+\r
error:\r
if ( pah && stream_.callbackInfo.isRunning ) {\r
pthread_cond_destroy( &pah->runnable_cv );\r
// End:\r
//\r
// vim: et sts=2 sw=2\r
-\r
open the input and/or output stream device(s) for exclusive use.
Note that this is not possible with all supported audio APIs.
- If the RTAUDIO_SCHEDULE_REALTIME flag is set, RtAudio will attempt
+ If the RTAUDIO_SCHEDULE_REALTIME flag is set, RtAudio will attempt
to select realtime scheduling (round-robin) for the callback thread.
If the RTAUDIO_ALSA_USE_DEFAULT flag is set, RtAudio will attempt to
//! The constructor.
RtAudioError( const std::string& message, Type type = RtAudioError::UNSPECIFIED ) throw() : message_(message), type_(type) {}
-
+
//! The destructor.
virtual ~RtAudioError( void ) throw() {}
open the input and/or output stream device(s) for exclusive use.
Note that this is not possible with all supported audio APIs.
- If the RTAUDIO_SCHEDULE_REALTIME flag is set, RtAudio will attempt
+ If the RTAUDIO_SCHEDULE_REALTIME flag is set, RtAudio will attempt
to select realtime scheduling (round-robin) for the callback thread.
The \c priority parameter will only be used if the RTAUDIO_SCHEDULE_REALTIME
flag is set. It defines the thread's realtime priority.
/*!
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.
+ a system error occurs during processing, a warning will be issued.
*/
unsigned int getDeviceCount( void ) throw();
from within the callback function.
\param options An optional pointer to a structure containing various
global stream options, including a list of OR'ed RtAudioStreamFlags
- and a suggested number of stream buffers that can be used to
+ 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
"warning" message is reported and FAILURE is returned. A
successful probe is indicated by a return value of SUCCESS.
*/
- virtual bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
+ virtual bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
unsigned int firstChannel, unsigned int sampleRate,
RtAudioFormat format, unsigned int *bufferSize,
RtAudio::StreamOptions *options );
private:
- bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
+ bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
unsigned int firstChannel, unsigned int sampleRate,
RtAudioFormat format, unsigned int *bufferSize,
RtAudio::StreamOptions *options );
private:
- bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
+ bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
unsigned int firstChannel, unsigned int sampleRate,
RtAudioFormat format, unsigned int *bufferSize,
RtAudio::StreamOptions *options );
std::vector<RtAudio::DeviceInfo> devices_;
void saveDeviceInfo( void );
bool coInitialized_;
- bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
+ bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
unsigned int firstChannel, unsigned int sampleRate,
RtAudioFormat format, unsigned int *bufferSize,
RtAudio::StreamOptions *options );
bool buffersRolling;
long duplexPrerollBytes;
std::vector<struct DsDevice> dsDevices;
- bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
+ bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
unsigned int firstChannel, unsigned int sampleRate,
RtAudioFormat format, unsigned int *bufferSize,
RtAudio::StreamOptions *options );
std::vector<RtAudio::DeviceInfo> devices_;
void saveDeviceInfo( void );
- bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
+ bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
unsigned int firstChannel, unsigned int sampleRate,
RtAudioFormat format, unsigned int *bufferSize,
RtAudio::StreamOptions *options );
#if defined(__LINUX_PULSE__)
+struct pa_context;
+struct pa_sink_info;
+struct pa_threaded_mainloop;
+
class RtApiPulse: public RtApi
{
public:
+ RtApiPulse() : mainloop_(0), channels_(2) {}
~RtApiPulse();
RtAudio::Api getCurrentApi() { return RtAudio::LINUX_PULSE; }
unsigned int getDeviceCount( void );
unsigned int firstChannel, unsigned int sampleRate,
RtAudioFormat format, unsigned int *bufferSize,
RtAudio::StreamOptions *options );
+
+ static void sinkInfoCallback(pa_context* c, const pa_sink_info* info, int eol, void* arg);
+ static void contextStateCallback(pa_context* c, void* arg);
+ pa_threaded_mainloop* mainloop_;
+ int channels_;
};
#endif
private:
- bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
+ bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
unsigned int firstChannel, unsigned int sampleRate,
RtAudioFormat format, unsigned int *bufferSize,
RtAudio::StreamOptions *options );
private:
- bool probeDeviceOpen( unsigned int /*device*/, StreamMode /*mode*/, unsigned int /*channels*/,
+ bool probeDeviceOpen( unsigned int /*device*/, StreamMode /*mode*/, unsigned int /*channels*/,
unsigned int /*firstChannel*/, unsigned int /*sampleRate*/,
RtAudioFormat /*format*/, unsigned int * /*bufferSize*/,
RtAudio::StreamOptions * /*options*/ ) { return false; }