Browse Source

Updates for release 4.0.9, including OS-X fixes for 10.6 and 10.7 (gs).

tags/4.0.9
Gary Scavone Stephen Sinclair 14 years ago
parent
commit
6d437609d0
4 changed files with 192 additions and 161 deletions
  1. +183
    -159
      RtAudio.cpp
  2. +1
    -1
      RtAudio.h
  3. +1
    -1
      doc/doxygen/tutorial.txt
  4. +7
    -0
      doc/release.txt

+ 183
- 159
RtAudio.cpp View File

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


+ 1
- 1
RtAudio.h View File

@@ -42,7 +42,7 @@
\file RtAudio.h
*/

// RtAudio: Version 4.0.8
// RtAudio: Version 4.0.9

#ifndef __RTAUDIO_H
#define __RTAUDIO_H


+ 1
- 1
doc/doxygen/tutorial.txt View File

@@ -32,7 +32,7 @@ Devices are now re-enumerated every time the RtAudio::getDeviceCount(), RtAudio:

\section download Download

Latest Release (12 April 2011): <A href="http://www.music.mcgill.ca/~gary/rtaudio/release/rtaudio-4.0.8.tar.gz">Version 4.0.8</A>
Latest Release (11 August 2011): <A href="http://www.music.mcgill.ca/~gary/rtaudio/release/rtaudio-4.0.9.tar.gz">Version 4.0.9</A>

\section documentation Documentation Links



+ 7
- 0
doc/release.txt View File

@@ -2,6 +2,13 @@ RtAudio - a set of C++ classes that provide a common API for realtime audio inpu

By Gary P. Scavone, 2001-2011.

v4.0.9: (?? August 2011)
- fix for ASIO problem enumerating devices after opening duplex stream (Oliver Larkin)
- fix for OS-X problems setting sample rate and bits-per-sample
- updates for OS-X "Lion"
- updates for wide character support in Windows DS (UNICODE)
- fix for possible ALSA callback thread hang (thanks to Tristan Matthews)

v4.0.8: (12 April 2011)
- fix for MinGW4 problem enumerating and setting sample rates (iasiothiscallresolver, Dmitry Kostjuchenko)
- fix for OS-X problem handling device names in some languages (CFString conversion, Vincent Bénony)


Loading…
Cancel
Save