X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=RtAudio.cpp;h=b091e15782690a0324a29b2f6b91e90f4e8f20a4;hb=598a21f4114a4d49e4403215448ff4156778c616;hp=00d63f0c0a83dad2adada841be7fe9c2789a54fa;hpb=29167f363ed88727e28d3003fc0cd2e56a04a5ac;p=rtaudio-cdist.git diff --git a/RtAudio.cpp b/RtAudio.cpp index 00d63f0..b091e15 100644 --- a/RtAudio.cpp +++ b/RtAudio.cpp @@ -107,12 +107,12 @@ void RtAudio :: getCompiledApi( std::vector &apis ) #if defined(__UNIX_JACK__) apis.push_back( UNIX_JACK ); #endif -#if defined(__LINUX_ALSA__) - apis.push_back( LINUX_ALSA ); -#endif #if defined(__LINUX_PULSE__) apis.push_back( LINUX_PULSE ); #endif +#if defined(__LINUX_ALSA__) + apis.push_back( LINUX_ALSA ); +#endif #if defined(__LINUX_OSS__) apis.push_back( LINUX_OSS ); #endif @@ -1944,7 +1944,9 @@ struct JackHandle { :client(0), drainCounter(0), internalDrain(false) { ports[0] = 0; ports[1] = 0; xrun[0] = false; xrun[1] = false; } }; +#if !defined(__RTAUDIO_DEBUG__) static void jackSilentError( const char * ) {}; +#endif RtApiJack :: RtApiJack() :shouldAutoconnect_(true) { @@ -2128,7 +2130,7 @@ static void jackShutdown( void *infoPointer ) 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; @@ -2332,7 +2334,7 @@ bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne 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 ); } @@ -3689,6 +3691,7 @@ static const char* getAsioErrorString( ASIOError result ) #include #include #include +#include //============================================================================= @@ -3862,149 +3865,6 @@ private: //----------------------------------------------------------------------------- -// In order to satisfy WASAPI's buffer requirements, we need a means of converting sample rate -// between HW and the user. The convertBufferWasapi function is used to perform this conversion -// between HwIn->UserIn and UserOut->HwOut during the stream callback loop. -// This sample rate converter works best with conversions between one rate and its multiple. -void convertBufferWasapi( char* outBuffer, - const char* inBuffer, - const unsigned int& channelCount, - const unsigned int& inSampleRate, - const unsigned int& outSampleRate, - const unsigned int& inSampleCount, - unsigned int& outSampleCount, - const RtAudioFormat& format ) -{ - // calculate the new outSampleCount and relative sampleStep - float sampleRatio = ( float ) outSampleRate / inSampleRate; - float sampleRatioInv = ( float ) 1 / sampleRatio; - float sampleStep = 1.0f / sampleRatio; - float inSampleFraction = 0.0f; - - outSampleCount = ( unsigned int ) std::roundf( inSampleCount * sampleRatio ); - - // if inSampleRate is a multiple of outSampleRate (or vice versa) there's no need to interpolate - if ( floor( sampleRatio ) == sampleRatio || floor( sampleRatioInv ) == sampleRatioInv ) - { - // frame-by-frame, copy each relative input sample into it's corresponding output sample - for ( unsigned int outSample = 0; outSample < outSampleCount; outSample++ ) - { - unsigned int inSample = ( unsigned int ) inSampleFraction; - - switch ( format ) - { - case RTAUDIO_SINT8: - memcpy( &( ( char* ) outBuffer )[ outSample * channelCount ], &( ( char* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( char ) ); - break; - case RTAUDIO_SINT16: - memcpy( &( ( short* ) outBuffer )[ outSample * channelCount ], &( ( short* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( short ) ); - break; - case RTAUDIO_SINT24: - memcpy( &( ( S24* ) outBuffer )[ outSample * channelCount ], &( ( S24* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( S24 ) ); - break; - case RTAUDIO_SINT32: - memcpy( &( ( int* ) outBuffer )[ outSample * channelCount ], &( ( int* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( int ) ); - break; - case RTAUDIO_FLOAT32: - memcpy( &( ( float* ) outBuffer )[ outSample * channelCount ], &( ( float* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( float ) ); - break; - case RTAUDIO_FLOAT64: - memcpy( &( ( double* ) outBuffer )[ outSample * channelCount ], &( ( double* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( double ) ); - break; - } - - // jump to next in sample - inSampleFraction += sampleStep; - } - } - else // else interpolate - { - // frame-by-frame, copy each relative input sample into it's corresponding output sample - for ( unsigned int outSample = 0; outSample < outSampleCount; outSample++ ) - { - unsigned int inSample = ( unsigned int ) inSampleFraction; - float inSampleDec = inSampleFraction - inSample; - unsigned int frameInSample = inSample * channelCount; - unsigned int frameOutSample = outSample * channelCount; - - switch ( format ) - { - case RTAUDIO_SINT8: - { - for ( unsigned int channel = 0; channel < channelCount; channel++ ) - { - char fromSample = ( ( char* ) inBuffer )[ frameInSample + channel ]; - char toSample = ( ( char* ) inBuffer )[ frameInSample + channelCount + channel ]; - char sampleDiff = ( char ) ( ( toSample - fromSample ) * inSampleDec ); - ( ( char* ) outBuffer )[ frameOutSample + channel ] = fromSample + sampleDiff; - } - break; - } - case RTAUDIO_SINT16: - { - for ( unsigned int channel = 0; channel < channelCount; channel++ ) - { - short fromSample = ( ( short* ) inBuffer )[ frameInSample + channel ]; - short toSample = ( ( short* ) inBuffer )[ frameInSample + channelCount + channel ]; - short sampleDiff = ( short ) ( ( toSample - fromSample ) * inSampleDec ); - ( ( short* ) outBuffer )[ frameOutSample + channel ] = fromSample + sampleDiff; - } - break; - } - case RTAUDIO_SINT24: - { - for ( unsigned int channel = 0; channel < channelCount; channel++ ) - { - int fromSample = ( ( S24* ) inBuffer )[ frameInSample + channel ].asInt(); - int toSample = ( ( S24* ) inBuffer )[ frameInSample + channelCount + channel ].asInt(); - int sampleDiff = ( int ) ( ( toSample - fromSample ) * inSampleDec ); - ( ( S24* ) outBuffer )[ frameOutSample + channel ] = fromSample + sampleDiff; - } - break; - } - case RTAUDIO_SINT32: - { - for ( unsigned int channel = 0; channel < channelCount; channel++ ) - { - int fromSample = ( ( int* ) inBuffer )[ frameInSample + channel ]; - int toSample = ( ( int* ) inBuffer )[ frameInSample + channelCount + channel ]; - int sampleDiff = ( int ) ( ( toSample - fromSample ) * inSampleDec ); - ( ( int* ) outBuffer )[ frameOutSample + channel ] = fromSample + sampleDiff; - } - break; - } - case RTAUDIO_FLOAT32: - { - for ( unsigned int channel = 0; channel < channelCount; channel++ ) - { - float fromSample = ( ( float* ) inBuffer )[ frameInSample + channel ]; - float toSample = ( ( float* ) inBuffer )[ frameInSample + channelCount + channel ]; - float sampleDiff = ( toSample - fromSample ) * inSampleDec; - ( ( float* ) outBuffer )[ frameOutSample + channel ] = fromSample + sampleDiff; - } - break; - } - case RTAUDIO_FLOAT64: - { - for ( unsigned int channel = 0; channel < channelCount; channel++ ) - { - double fromSample = ( ( double* ) inBuffer )[ frameInSample + channel ]; - double toSample = ( ( double* ) inBuffer )[ frameInSample + channelCount + channel ]; - double sampleDiff = ( toSample - fromSample ) * inSampleDec; - ( ( double* ) outBuffer )[ frameOutSample + channel ] = fromSample + sampleDiff; - } - break; - } - } - - // jump to next in sample - inSampleFraction += sampleStep; - } - } -} - -//----------------------------------------------------------------------------- - // A structure to hold various information related to the WASAPI implementation. struct WasapiHandle { @@ -4270,15 +4130,12 @@ RtAudio::DeviceInfo RtApiWasapi::getDeviceInfo( unsigned int device ) info.duplexChannels = 0; } - // sample rates - info.sampleRates.clear(); - - // allow support for all sample rates as we have a built-in sample rate converter - for ( unsigned int i = 0; i < MAX_SAMPLE_RATES; i++ ) { - info.sampleRates.push_back( SAMPLE_RATES[i] ); - } + // sample rates (WASAPI only supports the one native sample rate) info.preferredSampleRate = deviceFormat->nSamplesPerSec; + info.sampleRates.clear(); + info.sampleRates.push_back( deviceFormat->nSamplesPerSec ); + // native format info.nativeFormats = 0; @@ -4554,6 +4411,7 @@ bool RtApiWasapi::probeDeviceOpen( unsigned int device, StreamMode mode, unsigne WAVEFORMATEX* deviceFormat = NULL; unsigned int bufferBytes; stream_.state = STREAM_STOPPED; + RtAudio::DeviceInfo deviceInfo; // create API Handle if not already created if ( !stream_.apiHandle ) @@ -4594,6 +4452,20 @@ bool RtApiWasapi::probeDeviceOpen( unsigned int device, StreamMode mode, unsigne goto Exit; } + deviceInfo = getDeviceInfo( device ); + + // validate sample rate + if ( sampleRate != deviceInfo.preferredSampleRate ) + { + errorType = RtAudioError::INVALID_USE; + std::stringstream ss; + ss << "RtApiWasapi::probeDeviceOpen: " << sampleRate + << "Hz sample rate not supported. This device only supports " + << deviceInfo.preferredSampleRate << "Hz."; + errorText_ = ss.str(); + goto Exit; + } + // determine whether index falls within capture or render devices if ( device >= renderDeviceCount ) { if ( mode != INPUT ) { @@ -4677,7 +4549,7 @@ bool RtApiWasapi::probeDeviceOpen( unsigned int device, StreamMode mode, unsigne stream_.nUserChannels[mode] = channels; stream_.channelOffset[mode] = firstChannel; stream_.userFormat = format; - stream_.deviceFormat[mode] = getDeviceInfo( device ).nativeFormats; + stream_.deviceFormat[mode] = deviceInfo.nativeFormats; if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) stream_.userInterleaved = false; @@ -4777,8 +4649,6 @@ void RtApiWasapi::wasapiThread() WAVEFORMATEX* captureFormat = NULL; WAVEFORMATEX* renderFormat = NULL; - float captureSrRatio = 0.0f; - float renderSrRatio = 0.0f; WasapiBuffer captureBuffer; WasapiBuffer renderBuffer; @@ -4788,15 +4658,11 @@ void RtApiWasapi::wasapiThread() unsigned long captureFlags = 0; unsigned int bufferFrameCount = 0; unsigned int numFramesPadding = 0; - unsigned int convBufferSize = 0; bool callbackPushed = false; bool callbackPulled = false; bool callbackStopped = false; int callbackResult = 0; - // convBuffer is used to store converted buffers between WASAPI and the user - char* convBuffer = NULL; - unsigned int convBuffSize = 0; unsigned int deviceBuffSize = 0; errorText_.clear(); @@ -4819,11 +4685,8 @@ void RtApiWasapi::wasapiThread() goto Exit; } - captureSrRatio = ( ( float ) captureFormat->nSamplesPerSec / stream_.sampleRate ); - // initialize capture stream according to desire buffer size - float desiredBufferSize = stream_.bufferSize * captureSrRatio; - REFERENCE_TIME desiredBufferPeriod = ( REFERENCE_TIME ) ( ( float ) desiredBufferSize * 10000000 / captureFormat->nSamplesPerSec ); + REFERENCE_TIME desiredBufferPeriod = ( REFERENCE_TIME ) ( ( float ) stream_.bufferSize * 10000000 / captureFormat->nSamplesPerSec ); if ( !captureClient ) { hr = captureAudioClient->Initialize( AUDCLNT_SHAREMODE_SHARED, @@ -4870,7 +4733,7 @@ void RtApiWasapi::wasapiThread() } // scale outBufferSize according to stream->user sample rate ratio - unsigned int outBufferSize = ( unsigned int ) ( stream_.bufferSize * captureSrRatio ) * stream_.nDeviceChannels[INPUT]; + unsigned int outBufferSize = ( unsigned int ) stream_.bufferSize * stream_.nDeviceChannels[INPUT]; inBufferSize *= stream_.nDeviceChannels[INPUT]; // set captureBuffer size @@ -4899,11 +4762,8 @@ void RtApiWasapi::wasapiThread() goto Exit; } - renderSrRatio = ( ( float ) renderFormat->nSamplesPerSec / stream_.sampleRate ); - // initialize render stream according to desire buffer size - float desiredBufferSize = stream_.bufferSize * renderSrRatio; - REFERENCE_TIME desiredBufferPeriod = ( REFERENCE_TIME ) ( ( float ) desiredBufferSize * 10000000 / renderFormat->nSamplesPerSec ); + REFERENCE_TIME desiredBufferPeriod = ( REFERENCE_TIME ) ( ( float ) stream_.bufferSize * 10000000 / renderFormat->nSamplesPerSec ); if ( !renderClient ) { hr = renderAudioClient->Initialize( AUDCLNT_SHAREMODE_SHARED, @@ -4950,7 +4810,7 @@ void RtApiWasapi::wasapiThread() } // scale inBufferSize according to user->stream sample rate ratio - unsigned int inBufferSize = ( unsigned int ) ( stream_.bufferSize * renderSrRatio ) * stream_.nDeviceChannels[OUTPUT]; + unsigned int inBufferSize = ( unsigned int ) stream_.bufferSize * stream_.nDeviceChannels[OUTPUT]; outBufferSize *= stream_.nDeviceChannels[OUTPUT]; // set renderBuffer size @@ -4972,23 +4832,19 @@ void RtApiWasapi::wasapiThread() } if ( stream_.mode == INPUT ) { - convBuffSize = ( size_t ) ( stream_.bufferSize * captureSrRatio ) * stream_.nDeviceChannels[INPUT] * formatBytes( stream_.deviceFormat[INPUT] ); + using namespace std; // for roundf deviceBuffSize = stream_.bufferSize * stream_.nDeviceChannels[INPUT] * formatBytes( stream_.deviceFormat[INPUT] ); } else if ( stream_.mode == OUTPUT ) { - convBuffSize = ( size_t ) ( stream_.bufferSize * renderSrRatio ) * stream_.nDeviceChannels[OUTPUT] * formatBytes( stream_.deviceFormat[OUTPUT] ); deviceBuffSize = stream_.bufferSize * stream_.nDeviceChannels[OUTPUT] * formatBytes( stream_.deviceFormat[OUTPUT] ); } else if ( stream_.mode == DUPLEX ) { - convBuffSize = std::max( ( size_t ) ( stream_.bufferSize * captureSrRatio ) * stream_.nDeviceChannels[INPUT] * formatBytes( stream_.deviceFormat[INPUT] ), - ( size_t ) ( stream_.bufferSize * renderSrRatio ) * stream_.nDeviceChannels[OUTPUT] * formatBytes( stream_.deviceFormat[OUTPUT] ) ); deviceBuffSize = std::max( stream_.bufferSize * stream_.nDeviceChannels[INPUT] * formatBytes( stream_.deviceFormat[INPUT] ), stream_.bufferSize * stream_.nDeviceChannels[OUTPUT] * formatBytes( stream_.deviceFormat[OUTPUT] ) ); } - convBuffer = ( char* ) malloc( convBuffSize ); stream_.deviceBuffer = ( char* ) malloc( deviceBuffSize ); - if ( !convBuffer || !stream_.deviceBuffer ) { + if ( !stream_.deviceBuffer ) { errorType = RtAudioError::MEMORY_ERROR; errorText_ = "RtApiWasapi::wasapiThread: Error allocating device buffer memory."; goto Exit; @@ -5000,26 +4856,15 @@ void RtApiWasapi::wasapiThread() // Callback Input // ============== // 1. Pull callback buffer from inputBuffer - // 2. If 1. was successful: Convert callback buffer to user sample rate and channel count - // Convert callback buffer to user format + // 2. If 1. was successful: Convert callback buffer to user format if ( captureAudioClient ) { // Pull callback buffer from inputBuffer - callbackPulled = captureBuffer.pullBuffer( convBuffer, - ( unsigned int ) ( stream_.bufferSize * captureSrRatio ) * stream_.nDeviceChannels[INPUT], + callbackPulled = captureBuffer.pullBuffer( stream_.deviceBuffer, + ( unsigned int ) stream_.bufferSize * stream_.nDeviceChannels[INPUT], stream_.deviceFormat[INPUT] ); if ( callbackPulled ) { - // Convert callback buffer to user sample rate - convertBufferWasapi( stream_.deviceBuffer, - convBuffer, - stream_.nDeviceChannels[INPUT], - captureFormat->nSamplesPerSec, - stream_.sampleRate, - ( unsigned int ) ( stream_.bufferSize * captureSrRatio ), - convBufferSize, - stream_.deviceFormat[INPUT] ); - if ( stream_.doConvertBuffer[INPUT] ) { // Convert callback buffer to user format convertBuffer( stream_.userBuffer[INPUT], @@ -5093,8 +4938,7 @@ void RtApiWasapi::wasapiThread() // Callback Output // =============== // 1. Convert callback buffer to stream format - // 2. Convert callback buffer to stream sample rate and channel count - // 3. Push callback buffer into outputBuffer + // 2. Push callback buffer into outputBuffer if ( renderAudioClient && callbackPulled ) { if ( stream_.doConvertBuffer[OUTPUT] ) { @@ -5105,19 +4949,9 @@ void RtApiWasapi::wasapiThread() } - // Convert callback buffer to stream sample rate - convertBufferWasapi( convBuffer, - stream_.deviceBuffer, - stream_.nDeviceChannels[OUTPUT], - stream_.sampleRate, - renderFormat->nSamplesPerSec, - stream_.bufferSize, - convBufferSize, - stream_.deviceFormat[OUTPUT] ); - // Push callback buffer into outputBuffer - callbackPushed = renderBuffer.pushBuffer( convBuffer, - convBufferSize * stream_.nDeviceChannels[OUTPUT], + callbackPushed = renderBuffer.pushBuffer( stream_.deviceBuffer, + stream_.bufferSize * stream_.nDeviceChannels[OUTPUT], stream_.deviceFormat[OUTPUT] ); } else { @@ -5263,8 +5097,6 @@ Exit: CoTaskMemFree( captureFormat ); CoTaskMemFree( renderFormat ); - free ( convBuffer ); - CoUninitialize(); // update stream state @@ -7728,30 +7560,41 @@ bool RtApiAlsa :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne 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; + } } } @@ -8168,9 +8011,9 @@ static void *alsaCallbackHandler( void *ptr ) #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 @@ -8253,7 +8096,15 @@ static void *pulseaudio_callback( void * user ) CallbackInfo *cbi = static_cast( user ); RtApiPulse *context = static_cast( 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(); @@ -8638,15 +8489,56 @@ bool RtApiPulse::probeDeviceOpen( unsigned int device, StreamMode mode, 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 ) { @@ -8667,6 +8559,7 @@ bool RtApiPulse::probeDeviceOpen( unsigned int device, StreamMode mode, stream_.deviceBuffer = 0; } + stream_.state = STREAM_CLOSED; return FAILURE; } @@ -9230,6 +9123,7 @@ bool RtApiOss :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned 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 ); @@ -9237,8 +9131,13 @@ bool RtApiOss :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned 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 ); @@ -9250,9 +9149,13 @@ bool RtApiOss :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned 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; + } } } @@ -9279,6 +9182,7 @@ bool RtApiOss :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned stream_.deviceBuffer = 0; } + stream_.state = STREAM_CLOSED; return FAILURE; } @@ -9608,6 +9512,14 @@ static void *ossCallbackHandler( void *ptr ) 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();