return;
}
+ #if defined( HAVE_GETTIMEOFDAY )
+ gettimeofday( &stream_.lastTickTimestamp, NULL );
+ #endif
+
OSStatus result = noErr;
CoreHandle *handle = (CoreHandle *) stream_.apiHandle;
if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
return;
}
+ #if defined( HAVE_GETTIMEOFDAY )
+ gettimeofday( &stream_.lastTickTimestamp, NULL );
+ #endif
+
JackHandle *handle = (JackHandle *) stream_.apiHandle;
int result = jack_activate( handle->client );
if ( result ) {
result = ASIOCreateBuffers( handle->bufferInfos, nChannels, stream_.bufferSize, &asioCallbacks );
if ( result != ASE_OK ) {
// Standard method failed. This can happen with strict/misbehaving drivers that return valid buffer size ranges
- // but only accept the preferred buffer size as parameter for ASIOCreateBuffers. eg. Creatives ASIO driver
- // in that case, let's be naïve and try that instead
+ // but only accept the preferred buffer size as parameter for ASIOCreateBuffers (e.g. Creative's ASIO driver).
+ // In that case, let's be naïve and try that instead.
*bufferSize = preferSize;
stream_.bufferSize = *bufferSize;
result = ASIOCreateBuffers( handle->bufferInfos, nChannels, stream_.bufferSize, &asioCallbacks );
return;
}
+ #if defined( HAVE_GETTIMEOFDAY )
+ gettimeofday( &stream_.lastTickTimestamp, NULL );
+ #endif
+
AsioHandle *handle = (AsioHandle *) stream_.apiHandle;
ASIOError result = ASIOStart();
if ( result != ASE_OK ) {
}
// "in" index can end on the "out" index but cannot begin at it
- if ( inIndex_ <= relOutIndex && inIndexEnd > relOutIndex ) {
+ if ( inIndex_ < relOutIndex && inIndexEnd > relOutIndex ) {
return false; // not enough space between "in" index and "out" index
}
}
// "out" index can begin at and end on the "in" index
- if ( outIndex_ < relInIndex && outIndexEnd > relInIndex ) {
+ if ( outIndex_ <= relInIndex && outIndexEnd > relInIndex ) {
return false; // not enough space between "out" index and "in" index
}
return;
}
+ #if defined( HAVE_GETTIMEOFDAY )
+ gettimeofday( &stream_.lastTickTimestamp, NULL );
+ #endif
+
// update stream state
stream_.state = STREAM_RUNNING;
goto Exit;
}
- // determine whether index falls within capture or render devices
+ // if device index falls within capture devices
if ( device >= renderDeviceCount ) {
if ( mode != INPUT ) {
errorType = RtAudioError::INVALID_USE;
hr = devicePtr->Activate( __uuidof( IAudioClient ), CLSCTX_ALL,
NULL, ( void** ) &captureAudioClient );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve device audio client.";
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve capture device audio client.";
goto Exit;
}
hr = captureAudioClient->GetMixFormat( &deviceFormat );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve device mix format.";
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve capture device mix format.";
goto Exit;
}
stream_.nDeviceChannels[mode] = deviceFormat->nChannels;
captureAudioClient->GetStreamLatency( ( long long* ) &stream_.latency[mode] );
}
- else {
- if ( mode != OUTPUT ) {
- errorType = RtAudioError::INVALID_USE;
- errorText_ = "RtApiWasapi::probeDeviceOpen: Render device selected as input device.";
+
+ // if device index falls within render devices and is configured for loopback
+ if ( device < renderDeviceCount && mode == INPUT )
+ {
+ // if renderAudioClient is not initialised, initialise it now
+ IAudioClient*& renderAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient;
+ if ( !renderAudioClient )
+ {
+ probeDeviceOpen( device, OUTPUT, channels, firstChannel, sampleRate, format, bufferSize, options );
+ }
+
+ // retrieve captureAudioClient from devicePtr
+ IAudioClient*& captureAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient;
+
+ hr = renderDevices->Item( device, &devicePtr );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve render device handle.";
goto Exit;
}
- // retrieve renderAudioClient from devicePtr
+ hr = devicePtr->Activate( __uuidof( IAudioClient ), CLSCTX_ALL,
+ NULL, ( void** ) &captureAudioClient );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve render device audio client.";
+ goto Exit;
+ }
+
+ hr = captureAudioClient->GetMixFormat( &deviceFormat );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve render device mix format.";
+ goto Exit;
+ }
+
+ stream_.nDeviceChannels[mode] = deviceFormat->nChannels;
+ captureAudioClient->GetStreamLatency( ( long long* ) &stream_.latency[mode] );
+ }
+
+ // if device index falls within render devices and is configured for output
+ if ( device < renderDeviceCount && mode == OUTPUT )
+ {
+ // if renderAudioClient is already initialised, don't initialise it again
IAudioClient*& renderAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient;
+ if ( renderAudioClient )
+ {
+ methodResult = SUCCESS;
+ goto Exit;
+ }
hr = renderDevices->Item( device, &devicePtr );
if ( FAILED( hr ) ) {
hr = devicePtr->Activate( __uuidof( IAudioClient ), CLSCTX_ALL,
NULL, ( void** ) &renderAudioClient );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve device audio client.";
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve render device audio client.";
goto Exit;
}
hr = renderAudioClient->GetMixFormat( &deviceFormat );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve device mix format.";
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve render device mix format.";
goto Exit;
}
unsigned int bufferFrameCount = 0;
unsigned int numFramesPadding = 0;
unsigned int convBufferSize = 0;
+ bool loopbackEnabled = stream_.device[INPUT] == stream_.device[OUTPUT];
bool callbackPushed = true;
bool callbackPulled = false;
bool callbackStopped = false;
unsigned int convBuffSize = 0;
unsigned int deviceBuffSize = 0;
- errorText_.clear();
+ std::string errorText;
RtAudioError::Type errorType = RtAudioError::DRIVER_ERROR;
// Attempt to assign "Pro Audio" characteristic to thread
HMODULE AvrtDll = LoadLibrary( (LPCTSTR) "AVRT.dll" );
if ( AvrtDll ) {
DWORD taskIndex = 0;
- TAvSetMmThreadCharacteristicsPtr AvSetMmThreadCharacteristicsPtr = ( TAvSetMmThreadCharacteristicsPtr ) GetProcAddress( AvrtDll, "AvSetMmThreadCharacteristicsW" );
+ TAvSetMmThreadCharacteristicsPtr AvSetMmThreadCharacteristicsPtr =
+ ( TAvSetMmThreadCharacteristicsPtr ) (void(*)()) GetProcAddress( AvrtDll, "AvSetMmThreadCharacteristicsW" );
AvSetMmThreadCharacteristicsPtr( L"Pro Audio", &taskIndex );
FreeLibrary( AvrtDll );
}
if ( captureAudioClient ) {
hr = captureAudioClient->GetMixFormat( &captureFormat );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve device mix format.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to retrieve device mix format.";
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 );
-
if ( !captureClient ) {
hr = captureAudioClient->Initialize( AUDCLNT_SHAREMODE_SHARED,
- AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
- desiredBufferPeriod,
- desiredBufferPeriod,
+ loopbackEnabled ? AUDCLNT_STREAMFLAGS_LOOPBACK : AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
+ 0,
+ 0,
captureFormat,
NULL );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to initialize capture audio client.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to initialize capture audio client.";
goto Exit;
}
hr = captureAudioClient->GetService( __uuidof( IAudioCaptureClient ),
( void** ) &captureClient );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve capture client handle.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to retrieve capture client handle.";
goto Exit;
}
- // configure captureEvent to trigger on every available capture buffer
- captureEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
- if ( !captureEvent ) {
- errorType = RtAudioError::SYSTEM_ERROR;
- errorText_ = "RtApiWasapi::wasapiThread: Unable to create capture event.";
- goto Exit;
- }
+ // don't configure captureEvent if in loopback mode
+ if ( !loopbackEnabled )
+ {
+ // configure captureEvent to trigger on every available capture buffer
+ captureEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+ if ( !captureEvent ) {
+ errorType = RtAudioError::SYSTEM_ERROR;
+ errorText = "RtApiWasapi::wasapiThread: Unable to create capture event.";
+ goto Exit;
+ }
- hr = captureAudioClient->SetEventHandle( captureEvent );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to set capture event handle.";
- goto Exit;
+ hr = captureAudioClient->SetEventHandle( captureEvent );
+ if ( FAILED( hr ) ) {
+ errorText = "RtApiWasapi::wasapiThread: Unable to set capture event handle.";
+ goto Exit;
+ }
+
+ ( ( WasapiHandle* ) stream_.apiHandle )->captureEvent = captureEvent;
}
( ( WasapiHandle* ) stream_.apiHandle )->captureClient = captureClient;
- ( ( WasapiHandle* ) stream_.apiHandle )->captureEvent = captureEvent;
}
unsigned int inBufferSize = 0;
hr = captureAudioClient->GetBufferSize( &inBufferSize );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to get capture buffer size.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to get capture buffer size.";
goto Exit;
}
// reset the capture stream
hr = captureAudioClient->Reset();
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to reset capture stream.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to reset capture stream.";
goto Exit;
}
// start the capture stream
hr = captureAudioClient->Start();
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to start capture stream.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to start capture stream.";
goto Exit;
}
}
if ( renderAudioClient ) {
hr = renderAudioClient->GetMixFormat( &renderFormat );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve device mix format.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to retrieve device mix format.";
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 );
-
if ( !renderClient ) {
hr = renderAudioClient->Initialize( AUDCLNT_SHAREMODE_SHARED,
AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
- desiredBufferPeriod,
- desiredBufferPeriod,
+ 0,
+ 0,
renderFormat,
NULL );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to initialize render audio client.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to initialize render audio client.";
goto Exit;
}
hr = renderAudioClient->GetService( __uuidof( IAudioRenderClient ),
( void** ) &renderClient );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve render client handle.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to retrieve render client handle.";
goto Exit;
}
renderEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
if ( !renderEvent ) {
errorType = RtAudioError::SYSTEM_ERROR;
- errorText_ = "RtApiWasapi::wasapiThread: Unable to create render event.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to create render event.";
goto Exit;
}
hr = renderAudioClient->SetEventHandle( renderEvent );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to set render event handle.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to set render event handle.";
goto Exit;
}
unsigned int outBufferSize = 0;
hr = renderAudioClient->GetBufferSize( &outBufferSize );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to get render buffer size.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to get render buffer size.";
goto Exit;
}
// reset the render stream
hr = renderAudioClient->Reset();
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to reset render stream.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to reset render stream.";
goto Exit;
}
// start the render stream
hr = renderAudioClient->Start();
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to start render stream.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to start render stream.";
goto Exit;
}
}
}
convBuffSize *= 2; // allow overflow for *SrRatio remainders
- convBuffer = ( char* ) malloc( convBuffSize );
- stream_.deviceBuffer = ( char* ) malloc( deviceBuffSize );
+ convBuffer = ( char* ) calloc( convBuffSize, 1 );
+ stream_.deviceBuffer = ( char* ) calloc( deviceBuffSize, 1 );
if ( !convBuffer || !stream_.deviceBuffer ) {
errorType = RtAudioError::MEMORY_ERROR;
- errorText_ = "RtApiWasapi::wasapiThread: Error allocating device buffer memory.";
+ errorText = "RtApiWasapi::wasapiThread: Error allocating device buffer memory.";
goto Exit;
}
HANDLE threadHandle = CreateThread( NULL, 0, stopWasapiThread, this, 0, NULL );
if ( !threadHandle ) {
errorType = RtAudioError::THREAD_ERROR;
- errorText_ = "RtApiWasapi::wasapiThread: Unable to instantiate stream stop thread.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to instantiate stream stop thread.";
goto Exit;
}
else if ( !CloseHandle( threadHandle ) ) {
errorType = RtAudioError::THREAD_ERROR;
- errorText_ = "RtApiWasapi::wasapiThread: Unable to close stream stop thread handle.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to close stream stop thread handle.";
goto Exit;
}
HANDLE threadHandle = CreateThread( NULL, 0, abortWasapiThread, this, 0, NULL );
if ( !threadHandle ) {
errorType = RtAudioError::THREAD_ERROR;
- errorText_ = "RtApiWasapi::wasapiThread: Unable to instantiate stream abort thread.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to instantiate stream abort thread.";
goto Exit;
}
else if ( !CloseHandle( threadHandle ) ) {
errorType = RtAudioError::THREAD_ERROR;
- errorText_ = "RtApiWasapi::wasapiThread: Unable to close stream abort thread handle.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to close stream abort thread handle.";
goto Exit;
}
stream_.convertInfo[OUTPUT] );
}
+ else {
+ // no further conversion, simple copy userBuffer to deviceBuffer
+ memcpy( stream_.deviceBuffer,
+ stream_.userBuffer[OUTPUT],
+ stream_.bufferSize * stream_.nUserChannels[OUTPUT] * formatBytes( stream_.userFormat ) );
+ }
// Convert callback buffer to stream sample rate
renderResampler->Convert( convBuffer,
if ( captureAudioClient ) {
// if the callback input buffer was not pulled from captureBuffer, wait for next capture event
if ( !callbackPulled ) {
- WaitForSingleObject( captureEvent, INFINITE );
+ WaitForSingleObject( loopbackEnabled ? renderEvent : captureEvent, INFINITE );
}
// Get capture buffer from stream
&bufferFrameCount,
&captureFlags, NULL, NULL );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve capture buffer.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to retrieve capture buffer.";
goto Exit;
}
// Release capture buffer
hr = captureClient->ReleaseBuffer( bufferFrameCount );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to release capture buffer.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to release capture buffer.";
goto Exit;
}
}
// Inform WASAPI that capture was unsuccessful
hr = captureClient->ReleaseBuffer( 0 );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to release capture buffer.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to release capture buffer.";
goto Exit;
}
}
// Inform WASAPI that capture was unsuccessful
hr = captureClient->ReleaseBuffer( 0 );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to release capture buffer.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to release capture buffer.";
goto Exit;
}
}
// Get render buffer from stream
hr = renderAudioClient->GetBufferSize( &bufferFrameCount );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve render buffer size.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to retrieve render buffer size.";
goto Exit;
}
hr = renderAudioClient->GetCurrentPadding( &numFramesPadding );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve render buffer padding.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to retrieve render buffer padding.";
goto Exit;
}
if ( bufferFrameCount != 0 ) {
hr = renderClient->GetBuffer( bufferFrameCount, &streamBuffer );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve render buffer.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to retrieve render buffer.";
goto Exit;
}
// Release render buffer
hr = renderClient->ReleaseBuffer( bufferFrameCount, 0 );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to release render buffer.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to release render buffer.";
goto Exit;
}
}
// Inform WASAPI that render was unsuccessful
hr = renderClient->ReleaseBuffer( 0, 0 );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to release render buffer.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to release render buffer.";
goto Exit;
}
}
// Inform WASAPI that render was unsuccessful
hr = renderClient->ReleaseBuffer( 0, 0 );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to release render buffer.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to release render buffer.";
goto Exit;
}
}
CoUninitialize();
- if ( !errorText_.empty() )
- error( errorType );
-
// update stream state
stream_.state = STREAM_STOPPED;
+
+ if ( !errorText.empty() )
+ {
+ errorText_ = errorText;
+ error( errorType );
+ }
}
//******************** End of __WINDOWS_WASAPI__ *********************//
return;
}
+ #if defined( HAVE_GETTIMEOFDAY )
+ gettimeofday( &stream_.lastTickTimestamp, NULL );
+ #endif
+
DsHandle *handle = (DsHandle *) stream_.apiHandle;
// Increase scheduler frequency on lesser windows (a side-effect of
if ( result == 0 ) {
if ( nDevices == device ) {
strcpy( name, "default" );
+ snd_ctl_close( chandle );
goto foundDevice;
}
nDevices++;
}
+ snd_ctl_close( chandle );
if ( nDevices == 0 ) {
// This should not happen because a check is made before this function is called.
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)
+#ifdef SCHED_RR // Undefined with some OSes (e.g. NetBSD 1.6.x with GNU Pthread)
if ( options && options->flags & RTAUDIO_SCHEDULE_REALTIME ) {
stream_.callbackInfo.doRealtime = true;
struct sched_param param;
MUTEX_LOCK( &stream_.mutex );
+ #if defined( HAVE_GETTIMEOFDAY )
+ gettimeofday( &stream_.lastTickTimestamp, NULL );
+ #endif
+
int result = 0;
snd_pcm_state_t state;
AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;
RtApiAlsa *object = (RtApiAlsa *) info->object;
bool *isRunning = &info->isRunning;
-#ifdef SCHED_RR // Undefined with some OSes (eg: NetBSD 1.6.x with GNU Pthread)
+#ifdef SCHED_RR // Undefined with some OSes (e.g. NetBSD 1.6.x with GNU Pthread)
if ( info->doRealtime ) {
std::cerr << "RtAudio alsa: " <<
(sched_getscheduler(0) == SCHED_RR ? "" : "_NOT_ ") <<
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)
+#ifdef SCHED_RR // Undefined with some OSes (e.g. NetBSD 1.6.x with GNU Pthread)
if (cbi->doRealtime) {
std::cerr << "RtAudio pulse: " <<
(sched_getscheduler(0) == SCHED_RR ? "" : "_NOT_ ") <<
MUTEX_LOCK( &stream_.mutex );
+ #if defined( HAVE_GETTIMEOFDAY )
+ gettimeofday( &stream_.lastTickTimestamp, NULL );
+ #endif
+
stream_.state = STREAM_RUNNING;
pah->runnable = true;
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)
+#ifdef SCHED_RR // Undefined with some OSes (e.g. NetBSD 1.6.x with GNU Pthread)
if ( options && options->flags & RTAUDIO_SCHEDULE_REALTIME ) {
stream_.callbackInfo.doRealtime = true;
struct sched_param param;
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)
+#ifdef SCHED_RR // Undefined with some OSes (e.g. NetBSD 1.6.x with GNU Pthread)
if ( options && options->flags & RTAUDIO_SCHEDULE_REALTIME ) {
stream_.callbackInfo.doRealtime = true;
struct sched_param param;
MUTEX_LOCK( &stream_.mutex );
+ #if defined( HAVE_GETTIMEOFDAY )
+ gettimeofday( &stream_.lastTickTimestamp, NULL );
+ #endif
+
stream_.state = STREAM_RUNNING;
// No need to do anything else here ... OSS automatically starts
RtApiOss *object = (RtApiOss *) info->object;
bool *isRunning = &info->isRunning;
-#ifdef SCHED_RR // Undefined with some OSes (eg: NetBSD 1.6.x with GNU Pthread)
+#ifdef SCHED_RR // Undefined with some OSes (e.g. NetBSD 1.6.x with GNU Pthread)
if (info->doRealtime) {
std::cerr << "RtAudio oss: " <<
(sched_getscheduler(0) == SCHED_RR ? "" : "_NOT_ ") <<