From f7beca8b1d477c0b8aad8b892e0c3bdd13532fac Mon Sep 17 00:00:00 2001 From: Noam Postavsky Date: Tue, 19 Jan 2021 21:12:41 -0500 Subject: [PATCH 1/2] ASIO: Handle buffer size changes When kAsioBufferSizeChange or kAsioResetRequest is received, remember it and update the buffer sizes the next time PaAsio_GetAvailableBufferSizes() is called. Add callbacks for those messages so that the library user can be aware of them. --- include/pa_asio.h | 14 +++++++++ src/hostapi/asio/pa_asio.cpp | 58 +++++++++++++++++++++++++++++++++++- 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/include/pa_asio.h b/include/pa_asio.h index 27cbd3b81..3629fad25 100644 --- a/include/pa_asio.h +++ b/include/pa_asio.h @@ -71,6 +71,20 @@ PaError PaAsio_GetAvailableBufferSizes( PaDeviceIndex device, long *minBufferSizeFrames, long *maxBufferSizeFrames, long *preferredBufferSizeFrames, long *granularity ); +typedef void (*PaAsioResetRequestCallback)(); + +/** Register callback to detect reset requests. + + This correponds to the ASIO kAsioResetRequest and kAsioBufferSizeChange + messages. + + @param callback The function to call on ASIO reset request. This is called + when the driver's buffer size has changed or it needs a reset, usually in + response to a user changing the configuration. Pass NULL to unregister a + callback. +*/ +void PaAsio_RegisterResetRequestCallback( PaAsioResetRequestCallback callback ); + /** Backwards compatibility alias for PaAsio_GetAvailableBufferSizes @see PaAsio_GetAvailableBufferSizes diff --git a/src/hostapi/asio/pa_asio.cpp b/src/hostapi/asio/pa_asio.cpp index bc5f0e415..f775e8771 100644 --- a/src/hostapi/asio/pa_asio.cpp +++ b/src/hostapi/asio/pa_asio.cpp @@ -276,7 +276,7 @@ typedef struct PaAsioDriverInfo ASIODriverInfo asioDriverInfo; long inputChannelCount, outputChannelCount; long bufferMinSize, bufferMaxSize, bufferPreferredSize, bufferGranularity; - bool postOutput; + bool postOutput, bufferSizeOutdated; } PaAsioDriverInfo; @@ -928,6 +928,30 @@ PaError PaAsio_GetAvailableBufferSizes( PaDeviceIndex device, PaAsioDeviceInfo *asioDeviceInfo = (PaAsioDeviceInfo*)hostApi->deviceInfos[hostApiDevice]; + PaAsioHostApiRepresentation *asioApi = (PaAsioHostApiRepresentation*) hostApi; + if ( hostApiDevice == asioApi->openAsioDeviceIndex && + asioApi->openAsioDriverInfo.bufferSizeOutdated ) + { + ASIOError asioError; + PaAsioDriverInfo &driverInfo = asioApi->openAsioDriverInfo; + if( (asioError = ASIOGetBufferSize(&driverInfo.bufferMinSize, + &driverInfo.bufferMaxSize, &driverInfo.bufferPreferredSize, + &driverInfo.bufferGranularity)) != ASE_OK ) + { + PA_ASIO_SET_LAST_ASIO_ERROR( asioError ); + return paUnanticipatedHostError; + } + else + { + asioDeviceInfo->minBufferSize = driverInfo.bufferMinSize; + asioDeviceInfo->maxBufferSize = driverInfo.bufferMaxSize; + asioDeviceInfo->preferredBufferSize = driverInfo.bufferPreferredSize; + asioDeviceInfo->bufferGranularity = driverInfo.bufferGranularity; + + driverInfo.bufferSizeOutdated = false; + } + } + *minBufferSizeFrames = asioDeviceInfo->minBufferSize; *maxBufferSizeFrames = asioDeviceInfo->maxBufferSize; *preferredBufferSizeFrames = asioDeviceInfo->preferredBufferSize; @@ -995,6 +1019,7 @@ static PaError LoadAsioDriver( PaAsioHostApiRepresentation *asioHostApi, const c PA_ASIO_SET_LAST_ASIO_ERROR( asioError ); goto error; } + driverInfo->bufferSizeOutdated = false; if( ASIOOutputReady() == ASE_OK ) driverInfo->postOutput = true; @@ -3199,6 +3224,28 @@ static void sampleRateChanged(ASIOSampleRate sRate) PA_DEBUG( ("sampleRateChanged : %d \n", sRate)); } +static PaAsioResetRequestCallback resetRequestCallback_; + +void PaAsio_RegisterResetRequestCallback( PaAsioResetRequestCallback callback ) +{ + resetRequestCallback_ = callback; +} + +static void setBufferSizesOutdated() +{ + PaUtilHostApiRepresentation *hostApi; + PaAsioHostApiRepresentation *asioApi; + + PaError result = PaUtil_GetHostApiRepresentation( &hostApi, paASIO ); + if( result != paNoError ) + return; + asioApi = (PaAsioHostApiRepresentation*) hostApi; + if ( asioApi->openAsioDeviceIndex == paNoDevice ) + return; + + asioApi->openAsioDriverInfo.bufferSizeOutdated = true; +} + static long asioMessages(long selector, long value, void* message, double* opt) { // TAKEN FROM THE ASIO SDK @@ -3226,6 +3273,11 @@ static long asioMessages(long selector, long value, void* message, double* opt) case kAsioBufferSizeChange: //printf("kAsioBufferSizeChange \n"); + setBufferSizesOutdated(); + if (resetRequestCallback_) { + resetRequestCallback_(); + ret = 1L; + } break; case kAsioResetRequest: @@ -3240,6 +3292,10 @@ static long asioMessages(long selector, long value, void* message, double* opt) http://www.portaudio.com/trac/ticket/108 */ //asioDriverInfo.stopped; // In this sample the processing will just stop + setBufferSizesOutdated(); + if (resetRequestCallback_) { + resetRequestCallback_(); + } ret = 1L; break; From f8da4ee377278ef6e08700d2c87c69a3dcb78201 Mon Sep 17 00:00:00 2001 From: Noam Postavsky Date: Fri, 26 Feb 2021 13:58:36 -0500 Subject: [PATCH 2/2] Don't try to keep the buffer size info updated It raises threading synchronization issues, and not all kAsioResetRequest events will be about that anyway. For example, ASIO4ALL can have changes in input channels; Portaudio's current API can't have chanel names change without reinitializing the library. --- include/pa_asio.h | 5 ++-- src/hostapi/asio/pa_asio.cpp | 44 +----------------------------------- 2 files changed, 4 insertions(+), 45 deletions(-) diff --git a/include/pa_asio.h b/include/pa_asio.h index 3629fad25..f187a0f10 100644 --- a/include/pa_asio.h +++ b/include/pa_asio.h @@ -80,8 +80,9 @@ typedef void (*PaAsioResetRequestCallback)(); @param callback The function to call on ASIO reset request. This is called when the driver's buffer size has changed or it needs a reset, usually in - response to a user changing the configuration. Pass NULL to unregister a - callback. + response to a user changing the configuration. Call Pa_Terminate followed by + Pa_Initialize to have the changes reflected in Portaudio's API. Pass NULL to + unregister a callback. */ void PaAsio_RegisterResetRequestCallback( PaAsioResetRequestCallback callback ); diff --git a/src/hostapi/asio/pa_asio.cpp b/src/hostapi/asio/pa_asio.cpp index f775e8771..40d8899aa 100644 --- a/src/hostapi/asio/pa_asio.cpp +++ b/src/hostapi/asio/pa_asio.cpp @@ -276,7 +276,7 @@ typedef struct PaAsioDriverInfo ASIODriverInfo asioDriverInfo; long inputChannelCount, outputChannelCount; long bufferMinSize, bufferMaxSize, bufferPreferredSize, bufferGranularity; - bool postOutput, bufferSizeOutdated; + bool postOutput; } PaAsioDriverInfo; @@ -928,30 +928,6 @@ PaError PaAsio_GetAvailableBufferSizes( PaDeviceIndex device, PaAsioDeviceInfo *asioDeviceInfo = (PaAsioDeviceInfo*)hostApi->deviceInfos[hostApiDevice]; - PaAsioHostApiRepresentation *asioApi = (PaAsioHostApiRepresentation*) hostApi; - if ( hostApiDevice == asioApi->openAsioDeviceIndex && - asioApi->openAsioDriverInfo.bufferSizeOutdated ) - { - ASIOError asioError; - PaAsioDriverInfo &driverInfo = asioApi->openAsioDriverInfo; - if( (asioError = ASIOGetBufferSize(&driverInfo.bufferMinSize, - &driverInfo.bufferMaxSize, &driverInfo.bufferPreferredSize, - &driverInfo.bufferGranularity)) != ASE_OK ) - { - PA_ASIO_SET_LAST_ASIO_ERROR( asioError ); - return paUnanticipatedHostError; - } - else - { - asioDeviceInfo->minBufferSize = driverInfo.bufferMinSize; - asioDeviceInfo->maxBufferSize = driverInfo.bufferMaxSize; - asioDeviceInfo->preferredBufferSize = driverInfo.bufferPreferredSize; - asioDeviceInfo->bufferGranularity = driverInfo.bufferGranularity; - - driverInfo.bufferSizeOutdated = false; - } - } - *minBufferSizeFrames = asioDeviceInfo->minBufferSize; *maxBufferSizeFrames = asioDeviceInfo->maxBufferSize; *preferredBufferSizeFrames = asioDeviceInfo->preferredBufferSize; @@ -1019,7 +995,6 @@ static PaError LoadAsioDriver( PaAsioHostApiRepresentation *asioHostApi, const c PA_ASIO_SET_LAST_ASIO_ERROR( asioError ); goto error; } - driverInfo->bufferSizeOutdated = false; if( ASIOOutputReady() == ASE_OK ) driverInfo->postOutput = true; @@ -3231,21 +3206,6 @@ void PaAsio_RegisterResetRequestCallback( PaAsioResetRequestCallback callback ) resetRequestCallback_ = callback; } -static void setBufferSizesOutdated() -{ - PaUtilHostApiRepresentation *hostApi; - PaAsioHostApiRepresentation *asioApi; - - PaError result = PaUtil_GetHostApiRepresentation( &hostApi, paASIO ); - if( result != paNoError ) - return; - asioApi = (PaAsioHostApiRepresentation*) hostApi; - if ( asioApi->openAsioDeviceIndex == paNoDevice ) - return; - - asioApi->openAsioDriverInfo.bufferSizeOutdated = true; -} - static long asioMessages(long selector, long value, void* message, double* opt) { // TAKEN FROM THE ASIO SDK @@ -3273,7 +3233,6 @@ static long asioMessages(long selector, long value, void* message, double* opt) case kAsioBufferSizeChange: //printf("kAsioBufferSizeChange \n"); - setBufferSizesOutdated(); if (resetRequestCallback_) { resetRequestCallback_(); ret = 1L; @@ -3292,7 +3251,6 @@ static long asioMessages(long selector, long value, void* message, double* opt) http://www.portaudio.com/trac/ticket/108 */ //asioDriverInfo.stopped; // In this sample the processing will just stop - setBufferSizesOutdated(); if (resetRequestCallback_) { resetRequestCallback_(); }