RtAudio WWW site: http://www.music.mcgill.ca/~gary/rtaudio/\r
\r
RtAudio: realtime audio i/o C++ classes\r
- Copyright (c) 2001-2011 Gary P. Scavone\r
+ Copyright (c) 2001-2012 Gary P. Scavone\r
\r
Permission is hereby granted, free of charge, to any person\r
obtaining a copy of this software and associated documentation files\r
*/\r
/************************************************************************/\r
\r
-// RtAudio: Version 4.0.10\r
+// RtAudio: Version 4.0.11\r
\r
#include "RtAudio.h"\r
#include <iostream>\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
+ThreadHandle threadId;\r
+\r
RtApiCore:: RtApiCore()\r
{\r
#if defined( AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER )\r
return;\r
}\r
\r
- MUTEX_LOCK( &stream_.mutex );\r
+ //MUTEX_LOCK( &stream_.mutex );\r
\r
OSStatus result = noErr;\r
CoreHandle *handle = (CoreHandle *) stream_.apiHandle;\r
stream_.state = STREAM_RUNNING;\r
\r
unlock:\r
- MUTEX_UNLOCK( &stream_.mutex );\r
+ //MUTEX_UNLOCK( &stream_.mutex );\r
\r
if ( result == noErr ) return;\r
error( RtError::SYSTEM_ERROR );\r
return;\r
}\r
\r
+ /*\r
MUTEX_LOCK( &stream_.mutex );\r
\r
if ( stream_.state == STREAM_STOPPED ) {\r
MUTEX_UNLOCK( &stream_.mutex );\r
return;\r
}\r
+ */\r
\r
OSStatus result = noErr;\r
CoreHandle *handle = (CoreHandle *) stream_.apiHandle;\r
pthread_cond_wait( &handle->condition, &stream_.mutex ); // block until signaled\r
}\r
\r
- MUTEX_UNLOCK( &stream_.mutex );\r
+ //MUTEX_UNLOCK( &stream_.mutex );\r
result = AudioDeviceStop( handle->id[0], callbackHandler );\r
- MUTEX_LOCK( &stream_.mutex );\r
+ //MUTEX_LOCK( &stream_.mutex );\r
if ( result != noErr ) {\r
errorStream_ << "RtApiCore::stopStream: system error (" << getErrorCode( result ) << ") stopping callback procedure on device (" << stream_.device[0] << ").";\r
errorText_ = errorStream_.str();\r
\r
if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && stream_.device[0] != stream_.device[1] ) ) {\r
\r
- MUTEX_UNLOCK( &stream_.mutex );\r
+ //MUTEX_UNLOCK( &stream_.mutex );\r
result = AudioDeviceStop( handle->id[1], callbackHandler );\r
- MUTEX_LOCK( &stream_.mutex );\r
+ //MUTEX_LOCK( &stream_.mutex );\r
if ( result != noErr ) {\r
errorStream_ << "RtApiCore::stopStream: system error (" << getErrorCode( result ) << ") stopping input callback procedure on device (" << stream_.device[1] << ").";\r
errorText_ = errorStream_.str();\r
stream_.state = STREAM_STOPPED;\r
\r
unlock:\r
- MUTEX_UNLOCK( &stream_.mutex );\r
+ //MUTEX_UNLOCK( &stream_.mutex );\r
\r
if ( result == noErr ) return;\r
error( RtError::SYSTEM_ERROR );\r
stopStream();\r
}\r
\r
+// This function will be called by a spawned thread when the user\r
+// callback function signals that the stream should be stopped or\r
+// aborted. It is better to handle it this way because the\r
+// callbackEvent() function probably should return before the AudioDeviceStop()\r
+// function is called.\r
+extern "C" void *coreStopStream( void *ptr )\r
+{\r
+ CallbackInfo *info = (CallbackInfo *) ptr;\r
+ RtApiCore *object = (RtApiCore *) info->object;\r
+\r
+ object->stopStream();\r
+\r
+ pthread_exit( NULL );\r
+}\r
+\r
bool RtApiCore :: callbackEvent( AudioDeviceID deviceId,\r
const AudioBufferList *inBufferList,\r
const AudioBufferList *outBufferList )\r
{\r
- if ( stream_.state == STREAM_STOPPED ) return SUCCESS;\r
+ if ( stream_.state == STREAM_STOPPED || stream_.state == STREAM_STOPPING ) return SUCCESS;\r
if ( stream_.state == STREAM_CLOSED ) {\r
errorText_ = "RtApiCore::callbackEvent(): the stream is closed ... this shouldn't happen!";\r
error( RtError::WARNING );\r
\r
// Check if we were draining the stream and signal is finished.\r
if ( handle->drainCounter > 3 ) {\r
- if ( handle->internalDrain == true )\r
- stopStream();\r
+\r
+ if ( handle->internalDrain == true ) {\r
+ stream_.state = STREAM_STOPPING;\r
+ pthread_create( &threadId, NULL, coreStopStream, info );\r
+ //stopStream();\r
+ }\r
else // external call to stopStream()\r
pthread_cond_signal( &handle->condition );\r
return SUCCESS;\r
}\r
\r
+ /*\r
MUTEX_LOCK( &stream_.mutex );\r
\r
// The state might change while waiting on a mutex.\r
MUTEX_UNLOCK( &stream_.mutex );\r
return SUCCESS;\r
}\r
+ */\r
\r
AudioDeviceID outputDevice = handle->id[0];\r
\r
int cbReturnValue = callback( stream_.userBuffer[0], stream_.userBuffer[1],\r
stream_.bufferSize, streamTime, status, info->userData );\r
if ( cbReturnValue == 2 ) {\r
- MUTEX_UNLOCK( &stream_.mutex );\r
+ //MUTEX_UNLOCK( &stream_.mutex );\r
handle->drainCounter = 2;\r
abortStream();\r
return SUCCESS;\r
}\r
- else if ( cbReturnValue == 1 )\r
+ else if ( cbReturnValue == 1 ) {\r
handle->drainCounter = 1;\r
handle->internalDrain = true;\r
+ }\r
}\r
\r
if ( stream_.mode == OUTPUT || ( stream_.mode == DUPLEX && deviceId == outputDevice ) ) {\r
}\r
\r
unlock:\r
- MUTEX_UNLOCK( &stream_.mutex );\r
+ //MUTEX_UNLOCK( &stream_.mutex );\r
\r
RtApi::tickStreamTime();\r
return SUCCESS;\r
pthread_create( &id, NULL, jackStopStream, info );\r
return SUCCESS;\r
}\r
- else if ( cbReturnValue == 1 )\r
+ else if ( cbReturnValue == 1 ) {\r
handle->drainCounter = 1;\r
handle->internalDrain = true;\r
+ }\r
}\r
\r
jack_default_audio_sample_t *jackbuffer;\r
&stream_.callbackInfo, 0, &threadId );\r
return SUCCESS;\r
}\r
- else if ( cbReturnValue == 1 )\r
+ else if ( cbReturnValue == 1 ) {\r
handle->drainCounter = 1;\r
handle->internalDrain = true;\r
+ }\r
}\r
\r
unsigned int nChannels, bufferBytes, i, j;\r
abortStream();\r
return;\r
}\r
- else if ( cbReturnValue == 1 )\r
+ else if ( cbReturnValue == 1 ) {\r
handle->drainCounter = 1;\r
handle->internalDrain = true;\r
+ }\r
}\r
\r
HRESULT result;\r