return RTAUDIO_VERSION;
}
-void RtAudio :: getCompiledApi( std::vector<RtAudio::Api> &apis )
-{
- apis.clear();
-
- // The order here will control the order of RtAudio's API search in
- // the constructor.
+// Define API names.
+// TODO: replace with initializer list in C++11.
+// The order here will control the order of RtAudio's API search in
+// the constructor.
+// Have to maintain a separate list of API enum identifiers since map
+// doesn't preserve insertion order.
+static std::pair< RtAudio::ApiNameMap, std::vector<RtAudio::Api> > init_ApiNames()
+{
+ RtAudio::ApiNameMap names;
+ std::vector<RtAudio::Api> apis;
#if defined(__UNIX_JACK__)
- apis.push_back( UNIX_JACK );
-#endif
-#if defined(__LINUX_ALSA__)
- apis.push_back( LINUX_ALSA );
+ names["jack"] = std::pair<RtAudio::Api, std::string>(RtAudio::UNIX_JACK, "Jack");
+ apis.push_back(RtAudio::UNIX_JACK);
#endif
#if defined(__LINUX_PULSE__)
- apis.push_back( LINUX_PULSE );
+ names["pulse"] = std::pair<RtAudio::Api, std::string>(RtAudio::LINUX_PULSE, "Pulse");
+ apis.push_back(RtAudio::LINUX_PULSE);
+#endif
+#if defined(__LINUX_ALSA__)
+ names["alsa"] = std::pair<RtAudio::Api, std::string>(RtAudio::LINUX_ALSA, "ALSA");
+ apis.push_back(RtAudio::LINUX_ALSA);
#endif
#if defined(__LINUX_OSS__)
- apis.push_back( LINUX_OSS );
+ names["oss"] = std::pair<RtAudio::Api, std::string>(RtAudio::LINUX_OSS, "OSS");
+ apis.push_back(RtAudio::LINUX_OSS);
#endif
#if defined(__WINDOWS_ASIO__)
- apis.push_back( WINDOWS_ASIO );
+ names["asio"] = std::pair<RtAudio::Api, std::string>(RtAudio::WINDOWS_ASIO, "ASIO");
+ apis.push_back(RtAudio::WINDOWS_ASIO);
#endif
#if defined(__WINDOWS_WASAPI__)
- apis.push_back( WINDOWS_WASAPI );
+ names["wasapi"] = std::pair<RtAudio::Api, std::string>(RtAudio::WINDOWS_WASAPI, "WASAPI");
+ apis.push_back(RtAudio::WINDOWS_WASAPI);
#endif
#if defined(__WINDOWS_DS__)
- apis.push_back( WINDOWS_DS );
+ names["ds"] = std::pair<RtAudio::Api, std::string>(RtAudio::WINDOWS_DS, "DirectSound");
+ apis.push_back(RtAudio::WINDOWS_DS);
#endif
#if defined(__MACOSX_CORE__)
- apis.push_back( MACOSX_CORE );
+ names["core"] = std::pair<RtAudio::Api, std::string>(RtAudio::MACOSX_CORE, "CoreAudio");
+ apis.push_back(RtAudio::MACOSX_CORE);
#endif
#if defined(__RTAUDIO_DUMMY__)
- apis.push_back( RTAUDIO_DUMMY );
+ names["dummy"] = std::pair<RtAudio::Api, std::string>(RtAudio::RTAUDIO_DUMMY, "Dummy");
+ apis.push_back(RtAudio::RTAUDIO_DUMMY);
#endif
+ return std::make_pair(names, apis);
+}
+
+const RtAudio::ApiNameMap RtAudio::apiNames(init_ApiNames().first);
+const std::vector<RtAudio::Api> RtAudio::compiledApis(init_ApiNames().second);
+
+void RtAudio :: getCompiledApi( std::vector<RtAudio::Api> &apis )
+{
+ apis = compiledApis;
+}
+
+const std::vector<RtAudio::Api>& RtAudio :: getCompiledApi()
+{
+ return compiledApis;
+}
+
+static const std::string unknown_api_name = "";
+static const std::string unknown_api_display_name = "Unknown";
+
+const std::string& RtAudio :: getCompiledApiName( RtAudio::Api api )
+{
+ ApiNameMap::const_iterator it;
+ for (it = apiNames.begin(); it != apiNames.end(); it++)
+ if (it->second.first == api)
+ return it->first;
+ return unknown_api_name;
+}
+
+const std::string& RtAudio :: getCompiledApiDisplayName( RtAudio::Api api )
+{
+ ApiNameMap::const_iterator it;
+ for (it = apiNames.begin(); it != apiNames.end(); it++)
+ if (it->second.first == api)
+ return it->second.second;
+ return unknown_api_display_name;
+}
+
+RtAudio::Api RtAudio :: getCompiledApiByName( const std::string &name )
+{
+ if (apiNames.find(name) == apiNames.end())
+ return RtAudio::UNSPECIFIED;
+ return apiNames.at(name).first;
}
void RtAudio :: openRtApi( RtAudio::Api api )
static int jackXrun( void *infoPointer )
{
- JackHandle *handle = (JackHandle *) infoPointer;
+ JackHandle *handle = *((JackHandle **) infoPointer);
if ( handle->ports[0] ) handle->xrun[0] = true;
if ( handle->ports[1] ) handle->xrun[1] = true;
else {
stream_.mode = mode;
jack_set_process_callback( handle->client, jackCallbackHandler, (void *) &stream_.callbackInfo );
- jack_set_xrun_callback( handle->client, jackXrun, (void *) &handle );
+ jack_set_xrun_callback( handle->client, jackXrun, (void *) &stream_.apiHandle );
jack_on_shutdown( handle->client, jackShutdown, (void *) &stream_.callbackInfo );
}
if ( sampleRate != deviceInfo.preferredSampleRate )
{
errorType = RtAudioError::INVALID_USE;
- std::stringstring ss;
+ std::stringstream ss;
ss << "RtApiWasapi::probeDeviceOpen: " << sampleRate
<< "Hz sample rate not supported. This device only supports "
<< deviceInfo.preferredSampleRate << "Hz.";
// Various revisions for RtAudio 4.0 by Gary Scavone, April 2007
// Changed device query structure for RtAudio 4.0.7, January 2010
+#include <windows.h>
+#include <process.h>
#include <mmsystem.h>
#include <mmreg.h>
#include <dsound.h>
pthread_attr_t attr;
pthread_attr_init( &attr );
pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE );
-
#ifdef SCHED_RR // Undefined with some OSes (eg: NetBSD 1.6.x with GNU Pthread)
if ( options && options->flags & RTAUDIO_SCHEDULE_REALTIME ) {
- // We previously attempted to increase the audio callback priority
- // to SCHED_RR here via the attributes. However, while no errors
- // were reported in doing so, it did not work. So, now this is
- // done in the alsaCallbackHandler function.
stream_.callbackInfo.doRealtime = true;
+ struct sched_param param;
int priority = options->priority;
int min = sched_get_priority_min( SCHED_RR );
int max = sched_get_priority_max( SCHED_RR );
if ( priority < min ) priority = min;
else if ( priority > max ) priority = max;
- stream_.callbackInfo.priority = priority;
+ param.sched_priority = priority;
+
+ // Set the policy BEFORE the priority. Otherwise it fails.
+ pthread_attr_setschedpolicy(&attr, SCHED_RR);
+ pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM);
+ // This is definitely required. Otherwise it fails.
+ pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
+ pthread_attr_setschedparam(&attr, ¶m);
}
+ else
+ pthread_attr_setschedpolicy( &attr, SCHED_OTHER );
+#else
+ pthread_attr_setschedpolicy( &attr, SCHED_OTHER );
#endif
stream_.callbackInfo.isRunning = true;
result = pthread_create( &stream_.callbackInfo.thread, &attr, alsaCallbackHandler, &stream_.callbackInfo );
pthread_attr_destroy( &attr );
if ( result ) {
- stream_.callbackInfo.isRunning = false;
- errorText_ = "RtApiAlsa::error creating callback thread!";
- goto error;
+ // Failed. Try instead with default attributes.
+ result = pthread_create( &stream_.callbackInfo.thread, NULL, alsaCallbackHandler, &stream_.callbackInfo );
+ if ( result ) {
+ stream_.callbackInfo.isRunning = false;
+ errorText_ = "RtApiAlsa::error creating callback thread!";
+ goto error;
+ }
}
}
#ifdef SCHED_RR // Undefined with some OSes (eg: NetBSD 1.6.x with GNU Pthread)
if ( info->doRealtime ) {
- pthread_t tID = pthread_self(); // ID of this thread
- sched_param prio = { info->priority }; // scheduling priority of thread
- pthread_setschedparam( tID, SCHED_RR, &prio );
+ std::cerr << "RtAudio alsa: " <<
+ (sched_getscheduler(0) == SCHED_RR ? "" : "_NOT_ ") <<
+ "running realtime scheduling" << std::endl;
}
#endif
CallbackInfo *cbi = static_cast<CallbackInfo *>( user );
RtApiPulse *context = static_cast<RtApiPulse *>( cbi->object );
volatile bool *isRunning = &cbi->isRunning;
-
+
+#ifdef SCHED_RR // Undefined with some OSes (eg: NetBSD 1.6.x with GNU Pthread)
+ if (cbi->doRealtime) {
+ std::cerr << "RtAudio pulse: " <<
+ (sched_getscheduler(0) == SCHED_RR ? "" : "_NOT_ ") <<
+ "running realtime scheduling" << std::endl;
+ }
+#endif
+
while ( *isRunning ) {
pthread_testcancel();
context->callbackEvent();
if ( !stream_.callbackInfo.isRunning ) {
stream_.callbackInfo.object = this;
+
+ stream_.state = STREAM_STOPPED;
+ // Set the thread attributes for joinable and realtime scheduling
+ // priority (optional). The higher priority will only take affect
+ // if the program is run as root or suid. Note, under Linux
+ // processes with CAP_SYS_NICE privilege, a user can change
+ // scheduling policy and priority (thus need not be root). See
+ // POSIX "capabilities".
+ pthread_attr_t attr;
+ pthread_attr_init( &attr );
+ pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE );
+#ifdef SCHED_RR // Undefined with some OSes (eg: NetBSD 1.6.x with GNU Pthread)
+ if ( options && options->flags & RTAUDIO_SCHEDULE_REALTIME ) {
+ stream_.callbackInfo.doRealtime = true;
+ struct sched_param param;
+ int priority = options->priority;
+ int min = sched_get_priority_min( SCHED_RR );
+ int max = sched_get_priority_max( SCHED_RR );
+ if ( priority < min ) priority = min;
+ else if ( priority > max ) priority = max;
+ param.sched_priority = priority;
+
+ // Set the policy BEFORE the priority. Otherwise it fails.
+ pthread_attr_setschedpolicy(&attr, SCHED_RR);
+ pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM);
+ // This is definitely required. Otherwise it fails.
+ pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
+ pthread_attr_setschedparam(&attr, ¶m);
+ }
+ else
+ pthread_attr_setschedpolicy( &attr, SCHED_OTHER );
+#else
+ pthread_attr_setschedpolicy( &attr, SCHED_OTHER );
+#endif
+
stream_.callbackInfo.isRunning = true;
- if ( pthread_create( &pah->thread, NULL, pulseaudio_callback, (void *)&stream_.callbackInfo) != 0 ) {
- errorText_ = "RtApiPulse::probeDeviceOpen: error creating thread.";
- goto error;
+ int result = pthread_create( &pah->thread, &attr, pulseaudio_callback, (void *)&stream_.callbackInfo);
+ pthread_attr_destroy(&attr);
+ if(result != 0) {
+ // Failed. Try instead with default attributes.
+ result = pthread_create( &pah->thread, NULL, pulseaudio_callback, (void *)&stream_.callbackInfo);
+ if(result != 0) {
+ stream_.callbackInfo.isRunning = false;
+ errorText_ = "RtApiPulse::probeDeviceOpen: error creating thread.";
+ goto error;
+ }
}
}
- stream_.state = STREAM_STOPPED;
- return true;
+ return SUCCESS;
error:
if ( pah && stream_.callbackInfo.isRunning ) {
stream_.deviceBuffer = 0;
}
+ stream_.state = STREAM_CLOSED;
return FAILURE;
}
pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE );
#ifdef SCHED_RR // Undefined with some OSes (eg: NetBSD 1.6.x with GNU Pthread)
if ( options && options->flags & RTAUDIO_SCHEDULE_REALTIME ) {
+ stream_.callbackInfo.doRealtime = true;
struct sched_param param;
int priority = options->priority;
int min = sched_get_priority_min( SCHED_RR );
if ( priority < min ) priority = min;
else if ( priority > max ) priority = max;
param.sched_priority = priority;
- pthread_attr_setschedparam( &attr, ¶m );
- pthread_attr_setschedpolicy( &attr, SCHED_RR );
+
+ // Set the policy BEFORE the priority. Otherwise it fails.
+ pthread_attr_setschedpolicy(&attr, SCHED_RR);
+ pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM);
+ // This is definitely required. Otherwise it fails.
+ pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
+ pthread_attr_setschedparam(&attr, ¶m);
}
else
pthread_attr_setschedpolicy( &attr, SCHED_OTHER );
result = pthread_create( &stream_.callbackInfo.thread, &attr, ossCallbackHandler, &stream_.callbackInfo );
pthread_attr_destroy( &attr );
if ( result ) {
- stream_.callbackInfo.isRunning = false;
- errorText_ = "RtApiOss::error creating callback thread!";
- goto error;
+ // Failed. Try instead with default attributes.
+ result = pthread_create( &stream_.callbackInfo.thread, NULL, ossCallbackHandler, &stream_.callbackInfo );
+ if ( result ) {
+ stream_.callbackInfo.isRunning = false;
+ errorText_ = "RtApiOss::error creating callback thread!";
+ goto error;
+ }
}
}
stream_.deviceBuffer = 0;
}
+ stream_.state = STREAM_CLOSED;
return FAILURE;
}
RtApiOss *object = (RtApiOss *) info->object;
bool *isRunning = &info->isRunning;
+#ifdef SCHED_RR // Undefined with some OSes (eg: NetBSD 1.6.x with GNU Pthread)
+ if (info->doRealtime) {
+ std::cerr << "RtAudio oss: " <<
+ (sched_getscheduler(0) == SCHED_RR ? "" : "_NOT_ ") <<
+ "running realtime scheduling" << std::endl;
+ }
+#endif
+
while ( *isRunning == true ) {
pthread_testcancel();
object->callbackEvent();