Browse Source

Add loopback support to WASAPI

tags/5.1.0
Marcus Tomlinson Stephen Sinclair 6 years ago
parent
commit
5dff50ada9
1 changed files with 59 additions and 35 deletions
  1. +59
    -35
      RtAudio.cpp

+ 59
- 35
RtAudio.cpp View File

@@ -4727,7 +4727,7 @@ bool RtApiWasapi::probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
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;
@@ -4747,26 +4747,52 @@ bool RtApiWasapi::probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
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 )
{
// 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;
}

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 )
{
// retrieve renderAudioClient from devicePtr
IAudioClient*& renderAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient;

@@ -4779,13 +4805,13 @@ bool RtApiWasapi::probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
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;
}

@@ -4925,6 +4951,7 @@ void RtApiWasapi::wasapiThread()
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;
@@ -4962,15 +4989,11 @@ void RtApiWasapi::wasapiThread()

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 ) ) {
@@ -4985,22 +5008,27 @@ void RtApiWasapi::wasapiThread()
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;
@@ -5047,15 +5075,11 @@ void RtApiWasapi::wasapiThread()

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 ) ) {
@@ -5308,7 +5332,7 @@ void RtApiWasapi::wasapiThread()
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


Loading…
Cancel
Save