summaryrefslogtreecommitdiff
path: root/RtAudio.cpp
diff options
context:
space:
mode:
authorGary Scavone <gary.scavone@mcgill.ca>2022-01-08 11:43:40 -0500
committerGary Scavone <gary.scavone@mcgill.ca>2022-01-08 11:43:40 -0500
commit732159db15f10819e985bd4e703e0feecf46ecff (patch)
treedf576a8f5031ad08e296648ce749608c3ea07980 /RtAudio.cpp
parente97f356e4a8f51aab949ebe7ed95e931cf013ed0 (diff)
First commit of WASAPI updates for new device selection (untested), plus a few other miscellaneous changes.
Diffstat (limited to 'RtAudio.cpp')
-rw-r--r--RtAudio.cpp580
1 files changed, 327 insertions, 253 deletions
diff --git a/RtAudio.cpp b/RtAudio.cpp
index 18c98df..c6444a6 100644
--- a/RtAudio.cpp
+++ b/RtAudio.cpp
@@ -826,7 +826,35 @@ void RtApiCore :: probeDevices( void )
}
}
- // Identification of default devices is handled by CoreAudio functions.
+ // Get default devices and set flags in deviceList_.
+ AudioDeviceID defaultOutputId, defaultInputId;
+ dataSize = sizeof( AudioDeviceID );
+ property.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
+ result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, &dataSize, &defaultOutputId );
+ if ( result != noErr ) {
+ errorText_ = "RtApiCore::probeDeviceInfo: OS-X system error getting default output device.";
+ error( RTAUDIO_WARNING );
+ defaultOutputId = 0;
+ }
+
+ property.mSelector = kAudioHardwarePropertyDefaultInputDevice;
+ result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, &dataSize, &defaultInputId );
+ if ( result != noErr ) {
+ errorText_ = "RtApiCore::probeDeviceInfo: OS-X system error getting default input device.";
+ error( RTAUDIO_WARNING );
+ defaultInputId = 0;
+ }
+
+ for ( m=0; m<deviceList_.size(); m++ ) {
+ if ( deviceIds_[m] == defaultOutputId )
+ deviceList_[m].isDefaultOutput = true;
+ else
+ deviceList_[m].isDefaultOutput = false;
+ if ( deviceIds_[m] == defaultInputId )
+ deviceList_[m].isDefaultInput = true;
+ else
+ deviceList_[m].isDefaultInput = false;
+ }
}
bool RtApiCore :: probeDeviceInfo( AudioDeviceID id, RtAudio::DeviceInfo& info )
@@ -1035,30 +1063,6 @@ bool RtApiCore :: probeDeviceInfo( AudioDeviceID id, RtAudio::DeviceInfo& info )
// no interest to the client.
info.nativeFormats = RTAUDIO_FLOAT32;
- AudioDeviceID defaultId;
- property.mScope = kAudioObjectPropertyScopeGlobal;
- dataSize = sizeof( AudioDeviceID );
- if ( info.outputChannels > 0 ) {
- property.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
- OSStatus result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, &dataSize, &defaultId );
- if ( result != noErr ) {
- errorText_ = "RtApiCore::probeDeviceInfo: OS-X system error getting default output device.";
- error( RTAUDIO_WARNING );
- return false;
- }
- if ( defaultId == id ) info.isDefaultOutput = true;
- }
- if ( info.inputChannels > 0 ) {
- property.mSelector = kAudioHardwarePropertyDefaultInputDevice;
- OSStatus result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, &dataSize, &defaultId );
- if ( result != noErr ) {
- errorText_ = "RtApiCore::probeDeviceInfo: OS-X system error getting default input device.";
- error( RTAUDIO_WARNING );
- return false;
- }
- if ( defaultId == id ) info.isDefaultInput = true;
- }
-
return true;
}
@@ -2290,7 +2294,10 @@ void RtApiJack :: probeDevices( void )
jack_client_close( client );
- if ( nDevices == 0 ) return;
+ if ( nDevices == 0 ) {
+ deviceList_.clear();
+ return;
+ }
// Jack doesn't provide default devices so call the getDefault
// functions, which will set the first available input and output
@@ -3014,25 +3021,6 @@ RtApiAsio :: ~RtApiAsio()
if ( coInitialized_ ) CoUninitialize();
}
-/*
-unsigned int RtApiAsio :: getDeviceCount( void )
-{
- return (unsigned int) drivers.asioGetNumDev();
-}
-
-// We can only load one ASIO driver, so the default output is always the first device.
-unsigned int RtApiAsio :: getDefaultOutputDevice( void )
-{
- return 0;
-}
-
-// We can only load one ASIO driver, so the default input is always the first device.
-unsigned int RtApiAsio :: getDefaultInputDevice( void )
-{
- return 0;
-}
-*/
-
void RtApiAsio :: probeDevices( void )
{
// See list of required functionality in RtApi::probeDevices().
@@ -4407,7 +4395,7 @@ struct WasapiHandle
renderEvent( NULL ) {}
};
-//=============================================================================
+//-----------------------------------------------------------------------------
RtApiWasapi::RtApiWasapi()
: coInitialized_( false ), deviceEnumerator_( NULL )
@@ -4441,173 +4429,314 @@ RtApiWasapi::~RtApiWasapi()
CoUninitialize();
}
-//=============================================================================
+//-----------------------------------------------------------------------------
-unsigned int RtApiWasapi::getDeviceCount( void )
+unsigned int RtApiWasapi::getDefaultInputDevice( void )
{
- unsigned int captureDeviceCount = 0;
- unsigned int renderDeviceCount = 0;
+ IMMDevice* devicePtr = NULL;
+ LPWSTR defaultId = NULL;
+ std::string id;
+
+ if ( !deviceEnumerator_ ) return 0; // invalid ID
+ errorText_.clear();
- IMMDeviceCollection* captureDevices = NULL;
- IMMDeviceCollection* renderDevices = NULL;
+ // Get the default capture device Id.
+ hr = deviceEnumerator_->GetDefaultAudioEndpoint( eCapture, eConsole, &devicePtr );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::getDefaultInputDevice: Unable to retrieve default capture device handle.";
+ goto Release;
+ }
+
+ hr = devicePtr->GetId( &defaultId );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::getDefaultInputDevice: Unable to get default capture device Id.";
+ goto Release;
+ }
+ id = defaultId;
- if ( !deviceEnumerator_ )
+ Release:
+ SAFE_RELEASE( devicePtr );
+ CoTaskMemFree( defaultId );
+
+ if ( !errorText_.empty() ) {
+ error( RTAUDIO_DRIVER_ERROR );
return 0;
+ }
- // Count capture devices
- errorText_.clear();
- HRESULT hr = deviceEnumerator_->EnumAudioEndpoints( eCapture, DEVICE_STATE_ACTIVE, &captureDevices );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::getDeviceCount: Unable to retrieve capture device collection.";
- goto Exit;
+ for ( unsigned int m=0; m<deviceIds_.size(); m++ ) {
+ if ( deviceIds_[m].first == id ) {
+ if ( deviceList_[m].isDefaultInput == false ) {
+ deviceList_[m].isDefaultInput = true;
+ for ( unsigned int j=m+1; j<deviceIds_.size(); j++ ) {
+ // make sure any remaining devices are not listed as the default
+ deviceList_[j].isDefaultInput = false;
+ }
+ }
+ return deviceList_[m].ID;
+ }
+ deviceList_[m].isDefaultInput = false;
}
- hr = captureDevices->GetCount( &captureDeviceCount );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::getDeviceCount: Unable to retrieve capture device count.";
- goto Exit;
+ // If not found above, then do system probe of devices and try again.
+ probeDevices();
+ for ( unsigned int m=0; m<deviceIds_.size(); m++ ) {
+ if ( deviceIds_[m].first == id ) return deviceList_[m].ID;
}
- // Count render devices
- hr = deviceEnumerator_->EnumAudioEndpoints( eRender, DEVICE_STATE_ACTIVE, &renderDevices );
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+
+unsigned int RtApiWasapi::getDefaultOutputDevice( void )
+{
+ IMMDevice* devicePtr = NULL;
+ LPWSTR defaultId = NULL;
+ std::string id;
+
+ if ( !deviceEnumerator_ ) return 0; // invalid ID
+ errorText_.clear();
+
+ // Get the default render device Id.
+ hr = deviceEnumerator_->GetDefaultAudioEndpoint( eRender, eConsole, &devicePtr );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::getDeviceCount: Unable to retrieve render device collection.";
- goto Exit;
+ errorText_ = "RtApiWasapi::getDefaultOutputDevice: Unable to retrieve default render device handle.";
+ goto Release;
}
- hr = renderDevices->GetCount( &renderDeviceCount );
+ hr = devicePtr->GetId( &defaultId );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::getDeviceCount: Unable to retrieve render device count.";
- goto Exit;
+ errorText_ = "RtApiWasapi::getDefaultOutputDevice: Unable to get default render device Id.";
+ goto Release;
}
+ id = defaultId;
-Exit:
- // release all references
- SAFE_RELEASE( captureDevices );
- SAFE_RELEASE( renderDevices );
+ Release:
+ SAFE_RELEASE( devicePtr );
+ CoTaskMemFree( defaultId );
+
+ if ( !errorText_.empty() ) {
+ error( RTAUDIO_DRIVER_ERROR );
+ return 0;
+ }
+
+ for ( unsigned int m=0; m<deviceIds_.size(); m++ ) {
+ if ( deviceIds_[m].first == id ) {
+ if ( deviceList_[m].isDefaultOutput == false ) {
+ deviceList_[m].isDefaultOutput = true;
+ for ( unsigned int j=m+1; j<deviceIds_.size(); j++ ) {
+ // make sure any remaining devices are not listed as the default
+ deviceList_[j].isDefaultOutput = false;
+ }
+ }
+ return deviceList_[m].ID;
+ }
+ deviceList_[m].isDefaultOutput = false;
+ }
- if ( errorText_.empty() )
- return captureDeviceCount + renderDeviceCount;
+ // If not found above, then do system probe of devices and try again.
+ probeDevices();
+ for ( unsigned int m=0; m<deviceIds_.size(); m++ ) {
+ if ( deviceIds_[m].first == id ) return deviceList_[m].ID;
+ }
- error( RTAUDIO_DRIVER_ERROR );
return 0;
}
//-----------------------------------------------------------------------------
-RtAudio::DeviceInfo RtApiWasapi::getDeviceInfo( unsigned int device )
+void RtApiWasapi::probeDevices( void )
{
- RtAudio::DeviceInfo info;
unsigned int captureDeviceCount = 0;
unsigned int renderDeviceCount = 0;
- std::string defaultDeviceName;
- bool isCaptureDevice = false;
-
- PROPVARIANT deviceNameProp;
- PROPVARIANT defaultDeviceNameProp;
-
+
IMMDeviceCollection* captureDevices = NULL;
IMMDeviceCollection* renderDevices = NULL;
IMMDevice* devicePtr = NULL;
- IMMDevice* defaultDevicePtr = NULL;
- IAudioClient* audioClient = NULL;
- IPropertyStore* devicePropStore = NULL;
- IPropertyStore* defaultDevicePropStore = NULL;
-
- WAVEFORMATEX* deviceFormat = NULL;
- WAVEFORMATEX* closestMatchFormat = NULL;
- // probed
- info.probed = false;
+ LPWSTR defaultCaptureId = NULL;
+ LPWSTR defaultRenderId = NULL;
- // Count capture devices
+ if ( !deviceEnumerator_ ) return;
errorText_.clear();
- RtAudioErrorType errorType = RTAUDIO_DRIVER_ERROR;
+
+ // Count capture devices
HRESULT hr = deviceEnumerator_->EnumAudioEndpoints( eCapture, DEVICE_STATE_ACTIVE, &captureDevices );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve capture device collection.";
+ errorText_ = "RtApiWasapi::probeDevices: Unable to retrieve capture device collection.";
goto Exit;
}
hr = captureDevices->GetCount( &captureDeviceCount );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve capture device count.";
+ errorText_ = "RtApiWasapi::probeDevices: Unable to retrieve capture device count.";
goto Exit;
}
// Count render devices
hr = deviceEnumerator_->EnumAudioEndpoints( eRender, DEVICE_STATE_ACTIVE, &renderDevices );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve render device collection.";
+ errorText_ = "RtApiWasapi::probeDevices: Unable to retrieve render device collection.";
goto Exit;
}
hr = renderDevices->GetCount( &renderDeviceCount );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve render device count.";
+ errorText_ = "RtApiWasapi::probeDevices: Unable to retrieve render device count.";
goto Exit;
}
- // validate device index
- if ( device >= captureDeviceCount + renderDeviceCount ) {
- errorText_ = "RtApiWasapi::getDeviceInfo: Invalid device index.";
- errorType = RTAUDIO_INVALID_USE;
+ unsigned int nDevices = captureDeviceCount + renderDeviceCount;
+ if ( nDevices == 0 ) {
+ errorText_ = "RtApiWasapi::probeDevices: No devices found.";
goto Exit;
}
- // determine whether index falls within capture or render devices
- if ( device >= renderDeviceCount ) {
- hr = captureDevices->Item( device - renderDeviceCount, &devicePtr );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve capture device handle.";
- goto Exit;
- }
- isCaptureDevice = true;
+ // Get the default capture device Id.
+ hr = deviceEnumerator_->GetDefaultAudioEndpoint( eCapture, eConsole, &devicePtr );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::probeDevices: Unable to retrieve default capture device handle.";
+ goto Exit;
}
- else {
- hr = renderDevices->Item( device, &devicePtr );
+
+ hr = devicePtr->GetId( &defaultCaptureId );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::probeDevices: Unable to get default capture device Id.";
+ goto Exit;
+ }
+
+ // Get the default render device Id.
+ SAFE_RELEASE( devicePtr );
+ hr = deviceEnumerator_->GetDefaultAudioEndpoint( eRender, eConsole, &devicePtr );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::probeDevices: Unable to retrieve default render device handle.";
+ goto Exit;
+ }
+
+ hr = devicePtr->GetId( &defaultRenderId );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::probeDevices: Unable to get default render device Id.";
+ goto Exit;
+ }
+
+ // Collect device IDs with mode.
+ std::vector< std::pair< std::string, bool> > ids;
+ LPWSTR deviceId = NULL;
+ bool isCaptureDevice = false;
+ for ( unsigned int n=0; n<nDevices; n++ ) {
+ SAFE_RELEASE( devicePtr );
+ if ( n < renderDeviceCount ) {
+ hr = renderDevices->Item( n, &devicePtr );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::probeDevices: Unable to retrieve render device handle.";
+ error( RTAUDIO_WARNING );
+ continue;
+ }
+ }
+ else {
+ hr = captureDevices->Item( n - renderDeviceCount, &devicePtr );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::probeDevices: Unable to retrieve capture device handle.";
+ error( RTAUDIO_WARNING );
+ continue;
+ }
+ isCaptureDevice = true;
+ }
+
+ hr = devicePtr->GetId( &deviceId );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve render device handle.";
- goto Exit;
+ errorText_ = "RtApiWasapi::probeDevices: Unable to get device Id.";
+ error( RTAUDIO_WARNING );
+ continue;
}
- isCaptureDevice = false;
+ ids.push_back( std::pair< deviceId, isCaptureDevice > );
+ CoTaskMemFree( deviceId );
}
- // get default device name
- if ( isCaptureDevice ) {
- hr = deviceEnumerator_->GetDefaultAudioEndpoint( eCapture, eConsole, &defaultDevicePtr );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve default capture device handle.";
- goto Exit;
+ // Fill or update the deviceList_ and also save a corresponding list of Ids.
+ for ( unsigned int n=0; n<ids.size(); n++ ) {
+ if ( std::find( deviceIds_.begin(), deviceIds_.end(), ids[n] ) != deviceIds_.end() ) {
+ continue; // We already have this device.
+ }
+ else { // There is a new device to probe.
+ RtAudio::DeviceInfo info;
+ if ( probeDeviceInfo( info, ids[n].first, ids[n].second ) == false ) continue; // ignore if probe fails
+ deviceIds_.push_back( ids[n] );
+ info.ID = currentDeviceId_++; // arbitrary internal device ID
+ deviceList_.push_back( info );
}
}
- else {
- hr = deviceEnumerator_->GetDefaultAudioEndpoint( eRender, eConsole, &defaultDevicePtr );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve default render device handle.";
- goto Exit;
+
+ // Remove any devices left in the list that are no longer available.
+ unsigned int m;
+ for ( std::vector< std::string >::iterator it=deviceIds_.begin(); it!=deviceIds_.end(); ) {
+ for ( m=0; m<ids.size(); m++ ) {
+ if ( ids[m] == *it ) {
+ ++it;
+ break;
+ }
+ }
+ if ( m == ids.size() ) { // not found so remove it from our two lists
+ it = deviceIds_.erase(it);
+ deviceList_.erase( deviceList_.begin() + distance(deviceIds_.begin(), it ) );
}
}
- hr = defaultDevicePtr->OpenPropertyStore( STGM_READ, &defaultDevicePropStore );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::getDeviceInfo: Unable to open default device property store.";
- goto Exit;
+ // Set the default device flags in deviceList_.
+ for ( m=0; m<deviceList_.size(); m++ ) {
+ if ( deviceIds_[m] == defaultRenderId )
+ deviceList_[m].isDefaultOutput = true;
+ else
+ deviceList_[m].isDefaultOutput = false;
+ if ( deviceIds_[m] == defaultCaptureId )
+ deviceList_[m].isDefaultInput = true;
+ else
+ deviceList_[m].isDefaultInput = false;
+ }
+
+ Exit:
+ // Release all references
+ SAFE_RELEASE( captureDevices );
+ SAFE_RELEASE( renderDevices );
+ SAFE_RELEASE( devicePtr );
+
+ CoTaskMemFree( defaultCaptureId );
+ CoTaskMemFree( defaultRenderId );
+
+ if ( !errorText_.empty() ) {
+ deviceList_.clear();
+ deviceIds_.clear();
+ error( RTAUDIO_DRIVER_ERROR );
}
- PropVariantInit( &defaultDeviceNameProp );
+ return;
+}
+
+//-----------------------------------------------------------------------------
+
+bool RtApiWasapi::probeDeviceInfo( RtAudio::DeviceInfo &info, LPWSTR deviceId, bool isCaptureDevice )
+{
+ PROPVARIANT deviceNameProp;
+ IMMDevice* devicePtr = NULL;
+ IAudioClient* audioClient = NULL;
+ IPropertyStore* devicePropStore = NULL;
+
+ WAVEFORMATEX* deviceFormat = NULL;
+ WAVEFORMATEX* closestMatchFormat = NULL;
+
+ errorText_.clear();
+ RtAudioErrorType errorType = RTAUDIO_DRIVER_ERROR;
- hr = defaultDevicePropStore->GetValue( PKEY_Device_FriendlyName, &defaultDeviceNameProp );
+ // Get the device pointer from the device Id
+ HRESULT hr = GetDevice( deviceId, &devicePtr );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve default device property: PKEY_Device_FriendlyName.";
+ errorText_ = "RtApiWasapi::probeDeviceInfo: Unable to retrieve device handle.";
goto Exit;
}
- defaultDeviceName = convertCharPointerToStdString(defaultDeviceNameProp.pwszVal);
-
- // name
+ // Get device name
hr = devicePtr->OpenPropertyStore( STGM_READ, &devicePropStore );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::getDeviceInfo: Unable to open device property store.";
+ errorText_ = "RtApiWasapi::probeDeviceInfo: Unable to open device property store.";
goto Exit;
}
@@ -4615,35 +4744,26 @@ RtAudio::DeviceInfo RtApiWasapi::getDeviceInfo( unsigned int device )
hr = devicePropStore->GetValue( PKEY_Device_FriendlyName, &deviceNameProp );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve device property: PKEY_Device_FriendlyName.";
+ errorText_ = "RtApiWasapi::probeDeviceInfo: Unable to retrieve device property: PKEY_Device_FriendlyName.";
goto Exit;
}
- info.name =convertCharPointerToStdString(deviceNameProp.pwszVal);
-
- // is default
- if ( isCaptureDevice ) {
- info.isDefaultInput = info.name == defaultDeviceName;
- info.isDefaultOutput = false;
- }
- else {
- info.isDefaultInput = false;
- info.isDefaultOutput = info.name == defaultDeviceName;
- }
+ info.name = convertCharPointerToStdString( deviceNameProp.pwszVal );
- // channel count
+ // Get audio client
hr = devicePtr->Activate( __uuidof( IAudioClient ), CLSCTX_ALL, NULL, ( void** ) &audioClient );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve device audio client.";
+ errorText_ = "RtApiWasapi::probeDeviceInfo: Unable to retrieve device audio client.";
goto Exit;
}
hr = audioClient->GetMixFormat( &deviceFormat );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve device mix format.";
+ errorText_ = "RtApiWasapi::probeDeviceInfo: Unable to retrieve device mix format.";
goto Exit;
}
+ // Set channel count
if ( isCaptureDevice ) {
info.inputChannels = deviceFormat->nChannels;
info.outputChannels = 0;
@@ -4655,16 +4775,16 @@ RtAudio::DeviceInfo RtApiWasapi::getDeviceInfo( unsigned int device )
info.duplexChannels = 0;
}
- // sample rates
+ // Set sample rates
info.sampleRates.clear();
- // allow support for all sample rates as we have a built-in sample rate converter
+ // Allow support for all sample rates as we have a built-in sample rate converter.
for ( unsigned int i = 0; i < MAX_SAMPLE_RATES; i++ ) {
info.sampleRates.push_back( SAMPLE_RATES[i] );
}
info.preferredSampleRate = deviceFormat->nSamplesPerSec;
- // native format
+ // Set native formats
info.nativeFormats = 0;
if ( deviceFormat->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
@@ -4679,8 +4799,8 @@ RtAudio::DeviceInfo RtApiWasapi::getDeviceInfo( unsigned int device )
}
}
else if ( deviceFormat->wFormatTag == WAVE_FORMAT_PCM ||
- ( deviceFormat->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
- ( ( WAVEFORMATEXTENSIBLE* ) deviceFormat )->SubFormat == KSDATAFORMAT_SUBTYPE_PCM ) )
+ ( deviceFormat->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
+ ( ( WAVEFORMATEXTENSIBLE* ) deviceFormat )->SubFormat == KSDATAFORMAT_SUBTYPE_PCM ) )
{
if ( deviceFormat->wBitsPerSample == 8 ) {
info.nativeFormats |= RTAUDIO_SINT8;
@@ -4696,28 +4816,22 @@ RtAudio::DeviceInfo RtApiWasapi::getDeviceInfo( unsigned int device )
}
}
- // probed
- info.probed = true;
-
-Exit:
- // release all references
+ Exit:
+ // Release all references
PropVariantClear( &deviceNameProp );
- PropVariantClear( &defaultDeviceNameProp );
- SAFE_RELEASE( captureDevices );
- SAFE_RELEASE( renderDevices );
SAFE_RELEASE( devicePtr );
- SAFE_RELEASE( defaultDevicePtr );
SAFE_RELEASE( audioClient );
SAFE_RELEASE( devicePropStore );
- SAFE_RELEASE( defaultDevicePropStore );
CoTaskMemFree( deviceFormat );
CoTaskMemFree( closestMatchFormat );
- if ( !errorText_.empty() )
+ if ( !errorText_.empty() ) {
error( errorType );
- return info;
+ return false;
+ }
+ return true;
}
void RtApiWasapi::closeStream( void )
@@ -4854,78 +4968,56 @@ RtAudioErrorType RtApiWasapi::abortStream( void )
//-----------------------------------------------------------------------------
-bool RtApiWasapi::probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
+bool RtApiWasapi::probeDeviceOpen( unsigned int deviceId, StreamMode mode, unsigned int channels,
unsigned int firstChannel, unsigned int sampleRate,
RtAudioFormat format, unsigned int* bufferSize,
RtAudio::StreamOptions* options )
{
bool methodResult = FAILURE;
- unsigned int captureDeviceCount = 0;
- unsigned int renderDeviceCount = 0;
-
- IMMDeviceCollection* captureDevices = NULL;
- IMMDeviceCollection* renderDevices = NULL;
IMMDevice* devicePtr = NULL;
WAVEFORMATEX* deviceFormat = NULL;
unsigned int bufferBytes;
stream_.state = STREAM_STOPPED;
+ bool isInput = false;
+ std::string id;
- // create API Handle if not already created
- if ( !stream_.apiHandle )
- stream_.apiHandle = ( void* ) new WasapiHandle();
-
- // Count capture devices
- errorText_.clear();
- RtAudioErrorType errorType = RTAUDIO_DRIVER_ERROR;
- HRESULT hr = deviceEnumerator_->EnumAudioEndpoints( eCapture, DEVICE_STATE_ACTIVE, &captureDevices );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve capture device collection.";
- goto Exit;
+ unsigned int deviceIdx;
+ for ( deviceIdx=0; deviceIdx<deviceList_.size(); deviceIdx++ ) {
+ if ( deviceList_[deviceIdx].ID == deviceId ) {
+ id = deviceIds_[deviceIdx].first;
+ if ( deviceIds_[deviceIdx].second ) isInput = true;
+ break;
+ }
}
- hr = captureDevices->GetCount( &captureDeviceCount );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve capture device count.";
- goto Exit;
+ if ( id.empty() ) {
+ errorText_ = "RtApiWasapi::probeDeviceOpen: the device ID was not found!";
+ return FAILURE;
}
- // Count render devices
- hr = deviceEnumerator_->EnumAudioEndpoints( eRender, DEVICE_STATE_ACTIVE, &renderDevices );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve render device collection.";
- goto Exit;
+ if ( isInput && mode != INPUT ) {
+ errorType = RTAUDIO_INVALID_USE;
+ errorText_ = "RtApiWasapi::probeDeviceOpen: deviceId specified does not support output mode.";
+ return FAILURE;
}
- hr = renderDevices->GetCount( &renderDeviceCount );
+ // Get the device pointer from the device Id
+ HRESULT hr = GetDevice( id.c_str(), &devicePtr );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve render device count.";
- goto Exit;
- }
-
- // validate device index
- if ( device >= captureDeviceCount + renderDeviceCount ) {
- errorType = RTAUDIO_INVALID_USE;
- errorText_ = "RtApiWasapi::probeDeviceOpen: Invalid device index.";
- goto Exit;
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve device handle.";
+ return FAILURE;
}
+
+ // Create API handle if not already created.
+ if ( !stream_.apiHandle )
+ stream_.apiHandle = ( void* ) new WasapiHandle();
- // if device index falls within capture devices
- if ( device >= renderDeviceCount ) {
- if ( mode != INPUT ) {
- errorType = RTAUDIO_INVALID_USE;
- errorText_ = "RtApiWasapi::probeDeviceOpen: Capture device selected as output device.";
- goto Exit;
- }
+ errorText_.clear();
+ RtAudioErrorType errorType = RTAUDIO_DRIVER_ERROR;
- // retrieve captureAudioClient from devicePtr
+ if ( isInput ) {
IAudioClient*& captureAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient;
- hr = captureDevices->Item( device - renderDeviceCount, &devicePtr );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve capture device handle.";
- goto Exit;
- }
-
hr = devicePtr->Activate( __uuidof( IAudioClient ), CLSCTX_ALL,
NULL, ( void** ) &captureAudioClient );
if ( FAILED( hr ) ) {
@@ -4943,25 +5035,17 @@ bool RtApiWasapi::probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
captureAudioClient->GetStreamLatency( ( long long* ) &stream_.latency[mode] );
}
- // 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
+ // If an output device and is configured for loopback (input mode)
+ if ( isInput == false && 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 );
+ if ( !renderAudioClient ) {
+ probeDeviceOpen( deviceId, OUTPUT, channels, firstChannel, sampleRate, format, bufferSize, options );
}
- // retrieve captureAudioClient from devicePtr
+ // Retrieve captureAudioClient from our stream handle.
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 ) ) {
@@ -4979,23 +5063,15 @@ bool RtApiWasapi::probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
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
+ // If output device and is configured for output.
+ if ( isInput == false && mode == OUTPUT ) {
+ // If renderAudioClient is already initialised, don't initialise it again
IAudioClient*& renderAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient;
- if ( renderAudioClient )
- {
+ if ( renderAudioClient ) {
methodResult = SUCCESS;
goto Exit;
}
- 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** ) &renderAudioClient );
if ( FAILED( hr ) ) {
@@ -5013,7 +5089,7 @@ bool RtApiWasapi::probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
renderAudioClient->GetStreamLatency( ( long long* ) &stream_.latency[mode] );
}
- // fill stream data
+ // Fill stream data
if ( ( stream_.mode == OUTPUT && mode == INPUT ) ||
( stream_.mode == INPUT && mode == OUTPUT ) ) {
stream_.mode = DUPLEX;
@@ -5022,7 +5098,7 @@ bool RtApiWasapi::probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
stream_.mode = mode;
}
- stream_.device[mode] = device;
+ stream_.deviceId[mode] = deviceId;
stream_.doByteSwap[mode] = false;
stream_.sampleRate = sampleRate;
stream_.bufferSize = *bufferSize;
@@ -5030,7 +5106,7 @@ bool RtApiWasapi::probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
stream_.nUserChannels[mode] = channels;
stream_.channelOffset[mode] = firstChannel;
stream_.userFormat = format;
- stream_.deviceFormat[mode] = getDeviceInfo( device ).nativeFormats;
+ stream_.deviceFormat[mode] = deviceList_[deviceIdx].nativeFormats;
if ( options && options->flags & RTAUDIO_NONINTERLEAVED )
stream_.userInterleaved = false;
@@ -5071,10 +5147,8 @@ bool RtApiWasapi::probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
methodResult = SUCCESS;
-Exit:
+ Exit:
//clean up
- SAFE_RELEASE( captureDevices );
- SAFE_RELEASE( renderDevices );
SAFE_RELEASE( devicePtr );
CoTaskMemFree( deviceFormat );