*/\r
/************************************************************************/\r
\r
-// RtAudio: Version 4.0.8\r
+// RtAudio: Version 4.0.9\r
\r
#include "RtAudio.h"\r
#include <iostream>\r
// quite a bit of extra code and most likely, a user program wouldn't\r
// be prepared for the result anyway. However, we do provide a flag\r
// to the client callback function to inform of an over/underrun.\r
-//\r
-// The mechanism for querying and setting system parameters was\r
-// updated (and perhaps simplified) in OS-X version 10.4. However,\r
-// since 10.4 support is not necessarily available to all users, I've\r
-// decided not to update the respective code at this time. Perhaps\r
-// this will happen when Apple makes 10.4 free for everyone. :-)\r
\r
// A structure to hold various information related to the CoreAudio API\r
// implementation.\r
:deviceBuffer(0), drainCounter(0), internalDrain(false) { nStreams[0] = 1; nStreams[1] = 1; id[0] = 0; id[1] = 0; xrun[0] = false; xrun[1] = false; }\r
};\r
\r
-RtApiCore :: RtApiCore()\r
+RtApiCore:: RtApiCore()\r
{\r
- // Nothing to do here.\r
+#if defined( AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER )\r
+ // This is a largely undocumented but absolutely necessary\r
+ // requirement starting with OS-X 10.6. If not called, queries and\r
+ // updates to various audio device properties are not handled\r
+ // correctly.\r
+ CFRunLoopRef theRunLoop = NULL;\r
+ AudioObjectPropertyAddress property = { kAudioHardwarePropertyRunLoop,\r
+ kAudioObjectPropertyScopeGlobal,\r
+ kAudioObjectPropertyElementMaster };\r
+ OSStatus result = AudioObjectSetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, sizeof(CFRunLoopRef), &theRunLoop);\r
+ if ( result != noErr ) {\r
+ errorText_ = "RtApiCore::RtApiCore: error setting run loop property!";\r
+ error( RtError::WARNING );\r
+ }\r
+#endif\r
}\r
\r
RtApiCore :: ~RtApiCore()\r
return kAudioHardwareNoError;\r
}\r
\r
-OSStatus deviceListener( AudioObjectID inDevice,\r
+OSStatus xrunListener( AudioObjectID inDevice,\r
UInt32 nAddresses,\r
const AudioObjectPropertyAddress properties[],\r
void* handlePointer )\r
return kAudioHardwareNoError;\r
}\r
\r
+OSStatus rateListener( AudioObjectID inDevice,\r
+ UInt32 nAddresses,\r
+ const AudioObjectPropertyAddress properties[],\r
+ void* ratePointer )\r
+{\r
+\r
+ Float64 *rate = (Float64 *) ratePointer;\r
+ UInt32 dataSize = sizeof( Float64 );\r
+ AudioObjectPropertyAddress property = { kAudioDevicePropertyNominalSampleRate,\r
+ kAudioObjectPropertyScopeGlobal,\r
+ kAudioObjectPropertyElementMaster };\r
+ AudioObjectGetPropertyData( inDevice, &property, 0, NULL, &dataSize, rate );\r
+ return kAudioHardwareNoError;\r
+}\r
+\r
bool RtApiCore :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,\r
unsigned int firstChannel, unsigned int sampleRate,\r
RtAudioFormat format, unsigned int *bufferSize,\r
stream_.bufferSize = *bufferSize;\r
stream_.nBuffers = 1;\r
\r
- // Check and if necessary, change the sample rate for the device.\r
- Float64 nominalRate;\r
- dataSize = sizeof( Float64 );\r
- property.mSelector = kAudioDevicePropertyNominalSampleRate;\r
- result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &nominalRate );\r
-\r
- if ( result != noErr ) {\r
- errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting current sample rate.";\r
- errorText_ = errorStream_.str();\r
- return FAILURE;\r
- }\r
-\r
- // Only change the sample rate if off by more than 1 Hz.\r
- if ( fabs( nominalRate - (double)sampleRate ) > 1.0 ) {\r
- nominalRate = (Float64) sampleRate;\r
- result = AudioObjectSetPropertyData( id, &property, 0, NULL, dataSize, &nominalRate );\r
-\r
- if ( result != noErr ) {\r
- errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting sample rate for device (" << device << ").";\r
- errorText_ = errorStream_.str();\r
- return FAILURE;\r
- }\r
- }\r
-\r
// Try to set "hog" mode ... it's not clear to me this is working.\r
if ( options && options->flags & RTAUDIO_HOG_DEVICE ) {\r
pid_t hog_pid;\r
}\r
}\r
\r
- // Get the stream ID(s) so we can set the stream format.\r
- AudioStreamID streamIDs[ nStreams ];\r
- dataSize = nStreams * sizeof( AudioStreamID );\r
- property.mSelector = kAudioDevicePropertyStreams;\r
- result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &streamIDs );\r
+ // Check and if necessary, change the sample rate for the device.\r
+ Float64 nominalRate;\r
+ dataSize = sizeof( Float64 );\r
+ property.mSelector = kAudioDevicePropertyNominalSampleRate;\r
+ result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &nominalRate );\r
\r
if ( result != noErr ) {\r
- errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting stream ID(s) for device (" << device << ").";\r
+ errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting current sample rate.";\r
errorText_ = errorStream_.str();\r
return FAILURE;\r
}\r
\r
- // Now set the stream format for each stream. Also, check the\r
- // physical format of the device and change that if necessary.\r
- AudioStreamBasicDescription description;\r
- dataSize = sizeof( AudioStreamBasicDescription );\r
-\r
- bool updateFormat;\r
- for ( UInt32 i=0; i<streamCount; i++ ) {\r
-\r
- property.mSelector = kAudioStreamPropertyVirtualFormat;\r
- result = AudioObjectGetPropertyData( streamIDs[firstStream+i], &property, 0, NULL, &dataSize, &description );\r
+ // Only change the sample rate if off by more than 1 Hz.\r
+ if ( fabs( nominalRate - (double)sampleRate ) > 1.0 ) {\r
\r
+ // Set a property listener for the sample rate change\r
+ Float64 reportedRate = 0.0;\r
+ AudioObjectPropertyAddress tmp = { kAudioDevicePropertyNominalSampleRate, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };\r
+ result = AudioObjectAddPropertyListener( id, &tmp, rateListener, (void *) &reportedRate );\r
if ( result != noErr ) {\r
- errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting stream format for device (" << device << ").";\r
+ errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting sample rate property listener for device (" << device << ").";\r
errorText_ = errorStream_.str();\r
return FAILURE;\r
}\r
\r
- // Set the sample rate and data format id. However, only make the\r
- // change if the sample rate is not within 1.0 of the desired\r
- // rate and the format is not linear pcm.\r
- updateFormat = false;\r
- if ( fabs( description.mSampleRate - (double)sampleRate ) > 1.0 ) {\r
- description.mSampleRate = (double) sampleRate;\r
- updateFormat = true;\r
- }\r
+ nominalRate = (Float64) sampleRate;\r
+ result = AudioObjectSetPropertyData( id, &property, 0, NULL, dataSize, &nominalRate );\r
\r
- if ( description.mFormatID != kAudioFormatLinearPCM ) {\r
- description.mFormatID = kAudioFormatLinearPCM;\r
- updateFormat = true;\r
+ if ( result != noErr ) {\r
+ errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting sample rate for device (" << device << ").";\r
+ errorText_ = errorStream_.str();\r
+ return FAILURE;\r
}\r
\r
- if ( updateFormat ) {\r
- result = AudioObjectSetPropertyData( streamIDs[firstStream+i], &property, 0, NULL, dataSize, &description );\r
- if ( result != noErr ) {\r
- errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting sample rate or data format for device (" << device << ").";\r
- errorText_ = errorStream_.str();\r
- return FAILURE;\r
- }\r
+ // Now wait until the reported nominal rate is what we just set.\r
+ UInt32 microCounter = 0;\r
+ while ( reportedRate != nominalRate ) {\r
+ microCounter += 5000;\r
+ if ( microCounter > 5000000 ) break;\r
+ usleep( 5000 );\r
}\r
\r
- // Now check the physical format.\r
- property.mSelector = kAudioStreamPropertyPhysicalFormat;\r
- result = AudioObjectGetPropertyData( streamIDs[firstStream+i], &property, 0, NULL, &dataSize, &description );\r
- if ( result != noErr ) {\r
- errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting stream physical format for device (" << device << ").";\r
+ // Remove the property listener.\r
+ AudioObjectRemovePropertyListener( id, &tmp, rateListener, (void *) &reportedRate );\r
+\r
+ if ( microCounter > 5000000 ) {\r
+ errorStream_ << "RtApiCore::probeDeviceOpen: timeout waiting for sample rate update for device (" << device << ").";\r
errorText_ = errorStream_.str();\r
return FAILURE;\r
}\r
+ }\r
\r
- if ( description.mFormatID != kAudioFormatLinearPCM || description.mBitsPerChannel < 24 ) {\r
- description.mFormatID = kAudioFormatLinearPCM;\r
- AudioStreamBasicDescription testDescription = description;\r
- unsigned long formatFlags;\r
+ // Now set the stream format for all streams. Also, check the\r
+ // physical format of the device and change that if necessary.\r
+ AudioStreamBasicDescription description;\r
+ dataSize = sizeof( AudioStreamBasicDescription );\r
+ property.mSelector = kAudioStreamPropertyVirtualFormat;\r
+ result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &description );\r
+ if ( result != noErr ) {\r
+ errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting stream format for device (" << device << ").";\r
+ errorText_ = errorStream_.str();\r
+ return FAILURE;\r
+ }\r
\r
- // We'll try higher bit rates first and then work our way down.\r
- testDescription.mBitsPerChannel = 32;\r
- testDescription.mBytesPerFrame = testDescription.mBitsPerChannel/8 * testDescription.mChannelsPerFrame;\r
- testDescription.mBytesPerPacket = testDescription.mBytesPerFrame * testDescription.mFramesPerPacket;\r
- formatFlags = description.mFormatFlags | kLinearPCMFormatFlagIsFloat & ~kLinearPCMFormatFlagIsSignedInteger;\r
- testDescription.mFormatFlags = formatFlags;\r
- result = AudioObjectSetPropertyData( streamIDs[firstStream+i], &property, 0, NULL, dataSize, &testDescription );\r
- if ( result == noErr ) continue;\r
+ // Set the sample rate and data format id. However, only make the\r
+ // change if the sample rate is not within 1.0 of the desired\r
+ // rate and the format is not linear pcm.\r
+ bool updateFormat = false;\r
+ if ( fabs( description.mSampleRate - (Float64)sampleRate ) > 1.0 ) {\r
+ description.mSampleRate = (Float64) sampleRate;\r
+ updateFormat = true;\r
+ }\r
\r
- testDescription = description;\r
- testDescription.mBitsPerChannel = 32;\r
- testDescription.mBytesPerFrame = testDescription.mBitsPerChannel/8 * testDescription.mChannelsPerFrame;\r
- testDescription.mBytesPerPacket = testDescription.mBytesPerFrame * testDescription.mFramesPerPacket;\r
- formatFlags = (description.mFormatFlags | kLinearPCMFormatFlagIsSignedInteger) & ~kLinearPCMFormatFlagIsFloat;\r
- testDescription.mFormatFlags = formatFlags;\r
- result = AudioObjectSetPropertyData( streamIDs[firstStream+i], &property, 0, NULL, dataSize, &testDescription );\r
- if ( result == noErr ) continue;\r
+ if ( description.mFormatID != kAudioFormatLinearPCM ) {\r
+ description.mFormatID = kAudioFormatLinearPCM;\r
+ updateFormat = true;\r
+ }\r
\r
- testDescription = description;\r
- testDescription.mBitsPerChannel = 24;\r
- testDescription.mBytesPerFrame = testDescription.mBitsPerChannel/8 * testDescription.mChannelsPerFrame;\r
- testDescription.mBytesPerPacket = testDescription.mBytesPerFrame * testDescription.mFramesPerPacket;\r
- testDescription.mFormatFlags = formatFlags;\r
- result = AudioObjectSetPropertyData( streamIDs[firstStream+i], &property, 0, NULL, dataSize, &testDescription );\r
- if ( result == noErr ) continue;\r
+ if ( updateFormat ) {\r
+ result = AudioObjectSetPropertyData( id, &property, 0, NULL, dataSize, &description );\r
+ if ( result != noErr ) {\r
+ errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting sample rate or data format for device (" << device << ").";\r
+ errorText_ = errorStream_.str();\r
+ return FAILURE;\r
+ }\r
+ }\r
\r
- testDescription = description;\r
- testDescription.mBitsPerChannel = 16;\r
- testDescription.mBytesPerFrame = testDescription.mBitsPerChannel/8 * testDescription.mChannelsPerFrame;\r
- testDescription.mBytesPerPacket = testDescription.mBytesPerFrame * testDescription.mFramesPerPacket;\r
- testDescription.mFormatFlags = formatFlags;\r
- result = AudioObjectSetPropertyData( streamIDs[firstStream+i], &property, 0, NULL, dataSize, &testDescription );\r
- if ( result == noErr ) continue;\r
+ // Now check the physical format.\r
+ property.mSelector = kAudioStreamPropertyPhysicalFormat;\r
+ result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &description );\r
+ if ( result != noErr ) {\r
+ errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting stream physical format for device (" << device << ").";\r
+ errorText_ = errorStream_.str();\r
+ return FAILURE;\r
+ }\r
\r
+ //std::cout << "Current physical stream format:" << std::endl;\r
+ //std::cout << " mBitsPerChan = " << description.mBitsPerChannel << std::endl;\r
+ //std::cout << " aligned high = " << (description.mFormatFlags & kAudioFormatFlagIsAlignedHigh) << ", isPacked = " << (description.mFormatFlags & kAudioFormatFlagIsPacked) << std::endl;\r
+ //std::cout << " bytesPerFrame = " << description.mBytesPerFrame << std::endl;\r
+ //std::cout << " sample rate = " << description.mSampleRate << std::endl;\r
+\r
+ if ( description.mFormatID != kAudioFormatLinearPCM || description.mBitsPerChannel < 16 ) {\r
+ description.mFormatID = kAudioFormatLinearPCM;\r
+ //description.mSampleRate = (Float64) sampleRate;\r
+ AudioStreamBasicDescription testDescription = description;\r
+ UInt32 formatFlags;\r
+\r
+ // We'll try higher bit rates first and then work our way down.\r
+ std::vector< std::pair<UInt32, UInt32> > physicalFormats;\r
+ formatFlags = description.mFormatFlags | kLinearPCMFormatFlagIsFloat & ~kLinearPCMFormatFlagIsSignedInteger;\r
+ physicalFormats.push_back( std::pair<Float32, UInt32>( 32, formatFlags ) );\r
+ formatFlags = (description.mFormatFlags | kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked) & ~kLinearPCMFormatFlagIsFloat;\r
+ physicalFormats.push_back( std::pair<Float32, UInt32>( 32, formatFlags ) );\r
+ physicalFormats.push_back( std::pair<Float32, UInt32>( 24, formatFlags ) ); // 24-bit packed\r
+ formatFlags &= ~( kAudioFormatFlagIsPacked | kAudioFormatFlagIsAlignedHigh );\r
+ physicalFormats.push_back( std::pair<Float32, UInt32>( 24.2, formatFlags ) ); // 24-bit in 4 bytes, aligned low\r
+ formatFlags |= kAudioFormatFlagIsAlignedHigh;\r
+ physicalFormats.push_back( std::pair<Float32, UInt32>( 24.4, formatFlags ) ); // 24-bit in 4 bytes, aligned high\r
+ formatFlags = (description.mFormatFlags | kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked) & ~kLinearPCMFormatFlagIsFloat;\r
+ physicalFormats.push_back( std::pair<Float32, UInt32>( 16, formatFlags ) );\r
+ physicalFormats.push_back( std::pair<Float32, UInt32>( 8, formatFlags ) );\r
+\r
+ bool setPhysicalFormat = false;\r
+ for( unsigned int i=0; i<physicalFormats.size(); i++ ) {\r
testDescription = description;\r
- testDescription.mBitsPerChannel = 8;\r
- testDescription.mBytesPerFrame = testDescription.mBitsPerChannel/8 * testDescription.mChannelsPerFrame;\r
+ testDescription.mBitsPerChannel = (UInt32) physicalFormats[i].first;\r
+ testDescription.mFormatFlags = physicalFormats[i].second;\r
+ if ( (24 == (UInt32)physicalFormats[i].first) && ~( physicalFormats[i].second & kAudioFormatFlagIsPacked ) )\r
+ testDescription.mBytesPerFrame = 4 * testDescription.mChannelsPerFrame;\r
+ else\r
+ testDescription.mBytesPerFrame = testDescription.mBitsPerChannel/8 * testDescription.mChannelsPerFrame;\r
testDescription.mBytesPerPacket = testDescription.mBytesPerFrame * testDescription.mFramesPerPacket;\r
- testDescription.mFormatFlags = formatFlags;\r
- result = AudioObjectSetPropertyData( streamIDs[firstStream+i], &property, 0, NULL, dataSize, &testDescription );\r
- if ( result != noErr ) {\r
- errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting physical data format for device (" << device << ").";\r
- errorText_ = errorStream_.str();\r
- return FAILURE;\r
+ result = AudioObjectSetPropertyData( id, &property, 0, NULL, dataSize, &testDescription );\r
+ if ( result == noErr ) {\r
+ setPhysicalFormat = true;\r
+ //std::cout << "Updated physical stream format:" << std::endl;\r
+ //std::cout << " mBitsPerChan = " << testDescription.mBitsPerChannel << std::endl;\r
+ //std::cout << " aligned high = " << (testDescription.mFormatFlags & kAudioFormatFlagIsAlignedHigh) << ", isPacked = " << (testDescription.mFormatFlags & kAudioFormatFlagIsPacked) << std::endl;\r
+ //std::cout << " bytesPerFrame = " << testDescription.mBytesPerFrame << std::endl;\r
+ //std::cout << " sample rate = " << testDescription.mSampleRate << std::endl;\r
+ break;\r
}\r
}\r
- }\r
\r
+ if ( !setPhysicalFormat ) {\r
+ errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting physical data format for device (" << device << ").";\r
+ errorText_ = errorStream_.str();\r
+ return FAILURE;\r
+ }\r
+ } // done setting virtual/physical formats.\r
\r
- // Get the stream latency. There can be latency in both the device\r
- // and the stream. First, attempt to get the device latency on the\r
- // master channel or the first open channel. Errors that might\r
- // occur here are not deemed critical.\r
-\r
+ // Get the stream / device latency.\r
UInt32 latency;\r
dataSize = sizeof( UInt32 );\r
property.mSelector = kAudioDevicePropertyLatency;\r
}\r
}\r
\r
- // Now try to get the stream latency. For multiple streams, I assume the\r
- // latency is equal for each.\r
- result = AudioObjectGetPropertyData( streamIDs[firstStream], &property, 0, NULL, &dataSize, &latency );\r
- if ( result == kAudioHardwareNoError ) stream_.latency[ mode ] += latency;\r
- else {\r
- errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting stream latency for device (" << device << ").";\r
- errorText_ = errorStream_.str();\r
- error( RtError::WARNING );\r
- }\r
-\r
// Byte-swapping: According to AudioHardware.h, the stream data will\r
// always be presented in native-endian format, so we should never\r
// need to byte swap.\r
unsigned long bufferBytes;\r
bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat );\r
// stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 );\r
- stream_.userBuffer[mode] = (char *) malloc( bufferBytes );\r
+ stream_.userBuffer[mode] = (char *) malloc( bufferBytes * sizeof(char) );\r
+ memset( stream_.userBuffer[mode], 0, bufferBytes * sizeof(char) );\r
if ( stream_.userBuffer[mode] == NULL ) {\r
errorText_ = "RtApiCore::probeDeviceOpen: error allocating user buffer memory.";\r
goto error;\r
\r
// Setup the device property listener for over/underload.\r
property.mSelector = kAudioDeviceProcessorOverload;\r
- result = AudioObjectAddPropertyListener( id, &property, deviceListener, (void *) handle );\r
+ result = AudioObjectAddPropertyListener( id, &property, xrunListener, (void *) handle );\r
\r
return SUCCESS;\r
\r
return FAILURE;\r
}\r
\r
- // The getDeviceInfo() function will not work when a stream is open\r
- // because ASIO does not allow multiple devices to run at the same\r
- // time. Thus, we'll probe the system before opening a stream and\r
- // save the results for use by getDeviceInfo().\r
- this->saveDeviceInfo();\r
-\r
// Only load the driver once for duplex stream.\r
if ( mode != INPUT || stream_.mode != OUTPUT ) {\r
+ // The getDeviceInfo() function will not work when a stream is open\r
+ // because ASIO does not allow multiple devices to run at the same\r
+ // time. Thus, we'll probe the system before opening a stream and\r
+ // save the results for use by getDeviceInfo().\r
+ this->saveDeviceInfo();\r
+\r
if ( !drivers.loadDriver( driverName ) ) {\r
errorStream_ << "RtApiAsio::probeDeviceOpen: unable to load driver (" << driverName << ").";\r
errorText_ = errorStream_.str();\r
}\r
if ( found == false ) info.sampleRates.push_back( rates[i] );\r
}\r
- sort( info.sampleRates.begin(), info.sampleRates.end() );\r
+ std::sort( info.sampleRates.begin(), info.sampleRates.end() );\r
\r
// If device opens for both playback and capture, we determine the channels.\r
if ( info.outputChannels > 0 && info.inputChannels > 0 )\r
\r
std::string convertTChar( LPCTSTR name )\r
{\r
- std::string s;\r
-\r
#if defined( UNICODE ) || defined( _UNICODE )\r
- // Yes, this conversion doesn't make sense for two-byte characters\r
- // but RtAudio is currently written to return an std::string of\r
- // one-byte chars for the device name.\r
- for ( unsigned int i=0; i<wcslen( name ); i++ )\r
- s.push_back( name[i] );\r
+ int length = WideCharToMultiByte(CP_UTF8, 0, name, -1, NULL, 0, NULL, NULL);\r
+ std::string s( length, 0 );\r
+ length = WideCharToMultiByte(CP_UTF8, 0, name, wcslen(name), &s[0], length, NULL, NULL);\r
#else\r
- s.append( std::string( name ) );\r
+ std::string s( name );\r
#endif\r
\r
return s;\r
snd_pcm_t *handles[2];\r
bool synchronized;\r
bool xrun[2];\r
- pthread_cond_t runnable;\r
+ pthread_cond_t runnable_cv;\r
+ bool runnable;\r
\r
AlsaHandle()\r
- :synchronized(false) { xrun[0] = false; xrun[1] = false; }\r
+ :synchronized(false), runnable(false) { xrun[0] = false; xrun[1] = false; }\r
};\r
\r
extern "C" void *alsaCallbackHandler( void * ptr );\r
goto error;\r
}\r
\r
- if ( pthread_cond_init( &apiInfo->runnable, NULL ) ) {\r
+ if ( pthread_cond_init( &apiInfo->runnable_cv, NULL ) ) {\r
errorText_ = "RtApiAlsa::probeDeviceOpen: error initializing pthread condition variable.";\r
goto error;\r
}\r
\r
error:\r
if ( apiInfo ) {\r
- pthread_cond_destroy( &apiInfo->runnable );\r
+ pthread_cond_destroy( &apiInfo->runnable_cv );\r
if ( apiInfo->handles[0] ) snd_pcm_close( apiInfo->handles[0] );\r
if ( apiInfo->handles[1] ) snd_pcm_close( apiInfo->handles[1] );\r
delete apiInfo;\r
AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;\r
stream_.callbackInfo.isRunning = false;\r
MUTEX_LOCK( &stream_.mutex );\r
- if ( stream_.state == STREAM_STOPPED )\r
- pthread_cond_signal( &apiInfo->runnable );\r
+ if ( stream_.state == STREAM_STOPPED ) {\r
+ apiInfo->runnable = true;\r
+ pthread_cond_signal( &apiInfo->runnable_cv );\r
+ }\r
MUTEX_UNLOCK( &stream_.mutex );\r
pthread_join( stream_.callbackInfo.thread, NULL );\r
\r
}\r
\r
if ( apiInfo ) {\r
- pthread_cond_destroy( &apiInfo->runnable );\r
+ pthread_cond_destroy( &apiInfo->runnable_cv );\r
if ( apiInfo->handles[0] ) snd_pcm_close( apiInfo->handles[0] );\r
if ( apiInfo->handles[1] ) snd_pcm_close( apiInfo->handles[1] );\r
delete apiInfo;\r
stream_.state = STREAM_RUNNING;\r
\r
unlock:\r
+ apiInfo->runnable = true;\r
+ pthread_cond_signal( &apiInfo->runnable_cv );\r
MUTEX_UNLOCK( &stream_.mutex );\r
\r
- pthread_cond_signal( &apiInfo->runnable );\r
-\r
if ( result >= 0 ) return;\r
error( RtError::SYSTEM_ERROR );\r
}\r
AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;\r
if ( stream_.state == STREAM_STOPPED ) {\r
MUTEX_LOCK( &stream_.mutex );\r
- pthread_cond_wait( &apiInfo->runnable, &stream_.mutex );\r
+ while ( !apiInfo->runnable )\r
+ pthread_cond_wait( &apiInfo->runnable_cv, &stream_.mutex );\r
+\r
if ( stream_.state != STREAM_RUNNING ) {\r
MUTEX_UNLOCK( &stream_.mutex );\r
return;\r