From b6edd70a7d12674f57a66ac6341572e4c274a704 Mon Sep 17 00:00:00 2001 From: garyscavone Date: Wed, 23 Aug 2023 10:15:04 -0400 Subject: [PATCH 01/15] Update for Pulse input to achieve better latency. --- RtAudio.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/RtAudio.cpp b/RtAudio.cpp index b13f04eb..0a55be12 100644 --- a/RtAudio.cpp +++ b/RtAudio.cpp @@ -9521,7 +9521,10 @@ bool RtApiPulse::probeDeviceOpen( unsigned int deviceId, StreamMode mode, pa_buffer_attr buffer_attr; case INPUT: buffer_attr.fragsize = bufferBytes; - buffer_attr.maxlength = -1; + if ( options && options->numberOfBuffers > 0 ) + buffer_attr.maxlength = bufferBytes * (options->numberOfBuffers + 1); + else + buffer_attr.maxlength = bufferBytes * 4; pah->s_rec = pa_simple_new( NULL, streamName.c_str(), PA_STREAM_RECORD, dev_input, "Record", &ss, NULL, &buffer_attr, &error ); From 6c043b45b214ecdee1618da16de57a1dceb11ac8 Mon Sep 17 00:00:00 2001 From: Paul Walker Date: Sat, 16 Sep 2023 08:52:06 -0400 Subject: [PATCH 02/15] Move include(CTest) to inside testing guard The RTAUDIO_BUILD_TESTING variable stops the testing target ejection but still does an include(CTest) which injects the standard CTest macros from enable_testing(). In rtmidi you include(CTest) inside the guard but in rtaudio you do not; as such using the cmake in a non-ctest project ejects multiple targets. For now you can get around this with BUILD_TESTING globally off but that means you can't activate your own ctests optionally. So move the include(CTEst) to be in the same spot as it is in rtmidi. Thanks for great software! --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3bea3710..1be49c9a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -280,12 +280,12 @@ target_compile_definitions(rtaudio PRIVATE RTAUDIO_EXPORT) target_link_libraries(rtaudio ${LINKLIBS}) # Subdirs -include(CTest) if (NOT DEFINED RTAUDIO_BUILD_TESTING OR RTAUDIO_BUILD_TESTING STREQUAL "") set(RTAUDIO_BUILD_TESTING ${BUILD_TESTING}) endif() if (RTAUDIO_BUILD_TESTING) + include(CTest) add_subdirectory(tests) endif() From b0e3374923399486380c014035f33ad25b713ce6 Mon Sep 17 00:00:00 2001 From: Mike Dickey Date: Wed, 10 Jan 2024 15:52:37 -0800 Subject: [PATCH 03/15] Remove CoreAudio device disconnect listener when closing input mode streams The flag handle->disconnectListenerAdded[0] is never set to true for input mode streams because the probeOpenStream() code uses handle->disconnectListenerAdded[mode]. This causes RtAudio to never remove device disconnect listeners, which can cause the listener slots to fill up and an "illegal instruction" error code to be returned when you try to add a new one. --- RtAudio.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RtAudio.cpp b/RtAudio.cpp index 0a55be12..bbe25399 100644 --- a/RtAudio.cpp +++ b/RtAudio.cpp @@ -1981,7 +1981,7 @@ void RtApiCore :: closeStream( void ) } } - if ( handle->disconnectListenerAdded[0] ) { + if ( handle->disconnectListenerAdded[1] ) { property.mSelector = kAudioDevicePropertyDeviceIsAlive; if (AudioObjectRemovePropertyListener( handle->id[1], &property, streamDisconnectListener, (void *) &stream_.callbackInfo ) != noErr) { errorText_ = "RtApiCore::closeStream(): error removing disconnect property listener!"; From adf2812d5741aa20eda37deeb6cfd9d335b26f2a Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Fri, 2 Feb 2024 22:52:09 +0000 Subject: [PATCH 04/15] Fixed MY_TYPE for RTAUDIO_SINT32 so that it's int32_t as `long` is 64-bit on some 64-bit systems Closes https://github.com/thestk/rtaudio/issues/420 --- tests/duplex.cpp | 2 +- tests/playsaw.cpp | 2 +- tests/record.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/duplex.cpp b/tests/duplex.cpp index 1257eea5..24609f88 100644 --- a/tests/duplex.cpp +++ b/tests/duplex.cpp @@ -25,7 +25,7 @@ typedef signed short MY_TYPE; typedef S24 MY_TYPE; #define FORMAT RTAUDIO_SINT24 -typedef signed long MY_TYPE; +typedef int32_t MY_TYPE; #define FORMAT RTAUDIO_SINT32 typedef float MY_TYPE; diff --git a/tests/playsaw.cpp b/tests/playsaw.cpp index c23163ef..ddef6689 100644 --- a/tests/playsaw.cpp +++ b/tests/playsaw.cpp @@ -28,7 +28,7 @@ typedef S24 MY_TYPE; #define FORMAT RTAUDIO_SINT24 #define SCALE 8388607.0 -typedef signed long MY_TYPE; +typedef int32_t MY_TYPE; #define FORMAT RTAUDIO_SINT32 #define SCALE 2147483647.0 diff --git a/tests/record.cpp b/tests/record.cpp index c5f9cb51..5bd56186 100644 --- a/tests/record.cpp +++ b/tests/record.cpp @@ -27,7 +27,7 @@ typedef signed short MY_TYPE; typedef S24 MY_TYPE; #define FORMAT RTAUDIO_SINT24 -typedef signed long MY_TYPE; +typedef int32_t MY_TYPE; #define FORMAT RTAUDIO_SINT32 typedef float MY_TYPE; From 422d8b81b61bb4b261a36b4b7e3877f73fb5bef3 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Fri, 2 Feb 2024 22:53:40 +0000 Subject: [PATCH 05/15] Use fixed-width integer types for MY_TYPE in examples for clarity and future compatibility --- tests/duplex.cpp | 4 ++-- tests/playraw.cpp | 6 +++--- tests/playsaw.cpp | 4 ++-- tests/record.cpp | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/duplex.cpp b/tests/duplex.cpp index 24609f88..1d680b0b 100644 --- a/tests/duplex.cpp +++ b/tests/duplex.cpp @@ -14,11 +14,11 @@ #include /* -typedef char MY_TYPE; +typedef int8_t MY_TYPE; #define FORMAT RTAUDIO_SINT8 */ -typedef signed short MY_TYPE; +typedef int16_t MY_TYPE; #define FORMAT RTAUDIO_SINT16 /* diff --git a/tests/playraw.cpp b/tests/playraw.cpp index 8a15a960..7f6ccc9b 100644 --- a/tests/playraw.cpp +++ b/tests/playraw.cpp @@ -16,12 +16,12 @@ #include /* -typedef char MY_TYPE; +typedef int8_t MY_TYPE; #define FORMAT RTAUDIO_SINT8 #define SCALE 127.0 */ -typedef signed short MY_TYPE; +typedef int16_t MY_TYPE; #define FORMAT RTAUDIO_SINT16 #define SCALE 32767.0 @@ -30,7 +30,7 @@ typedef S24 MY_TYPE; #define FORMAT RTAUDIO_SINT24 #define SCALE 8388607.0 -typedef signed int MY_TYPE; +typedef int32_t MY_TYPE; #define FORMAT RTAUDIO_SINT32 #define SCALE 2147483647.0 diff --git a/tests/playsaw.cpp b/tests/playsaw.cpp index ddef6689..ee61f064 100644 --- a/tests/playsaw.cpp +++ b/tests/playsaw.cpp @@ -14,12 +14,12 @@ #include /* -typedef char MY_TYPE; +typedef int8_t MY_TYPE; #define FORMAT RTAUDIO_SINT8 #define SCALE 127.0 */ -typedef signed short MY_TYPE; +typedef int16_t MY_TYPE; #define FORMAT RTAUDIO_SINT16 #define SCALE 32767.0 diff --git a/tests/record.cpp b/tests/record.cpp index 5bd56186..06d398c9 100644 --- a/tests/record.cpp +++ b/tests/record.cpp @@ -16,11 +16,11 @@ #include /* -typedef char MY_TYPE; +typedef int8_t MY_TYPE; #define FORMAT RTAUDIO_SINT8 */ -typedef signed short MY_TYPE; +typedef int16_t MY_TYPE; #define FORMAT RTAUDIO_SINT16 /* From 992904560ce0b0b1a9210287970c88ff9d99d3c2 Mon Sep 17 00:00:00 2001 From: Mike Dickey Date: Sun, 11 Feb 2024 15:08:57 -0800 Subject: [PATCH 06/15] Use correct number of channels for the selected CoreAudio stream The kAudioStreamPropertyPhysicalFormat query returns the number of channels for the device's first audio stream. If any single, subsequent stream is selected to fulfill the user request, it may use a different number of channels. This mismatch can cause a lot of problems. --- RtAudio.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RtAudio.cpp b/RtAudio.cpp index bbe25399..bc61c545 100644 --- a/RtAudio.cpp +++ b/RtAudio.cpp @@ -1782,7 +1782,7 @@ bool RtApiCore :: probeDeviceOpen( unsigned int deviceId, StreamMode mode, unsig stream_.deviceFormat[mode] = RTAUDIO_FLOAT32; if ( streamCount == 1 ) - stream_.nDeviceChannels[mode] = description.mChannelsPerFrame; + stream_.nDeviceChannels[mode] = streamChannels; else // multiple streams stream_.nDeviceChannels[mode] = channels; stream_.nUserChannels[mode] = channels; From b8d09eca9a7249f064140baf4fda4c928b5c9472 Mon Sep 17 00:00:00 2001 From: Jerry Evans Date: Sat, 6 Apr 2024 17:23:56 +0100 Subject: [PATCH 07/15] Fix convertCharPointerToStdString with MSC_VER guard --- RtAudio.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/RtAudio.cpp b/RtAudio.cpp index bc61c545..b7459be0 100644 --- a/RtAudio.cpp +++ b/RtAudio.cpp @@ -72,9 +72,24 @@ std::string convertCharPointerToStdString(const char *text) } template<> inline -std::string convertCharPointerToStdString(const wchar_t *text) +std::string convertCharPointerToStdString(const wchar_t* text) { +#if defined(_MSC_VER) + if (!text) + return std::string(); + const int wchars = (int)wcslen(text); + // how many characters are required after conversion? + const int nchars = WideCharToMultiByte(CP_UTF8, 0, text, wchars, 0, 0, 0, 0); + if (!nchars) + return std::string(); + // create buffer + std::string nret(nchars, 0); + // do the conversion + WideCharToMultiByte(CP_UTF8, 0, text, wchars, &nret[0], nchars, 0, 0); + return nret; +#else return std::wstring_convert>{}.to_bytes(text); +#endif } #if defined(_MSC_VER) From 028484cb8185b42c1cecfb616cca86972180791b Mon Sep 17 00:00:00 2001 From: Lalit Shankar Chowdhury Date: Thu, 16 May 2024 13:34:14 +0530 Subject: [PATCH 08/15] Use COM smart pointers in WASAPI driver --- RtAudio.cpp | 127 +++++++++++++++++----------------------------------- 1 file changed, 42 insertions(+), 85 deletions(-) diff --git a/RtAudio.cpp b/RtAudio.cpp index b7459be0..db4f1afa 100644 --- a/RtAudio.cpp +++ b/RtAudio.cpp @@ -52,6 +52,8 @@ #include #if defined(_WIN32) +#include +using Microsoft::WRL::ComPtr; #include #endif @@ -273,7 +275,7 @@ class RtApiWasapi : public RtApi private: bool coInitialized_; - IMMDeviceEnumerator* deviceEnumerator_; + ComPtr deviceEnumerator_; std::vector< std::pair< std::string, bool> > deviceIds_; void probeDevices( void ) override; @@ -4637,17 +4639,17 @@ class WasapiResampler _mediaType->SetUINT32( MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE ); MFCreateMediaType( &_inputMediaType ); - _mediaType->CopyAllItems( _inputMediaType ); + _mediaType->CopyAllItems( _inputMediaType.Get() ); - _transform->SetInputType( 0, _inputMediaType, 0 ); + _transform->SetInputType( 0, _inputMediaType.Get(), 0 ); MFCreateMediaType( &_outputMediaType ); - _mediaType->CopyAllItems( _outputMediaType ); + _mediaType->CopyAllItems( _outputMediaType.Get() ); _outputMediaType->SetUINT32( MF_MT_AUDIO_SAMPLES_PER_SECOND, outSampleRate ); _outputMediaType->SetUINT32( MF_MT_AUDIO_AVG_BYTES_PER_SECOND, _bytesPerSample * channelCount * outSampleRate ); - _transform->SetOutputType( 0, _outputMediaType, 0 ); + _transform->SetOutputType( 0, _outputMediaType.Get(), 0 ); // 4. Send stream start messages to Resampler @@ -4666,16 +4668,6 @@ class WasapiResampler // 9. Cleanup MFShutdown(); - - SAFE_RELEASE( _transformUnk ); - SAFE_RELEASE( _transform ); - SAFE_RELEASE( _mediaType ); - SAFE_RELEASE( _inputMediaType ); - SAFE_RELEASE( _outputMediaType ); - - #ifdef __IWMResamplerProps_FWD_DEFINED__ - SAFE_RELEASE( _resamplerProps ); - #endif } void Convert( char* outBuffer, const char* inBuffer, unsigned int inSampleCount, unsigned int& outSampleCount, int maxOutSampleCount = -1 ) @@ -4699,8 +4691,8 @@ class WasapiResampler outputBufferSize = ( unsigned int ) ceilf( inputBufferSize * _sampleRatio ) + ( _bytesPerSample * _channelCount ); } - IMFMediaBuffer* rInBuffer; - IMFSample* rInSample; + ComPtr rInBuffer; + ComPtr rInSample; BYTE* rInByteBuffer = NULL; // 5. Create Sample object from input data @@ -4715,18 +4707,15 @@ class WasapiResampler rInBuffer->SetCurrentLength( inputBufferSize ); MFCreateSample( &rInSample ); - rInSample->AddBuffer( rInBuffer ); + rInSample->AddBuffer( rInBuffer.Get() ); // 6. Pass input data to Resampler - _transform->ProcessInput( 0, rInSample, 0 ); - - SAFE_RELEASE( rInBuffer ); - SAFE_RELEASE( rInSample ); + _transform->ProcessInput( 0, rInSample.Get(), 0 ); // 7. Perform sample rate conversion - IMFMediaBuffer* rOutBuffer = NULL; + ComPtr rOutBuffer = NULL; BYTE* rOutByteBuffer = NULL; MFT_OUTPUT_DATA_BUFFER rOutDataBuffer; @@ -4738,7 +4727,7 @@ class WasapiResampler memset( &rOutDataBuffer, 0, sizeof rOutDataBuffer ); MFCreateSample( &( rOutDataBuffer.pSample ) ); MFCreateMemoryBuffer( rBytes, &rOutBuffer ); - rOutDataBuffer.pSample->AddBuffer( rOutBuffer ); + rOutDataBuffer.pSample->AddBuffer( rOutBuffer.Get() ); rOutDataBuffer.dwStreamID = 0; rOutDataBuffer.dwStatus = 0; rOutDataBuffer.pEvents = NULL; @@ -4748,14 +4737,12 @@ class WasapiResampler if ( _transform->ProcessOutput( 0, 1, &rOutDataBuffer, &rStatus ) == MF_E_TRANSFORM_NEED_MORE_INPUT ) { outSampleCount = 0; - SAFE_RELEASE( rOutBuffer ); SAFE_RELEASE( rOutDataBuffer.pSample ); return; } // 7.3 Write output data to outBuffer - SAFE_RELEASE( rOutBuffer ); rOutDataBuffer.pSample->ConvertToContiguousBuffer( &rOutBuffer ); rOutBuffer->GetCurrentLength( &rBytes ); @@ -4765,7 +4752,6 @@ class WasapiResampler rOutByteBuffer = NULL; outSampleCount = rBytes / _bytesPerSample / _channelCount; - SAFE_RELEASE( rOutBuffer ); SAFE_RELEASE( rOutDataBuffer.pSample ); } @@ -4774,14 +4760,14 @@ class WasapiResampler unsigned int _channelCount; float _sampleRatio; - IUnknown* _transformUnk; - IMFTransform* _transform; - IMFMediaType* _mediaType; - IMFMediaType* _inputMediaType; - IMFMediaType* _outputMediaType; + ComPtr _transformUnk; + ComPtr _transform; + ComPtr _mediaType; + ComPtr _inputMediaType; + ComPtr _outputMediaType; #ifdef __IWMResamplerProps_FWD_DEFINED__ - IWMResamplerProps* _resamplerProps; + ComPtr _resamplerProps; #endif }; @@ -4790,10 +4776,10 @@ class WasapiResampler // A structure to hold various information related to the WASAPI implementation. struct WasapiHandle { - IAudioClient* captureAudioClient; - IAudioClient* renderAudioClient; - IAudioCaptureClient* captureClient; - IAudioRenderClient* renderClient; + ComPtr captureAudioClient; + ComPtr renderAudioClient; + ComPtr captureClient; + ComPtr renderClient; HANDLE captureEvent; HANDLE renderEvent; @@ -4820,10 +4806,6 @@ RtApiWasapi::RtApiWasapi() hr = CoCreateInstance( __uuidof( MMDeviceEnumerator ), NULL, CLSCTX_ALL, __uuidof( IMMDeviceEnumerator ), ( void** ) &deviceEnumerator_ ); - - // If this runs on an old Windows, it will fail. Ignore and proceed. - if ( FAILED( hr ) ) - deviceEnumerator_ = NULL; } //----------------------------------------------------------------------------- @@ -4838,8 +4820,6 @@ RtApiWasapi::~RtApiWasapi() MUTEX_LOCK( &stream_.mutex ); } - SAFE_RELEASE( deviceEnumerator_ ); - // If this object previously called CoInitialize() if ( coInitialized_ ) CoUninitialize(); @@ -4850,7 +4830,7 @@ RtApiWasapi::~RtApiWasapi() unsigned int RtApiWasapi::getDefaultInputDevice( void ) { - IMMDevice* devicePtr = NULL; + ComPtr devicePtr = NULL; LPWSTR defaultId = NULL; std::string id; @@ -4872,7 +4852,6 @@ unsigned int RtApiWasapi::getDefaultInputDevice( void ) id = convertCharPointerToStdString( defaultId ); Release: - SAFE_RELEASE( devicePtr ); CoTaskMemFree( defaultId ); if ( !errorText_.empty() ) { @@ -4907,7 +4886,7 @@ unsigned int RtApiWasapi::getDefaultInputDevice( void ) unsigned int RtApiWasapi::getDefaultOutputDevice( void ) { - IMMDevice* devicePtr = NULL; + ComPtr devicePtr = NULL; LPWSTR defaultId = NULL; std::string id; @@ -4929,7 +4908,6 @@ unsigned int RtApiWasapi::getDefaultOutputDevice( void ) id = convertCharPointerToStdString( defaultId ); Release: - SAFE_RELEASE( devicePtr ); CoTaskMemFree( defaultId ); if ( !errorText_.empty() ) { @@ -4967,9 +4945,9 @@ void RtApiWasapi::probeDevices( void ) unsigned int captureDeviceCount = 0; unsigned int renderDeviceCount = 0; - IMMDeviceCollection* captureDevices = NULL; - IMMDeviceCollection* renderDevices = NULL; - IMMDevice* devicePtr = NULL; + ComPtr captureDevices = NULL; + ComPtr renderDevices = NULL; + ComPtr devicePtr = NULL; LPWSTR defaultCaptureId = NULL; LPWSTR defaultRenderId = NULL; @@ -5028,7 +5006,6 @@ void RtApiWasapi::probeDevices( void ) } // Get the default render device Id. - SAFE_RELEASE( devicePtr ); hr = deviceEnumerator_->GetDefaultAudioEndpoint( eRender, eConsole, &devicePtr ); if ( SUCCEEDED( hr) ) { hr = devicePtr->GetId( &defaultRenderId ); @@ -5041,7 +5018,6 @@ void RtApiWasapi::probeDevices( void ) // Collect device IDs with mode. for ( unsigned int n=0; nItem( n, &devicePtr ); if ( FAILED( hr ) ) { @@ -5114,11 +5090,6 @@ void RtApiWasapi::probeDevices( void ) } Exit: - // Release all references - SAFE_RELEASE( captureDevices ); - SAFE_RELEASE( renderDevices ); - SAFE_RELEASE( devicePtr ); - CoTaskMemFree( defaultCaptureId ); CoTaskMemFree( defaultRenderId ); @@ -5135,9 +5106,9 @@ void RtApiWasapi::probeDevices( void ) bool RtApiWasapi::probeDeviceInfo( RtAudio::DeviceInfo &info, LPWSTR deviceId, bool isCaptureDevice ) { PROPVARIANT deviceNameProp; - IMMDevice* devicePtr = NULL; - IAudioClient* audioClient = NULL; - IPropertyStore* devicePropStore = NULL; + ComPtr devicePtr = NULL; + ComPtr audioClient = NULL; + ComPtr devicePropStore = NULL; WAVEFORMATEX* deviceFormat = NULL; WAVEFORMATEX* closestMatchFormat = NULL; @@ -5239,10 +5210,6 @@ bool RtApiWasapi::probeDeviceInfo( RtAudio::DeviceInfo &info, LPWSTR deviceId, b // Release all references PropVariantClear( &deviceNameProp ); - SAFE_RELEASE( devicePtr ); - SAFE_RELEASE( audioClient ); - SAFE_RELEASE( devicePropStore ); - CoTaskMemFree( deviceFormat ); CoTaskMemFree( closestMatchFormat ); @@ -5270,13 +5237,6 @@ void RtApiWasapi::closeStream( void ) MUTEX_LOCK( &stream_.mutex ); } - // clean up stream memory - SAFE_RELEASE(((WasapiHandle*)stream_.apiHandle)->captureClient) - SAFE_RELEASE(((WasapiHandle*)stream_.apiHandle)->renderClient) - - SAFE_RELEASE( ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient ) - SAFE_RELEASE( ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient ) - if ( ( ( WasapiHandle* ) stream_.apiHandle )->captureEvent ) CloseHandle( ( ( WasapiHandle* ) stream_.apiHandle )->captureEvent ); @@ -5412,7 +5372,7 @@ bool RtApiWasapi::probeDeviceOpen( unsigned int deviceId, StreamMode mode, unsig { MUTEX_LOCK( &stream_.mutex ); bool methodResult = FAILURE; - IMMDevice* devicePtr = NULL; + ComPtr devicePtr = NULL; WAVEFORMATEX* deviceFormat = NULL; unsigned int bufferBytes; stream_.state = STREAM_STOPPED; @@ -5457,7 +5417,7 @@ bool RtApiWasapi::probeDeviceOpen( unsigned int deviceId, StreamMode mode, unsig stream_.apiHandle = ( void* ) new WasapiHandle(); if ( isInput ) { - IAudioClient*& captureAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient; + ComPtr captureAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient; hr = devicePtr->Activate( __uuidof( IAudioClient ), CLSCTX_ALL, NULL, ( void** ) &captureAudioClient ); @@ -5479,7 +5439,7 @@ bool RtApiWasapi::probeDeviceOpen( unsigned int deviceId, StreamMode mode, unsig // 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; + ComPtr renderAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient; if ( !renderAudioClient ) { MUTEX_UNLOCK( &stream_.mutex ); probeDeviceOpen( deviceId, OUTPUT, channels, firstChannel, sampleRate, format, bufferSize, options ); @@ -5487,7 +5447,7 @@ bool RtApiWasapi::probeDeviceOpen( unsigned int deviceId, StreamMode mode, unsig } // Retrieve captureAudioClient from our stream handle. - IAudioClient*& captureAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient; + ComPtr captureAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient; hr = devicePtr->Activate( __uuidof( IAudioClient ), CLSCTX_ALL, NULL, ( void** ) &captureAudioClient ); @@ -5509,7 +5469,7 @@ bool RtApiWasapi::probeDeviceOpen( unsigned int deviceId, StreamMode mode, unsig // 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; + ComPtr renderAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient; if ( renderAudioClient ) { methodResult = SUCCESS; goto Exit; @@ -5592,7 +5552,6 @@ bool RtApiWasapi::probeDeviceOpen( unsigned int deviceId, StreamMode mode, unsig Exit: //clean up - SAFE_RELEASE( devicePtr ); CoTaskMemFree( deviceFormat ); // if method failed, close the stream @@ -5645,10 +5604,10 @@ void RtApiWasapi::wasapiThread() HRESULT hr; - IAudioClient* captureAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient; - IAudioClient* renderAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient; - IAudioCaptureClient* captureClient = ( ( WasapiHandle* ) stream_.apiHandle )->captureClient; - IAudioRenderClient* renderClient = ( ( WasapiHandle* ) stream_.apiHandle )->renderClient; + ComPtr captureAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient; + ComPtr renderAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient; + ComPtr captureClient = ( ( WasapiHandle* ) stream_.apiHandle )->captureClient; + ComPtr renderClient = ( ( WasapiHandle* ) stream_.apiHandle )->renderClient; HANDLE captureEvent = ( ( WasapiHandle* ) stream_.apiHandle )->captureEvent; HANDLE renderEvent = ( ( WasapiHandle* ) stream_.apiHandle )->renderEvent; @@ -5708,7 +5667,7 @@ void RtApiWasapi::wasapiThread() captureSrRatio = ( ( float ) captureFormat->nSamplesPerSec / stream_.sampleRate ); if ( !captureClient ) { - IAudioClient3* captureAudioClient3 = nullptr; + ComPtr captureAudioClient3 = nullptr; captureAudioClient->QueryInterface( __uuidof( IAudioClient3 ), ( void** ) &captureAudioClient3 ); if ( captureAudioClient3 && !loopbackEnabled ) { @@ -5728,7 +5687,6 @@ void RtApiWasapi::wasapiThread() MinPeriodInFrames, captureFormat, NULL ); - SAFE_RELEASE(captureAudioClient3); } else { @@ -5820,7 +5778,7 @@ void RtApiWasapi::wasapiThread() renderSrRatio = ( ( float ) renderFormat->nSamplesPerSec / stream_.sampleRate ); if ( !renderClient ) { - IAudioClient3* renderAudioClient3 = nullptr; + ComPtr renderAudioClient3 = nullptr; renderAudioClient->QueryInterface( __uuidof( IAudioClient3 ), ( void** ) &renderAudioClient3 ); if ( renderAudioClient3 ) { @@ -5840,7 +5798,6 @@ void RtApiWasapi::wasapiThread() MinPeriodInFrames, renderFormat, NULL ); - SAFE_RELEASE(renderAudioClient3); } else { From 82b282cf50606dbfece9b0c713c84dc07e45c1b9 Mon Sep 17 00:00:00 2001 From: leonsal Date: Mon, 3 Jun 2024 15:27:10 -0300 Subject: [PATCH 09/15] Delete struct rtaudio in rtaudio_destroy() (C api) --- rtaudio_c.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtaudio_c.cpp b/rtaudio_c.cpp index 63c7dec8..cdd491c0 100644 --- a/rtaudio_c.cpp +++ b/rtaudio_c.cpp @@ -71,7 +71,7 @@ rtaudio_t rtaudio_create(rtaudio_api_t api) { return audio; } -void rtaudio_destroy(rtaudio_t audio) { delete audio->audio; } +void rtaudio_destroy(rtaudio_t audio) { delete audio->audio; delete audio; } rtaudio_api_t rtaudio_current_api(rtaudio_t audio) { return (rtaudio_api_t)audio->audio->getCurrentApi(); From 737c16aa2808031cc85f0304770a1e52db102e1a Mon Sep 17 00:00:00 2001 From: garyscavone Date: Mon, 3 Jun 2024 15:32:25 -0400 Subject: [PATCH 10/15] Small doc fix in probe.txt. --- doc/doxygen/probe.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/doc/doxygen/probe.txt b/doc/doxygen/probe.txt index 545b90d3..8fa73375 100644 --- a/doc/doxygen/probe.txt +++ b/doc/doxygen/probe.txt @@ -27,9 +27,8 @@ int main() info = audio.getDeviceInfo( ids[n] ); // Print, for example, the name and maximum number of output channels for each device - std::cout << "device name = " << info.name << std::endl; - std::cout << ": maximum output channels = " << info.outputChannels << std::endl; - } + std::cout << "device name = " << info.name << std::endl; + std::cout << ": maximum output channels = " << info.outputChannels << std::endl; } return 0; From 17faa04ad1b65fffce3aeaffe4baf59607d14baf Mon Sep 17 00:00:00 2001 From: garyscavone Date: Mon, 3 Jun 2024 15:48:14 -0400 Subject: [PATCH 11/15] Update to configure.ac, removed AC_HEADER_STDC. --- configure.ac | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 6c1f7cc4..67dca684 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ # Process this file with autoconf to produce a configure script. -AC_INIT(RtAudio, 6.0.1, gary.scavone@mcgill.ca, rtaudio) +AC_INIT([RtAudio],[6.0.1],[gary.scavone@mcgill.ca],[rtaudio]) AC_CONFIG_AUX_DIR(config) AC_CONFIG_SRCDIR(RtAudio.cpp) AC_CONFIG_FILES([rtaudio.pc Makefile tests/Makefile doc/Makefile doc/Doxyfile]) @@ -91,7 +91,6 @@ LT_INIT([win32-dll]) AC_CONFIG_MACRO_DIR([m4]) # Checks for header files. -AC_HEADER_STDC AC_CHECK_HEADERS(sys/ioctl.h unistd.h) # Check compiler and use -Wall if gnu From dff3586c57c7c261ef071561ef64383fd98d73be Mon Sep 17 00:00:00 2001 From: garyscavone Date: Mon, 3 Jun 2024 16:04:58 -0400 Subject: [PATCH 12/15] Test to fix MacOS configure problem in github workflow test. --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 67dca684..7903d621 100644 --- a/configure.ac +++ b/configure.ac @@ -87,7 +87,7 @@ AS_IF([test "x${AR}" = "xno" ], [ ]) # Initialize libtool -LT_INIT([win32-dll]) +#LT_INIT([win32-dll]) AC_CONFIG_MACRO_DIR([m4]) # Checks for header files. From 5ac95f36c67961d6a130843b6e28e71fe241e5fa Mon Sep 17 00:00:00 2001 From: garyscavone Date: Mon, 3 Jun 2024 16:09:52 -0400 Subject: [PATCH 13/15] Another attempt to fix MacOS workflow problem. --- .github/workflows/ci.yml | 2 +- configure.ac | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 48178566..2d94dc1f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -72,7 +72,7 @@ jobs: with: fetch-depth: 0 - name: install dependencies - run: brew install autoconf-archive automake cmake meson + run: brew install autoconf-archive automake cmake meson libtool - name: automake run: env NOCONFIGURE=1 ./autogen.sh && mkdir bld-automake && cd bld-automake diff --git a/configure.ac b/configure.ac index 7903d621..67dca684 100644 --- a/configure.ac +++ b/configure.ac @@ -87,7 +87,7 @@ AS_IF([test "x${AR}" = "xno" ], [ ]) # Initialize libtool -#LT_INIT([win32-dll]) +LT_INIT([win32-dll]) AC_CONFIG_MACRO_DIR([m4]) # Checks for header files. From 4f51d0ad34f3f6957ba28997075156cdc1526f25 Mon Sep 17 00:00:00 2001 From: Lalit Shankar Chowdhury Date: Thu, 5 Sep 2024 20:59:32 +0530 Subject: [PATCH 14/15] Fix no audio output in WASAPI The issue was caused by creating new copies of ComPtr inside WasapiHandle instead of using references to the existing instance. --- RtAudio.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/RtAudio.cpp b/RtAudio.cpp index db4f1afa..ac6bee92 100644 --- a/RtAudio.cpp +++ b/RtAudio.cpp @@ -52,8 +52,6 @@ #include #if defined(_WIN32) -#include -using Microsoft::WRL::ComPtr; #include #endif @@ -257,6 +255,8 @@ class RtApiDs: public RtApi #endif #if defined(__WINDOWS_WASAPI__) +#include +using Microsoft::WRL::ComPtr; struct IMMDeviceEnumerator; @@ -4691,8 +4691,8 @@ class WasapiResampler outputBufferSize = ( unsigned int ) ceilf( inputBufferSize * _sampleRatio ) + ( _bytesPerSample * _channelCount ); } - ComPtr rInBuffer; - ComPtr rInSample; + ComPtr rInBuffer = NULL; + ComPtr rInSample = NULL; BYTE* rInByteBuffer = NULL; // 5. Create Sample object from input data @@ -4749,7 +4749,6 @@ class WasapiResampler rOutBuffer->Lock( &rOutByteBuffer, NULL, NULL ); memcpy( outBuffer, rOutByteBuffer, rBytes ); rOutBuffer->Unlock(); - rOutByteBuffer = NULL; outSampleCount = rBytes / _bytesPerSample / _channelCount; SAFE_RELEASE( rOutDataBuffer.pSample ); @@ -5090,6 +5089,8 @@ void RtApiWasapi::probeDevices( void ) } Exit: + // Release all references + CoTaskMemFree( defaultCaptureId ); CoTaskMemFree( defaultRenderId ); @@ -5237,6 +5238,8 @@ void RtApiWasapi::closeStream( void ) MUTEX_LOCK( &stream_.mutex ); } + // clean up stream memory + if ( ( ( WasapiHandle* ) stream_.apiHandle )->captureEvent ) CloseHandle( ( ( WasapiHandle* ) stream_.apiHandle )->captureEvent ); @@ -5439,7 +5442,7 @@ bool RtApiWasapi::probeDeviceOpen( unsigned int deviceId, StreamMode mode, unsig // If an output device and is configured for loopback (input mode) if ( isInput == false && mode == INPUT ) { // If renderAudioClient is not initialised, initialise it now - ComPtr renderAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient; + ComPtr& renderAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient; if ( !renderAudioClient ) { MUTEX_UNLOCK( &stream_.mutex ); probeDeviceOpen( deviceId, OUTPUT, channels, firstChannel, sampleRate, format, bufferSize, options ); @@ -5447,7 +5450,7 @@ bool RtApiWasapi::probeDeviceOpen( unsigned int deviceId, StreamMode mode, unsig } // Retrieve captureAudioClient from our stream handle. - ComPtr captureAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient; + ComPtr& captureAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient; hr = devicePtr->Activate( __uuidof( IAudioClient ), CLSCTX_ALL, NULL, ( void** ) &captureAudioClient ); @@ -5469,7 +5472,7 @@ bool RtApiWasapi::probeDeviceOpen( unsigned int deviceId, StreamMode mode, unsig // If output device and is configured for output. if ( isInput == false && mode == OUTPUT ) { // If renderAudioClient is already initialised, don't initialise it again - ComPtr renderAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient; + ComPtr& renderAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient; if ( renderAudioClient ) { methodResult = SUCCESS; goto Exit; From af3b361aee64a12aad0e7fea2dc2e2bf406a9ec4 Mon Sep 17 00:00:00 2001 From: garyscavone Date: Wed, 18 Sep 2024 09:41:31 -0400 Subject: [PATCH 15/15] Update to workflow to v4 of tarball artifact actions. --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2d94dc1f..a4d4dee3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,7 +6,7 @@ jobs: Tarball: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: install dependencies @@ -18,7 +18,7 @@ jobs: (./autogen.sh || (cat config.log; false)) && make distcheck && make clean - name: Archive dist tarball artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: rtaudio-dev-tarball path: rtaudio-*.tar.gz