From cee4dbe7bf539061b4025695ed0f091d77066446 Mon Sep 17 00:00:00 2001 From: Tuukka Pasanen Date: Mon, 3 Jun 2024 15:29:43 +0300 Subject: [PATCH 1/4] pulseaudio: Add function to handle Pulseaudio pa_operation Now pa_operation are handled multiple ways. Add function to make sure that they are handled always same. --- src/hostapi/pulseaudio/pa_linux_pulseaudio.c | 40 +++------ .../pulseaudio/pa_linux_pulseaudio_cb.c | 81 +++++++++---------- .../pulseaudio/pa_linux_pulseaudio_internal.h | 8 +- 3 files changed, 53 insertions(+), 76 deletions(-) diff --git a/src/hostapi/pulseaudio/pa_linux_pulseaudio.c b/src/hostapi/pulseaudio/pa_linux_pulseaudio.c index ec2fc74f5..32c22c494 100644 --- a/src/hostapi/pulseaudio/pa_linux_pulseaudio.c +++ b/src/hostapi/pulseaudio/pa_linux_pulseaudio.c @@ -51,14 +51,13 @@ */ -#include /* strlen() */ - #include "pa_linux_pulseaudio_cb_internal.h" #include "pa_linux_pulseaudio_block_internal.h" /* PulseAudio headers */ #include #include +#include #include /* This is used to identify process name for PulseAudio. */ @@ -650,12 +649,8 @@ PaError PaPulseAudio_Initialize( PaUtilHostApiRepresentation ** hostApi, PaPulseAudio_ServerInfoCb, pulseaudioHostApi ); - while( pa_operation_get_state( pulseaudioOperation ) == PA_OPERATION_RUNNING ) - { - pa_threaded_mainloop_wait( pulseaudioHostApi->mainloop ); - } - - pa_operation_unref( pulseaudioOperation ); + PaPulseAudio_ReleaseOperation( pulseaudioHostApi, + &pulseaudioOperation ); /* Add the "Default" sink at index 0 */ if( _PaPulseAudio_AddAudioDevice( pulseaudioHostApi, @@ -701,12 +696,8 @@ PaError PaPulseAudio_Initialize( PaUtilHostApiRepresentation ** hostApi, PaPulseAudio_SinkListCb, pulseaudioHostApi ); - while( pa_operation_get_state( pulseaudioOperation ) == PA_OPERATION_RUNNING ) - { - pa_threaded_mainloop_wait( pulseaudioHostApi->mainloop ); - } - - pa_operation_unref( pulseaudioOperation ); + PaPulseAudio_ReleaseOperation( pulseaudioHostApi, + &pulseaudioOperation ); /* List PulseAudio sources. If found callback: PaPulseAudio_SourceListCb */ pulseaudioOperation = @@ -714,12 +705,8 @@ PaError PaPulseAudio_Initialize( PaUtilHostApiRepresentation ** hostApi, PaPulseAudio_SourceListCb, pulseaudioHostApi ); - while( pa_operation_get_state( pulseaudioOperation ) == PA_OPERATION_RUNNING ) - { - pa_threaded_mainloop_wait( pulseaudioHostApi->mainloop ); - } - - pa_operation_unref( pulseaudioOperation ); + PaPulseAudio_ReleaseOperation( pulseaudioHostApi, + &pulseaudioOperation ); (*hostApi)->info.deviceCount = pulseaudioHostApi->deviceCount; @@ -1461,11 +1448,8 @@ PaError PaPulseAudio_RenameSource( PaStream *s, const char *streamName ) op = pa_stream_set_name( stream->inputStream, streamName, RenameStreamCb, stream ); PaPulseAudio_UnLock( stream->mainloop ); - /* Wait for completion. */ - while (pa_operation_get_state( op ) == PA_OPERATION_RUNNING) - { - pa_threaded_mainloop_wait( stream->mainloop ); - } + PaPulseAudio_ReleaseOperation( stream->hostapi, + &op ); return result; } @@ -1498,10 +1482,8 @@ PaError PaPulseAudio_RenameSink( PaStream *s, const char *streamName ) PaPulseAudio_UnLock( stream->mainloop ); /* Wait for completion. */ - while (pa_operation_get_state( op ) == PA_OPERATION_RUNNING) - { - pa_threaded_mainloop_wait( stream->mainloop ); - } + PaPulseAudio_ReleaseOperation( stream->hostapi, + &op ); return result; } diff --git a/src/hostapi/pulseaudio/pa_linux_pulseaudio_cb.c b/src/hostapi/pulseaudio/pa_linux_pulseaudio_cb.c index 3aa484a37..d925ebd6c 100644 --- a/src/hostapi/pulseaudio/pa_linux_pulseaudio_cb.c +++ b/src/hostapi/pulseaudio/pa_linux_pulseaudio_cb.c @@ -105,6 +105,34 @@ int PaPulseAudio_updateTimeInfo( pa_stream * s, return 0; } +/* Release pa_operation always same way */ +int PaPulseAudio_ReleaseOperation(PaPulseAudio_HostApiRepresentation *hostapi, + pa_operation **operation) +{ + unsigned int wait = 0; + pa_operation *localOperation = (*operation); + + while( pa_operation_get_state( localOperation ) == PA_OPERATION_RUNNING ) + { + pa_threaded_mainloop_wait( hostapi->mainloop ); + + wait ++; + usleep( 1000 ); + + if( wait > 2000 ) + { + PA_DEBUG( ( "Portaudio %s: Operation still running %d!\n", + __FUNCTION__, pa_operation_get_state( localOperation ) ) ); + break; + } + } + + PaPulseAudio_Lock( hostapi->mainloop ); + pa_operation_unref( localOperation ); + operation = NULL; + PaPulseAudio_UnLock( hostapi->mainloop ); +} + /* locks the Pulse Main loop when not called from it */ void PaPulseAudio_Lock( pa_threaded_mainloop *mainloop ) @@ -488,22 +516,10 @@ PaError PaPulseAudio_CloseStreamCb( PaStream * s ) stream ); PaPulseAudio_UnLock( stream->mainloop ); - while( pa_operation_get_state( pulseaudioOperation ) == PA_OPERATION_RUNNING ) - { - pa_threaded_mainloop_wait( pulseaudioHostApi->mainloop ); - waitLoop ++; - - if(waitLoop > 256) - { - break; - } - } - - waitLoop = 0; + PaPulseAudio_ReleaseOperation( pulseaudioHostApi, + &pulseaudioOperation ); PaPulseAudio_Lock(stream->mainloop); - pa_operation_unref( pulseaudioOperation ); - pulseaudioOperation = NULL; pa_stream_disconnect( stream->outputStream ); PaPulseAudio_UnLock( stream->mainloop ); @@ -520,22 +536,10 @@ PaError PaPulseAudio_CloseStreamCb( PaStream * s ) stream ); PaPulseAudio_UnLock( stream->mainloop ); - while( pa_operation_get_state( pulseaudioOperation ) == PA_OPERATION_RUNNING ) - { - pa_threaded_mainloop_wait( pulseaudioHostApi->mainloop ); - waitLoop ++; - - if(waitLoop > 256) - { - break; - } - } - - waitLoop = 0; + PaPulseAudio_ReleaseOperation( pulseaudioHostApi, + &pulseaudioOperation ); PaPulseAudio_Lock( stream->mainloop ); - pa_operation_unref( pulseaudioOperation ); - pulseaudioOperation = NULL; /* Then we disconnect stream and wait for * Termination @@ -641,7 +645,6 @@ PaError PaPulseAudio_StartStreamCb( PaStream * s ) PaPulseAudio_HostApiRepresentation *pulseaudioHostApi = stream->hostapi; const char *pulseaudioName = NULL; pa_operation *pulseaudioOperation = NULL; - int waitLoop = 0; unsigned int pulseaudioReqFrameSize = stream->suggestedLatencyUSecs; stream->isActive = 0; @@ -769,13 +772,8 @@ PaError PaPulseAudio_StartStreamCb( PaStream * s ) stream ); PaPulseAudio_UnLock( pulseaudioHostApi->mainloop ); - while( pa_operation_get_state( pulseaudioOperation ) == PA_OPERATION_RUNNING) - { - pa_threaded_mainloop_wait( pulseaudioHostApi->mainloop ); - } - - pa_operation_unref( pulseaudioOperation ); - pulseaudioOperation = NULL; + PaPulseAudio_ReleaseOperation( pulseaudioHostApi, + &pulseaudioOperation ); } else { @@ -897,6 +895,7 @@ static PaError RequestStop( PaPulseAudio_Stream * stream, PaError ret = paNoError; PaPulseAudio_HostApiRepresentation *pulseaudioHostApi = stream->hostapi; pa_operation *pulseaudioOperation = NULL; + int waitLoop = 0; PaPulseAudio_Lock( pulseaudioHostApi->mainloop ); @@ -919,14 +918,8 @@ static PaError RequestStop( PaPulseAudio_Stream * stream, PaPulseAudio_CorkSuccessCb, stream ); - while( pa_operation_get_state( pulseaudioOperation ) == PA_OPERATION_RUNNING ) - { - pa_threaded_mainloop_wait( pulseaudioHostApi->mainloop ); - } - - pa_operation_unref( pulseaudioOperation ); - - pulseaudioOperation = NULL; + PaPulseAudio_ReleaseOperation( pulseaudioHostApi, + &pulseaudioOperation ); } requeststop_error: diff --git a/src/hostapi/pulseaudio/pa_linux_pulseaudio_internal.h b/src/hostapi/pulseaudio/pa_linux_pulseaudio_internal.h index 2d71ae412..e1386185a 100644 --- a/src/hostapi/pulseaudio/pa_linux_pulseaudio_internal.h +++ b/src/hostapi/pulseaudio/pa_linux_pulseaudio_internal.h @@ -195,11 +195,14 @@ PaPulseAudio_Stream; return errorCode; \ } \ } \ - if( !pastream->isActive || pastream->isStopped ) \ + if( !(pastream)->isActive || (pastream)->isStopped ) \ { \ - return paStreamIsStopped; \ + return paStreamIsStopped; \ } +int PaPulseAudio_ReleaseOperation(PaPulseAudio_HostApiRepresentation *hostapi, + pa_operation **pulseaudioOperation); + void PaPulseAudio_Lock( pa_threaded_mainloop *mainloop ); void PaPulseAudio_UnLock( pa_threaded_mainloop *mainloop ); @@ -225,7 +228,6 @@ PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, PaStreamCallback * streamCallback, void *userData ); - PaError IsStreamStopped( PaStream * s ); PaError IsStreamActive( PaStream * stream ); From 57c75ca1dc41b432becd52d32d6751df90859249 Mon Sep 17 00:00:00 2001 From: Tuukka Pasanen Date: Tue, 2 Jul 2024 16:36:11 +0300 Subject: [PATCH 2/4] Update src/hostapi/pulseaudio/pa_linux_pulseaudio_cb.c As function does not return value it should be void type Co-authored-by: Ross Bencina --- src/hostapi/pulseaudio/pa_linux_pulseaudio_cb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hostapi/pulseaudio/pa_linux_pulseaudio_cb.c b/src/hostapi/pulseaudio/pa_linux_pulseaudio_cb.c index d925ebd6c..e05ec0a13 100644 --- a/src/hostapi/pulseaudio/pa_linux_pulseaudio_cb.c +++ b/src/hostapi/pulseaudio/pa_linux_pulseaudio_cb.c @@ -106,7 +106,7 @@ int PaPulseAudio_updateTimeInfo( pa_stream * s, } /* Release pa_operation always same way */ -int PaPulseAudio_ReleaseOperation(PaPulseAudio_HostApiRepresentation *hostapi, +void PaPulseAudio_ReleaseOperation(PaPulseAudio_HostApiRepresentation *hostapi, pa_operation **operation) { unsigned int wait = 0; From 6e2e98efd352fd340d2b085178c7e92bda95a971 Mon Sep 17 00:00:00 2001 From: Tuukka Pasanen Date: Tue, 2 Jul 2024 16:36:25 +0300 Subject: [PATCH 3/4] Update src/hostapi/pulseaudio/pa_linux_pulseaudio_internal.h As function does not return value it should be void type Co-authored-by: Ross Bencina --- src/hostapi/pulseaudio/pa_linux_pulseaudio_internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hostapi/pulseaudio/pa_linux_pulseaudio_internal.h b/src/hostapi/pulseaudio/pa_linux_pulseaudio_internal.h index e1386185a..011710453 100644 --- a/src/hostapi/pulseaudio/pa_linux_pulseaudio_internal.h +++ b/src/hostapi/pulseaudio/pa_linux_pulseaudio_internal.h @@ -200,7 +200,7 @@ PaPulseAudio_Stream; return paStreamIsStopped; \ } -int PaPulseAudio_ReleaseOperation(PaPulseAudio_HostApiRepresentation *hostapi, +void PaPulseAudio_ReleaseOperation(PaPulseAudio_HostApiRepresentation *hostapi, pa_operation **pulseaudioOperation); void PaPulseAudio_Lock( pa_threaded_mainloop *mainloop ); From cdde14d5d7690f2175d2b9fc50a328b7826e0ac3 Mon Sep 17 00:00:00 2001 From: Tuukka Pasanen Date: Tue, 2 Jul 2024 16:51:07 +0300 Subject: [PATCH 4/4] Pulseaudio: mainloop should be locked when using pa_threaded_mainloop_wait Mainloop should be locked when using pa_threaded_mainloop_wait make changes that it happens --- src/hostapi/pulseaudio/pa_linux_pulseaudio.c | 18 ++++++++++ .../pulseaudio/pa_linux_pulseaudio_cb.c | 33 ++++++++++++++----- 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/src/hostapi/pulseaudio/pa_linux_pulseaudio.c b/src/hostapi/pulseaudio/pa_linux_pulseaudio.c index 32c22c494..31e39ca84 100644 --- a/src/hostapi/pulseaudio/pa_linux_pulseaudio.c +++ b/src/hostapi/pulseaudio/pa_linux_pulseaudio.c @@ -649,9 +649,15 @@ PaError PaPulseAudio_Initialize( PaUtilHostApiRepresentation ** hostApi, PaPulseAudio_ServerInfoCb, pulseaudioHostApi ); + PaPulseAudio_UnLock( pulseaudioHostApi->mainloop ); + lockTaken = 0; + PaPulseAudio_ReleaseOperation( pulseaudioHostApi, &pulseaudioOperation ); + PaPulseAudio_Lock( pulseaudioHostApi->mainloop ); + lockTaken = 1; + /* Add the "Default" sink at index 0 */ if( _PaPulseAudio_AddAudioDevice( pulseaudioHostApi, "Default Sink", @@ -696,18 +702,30 @@ PaError PaPulseAudio_Initialize( PaUtilHostApiRepresentation ** hostApi, PaPulseAudio_SinkListCb, pulseaudioHostApi ); + PaPulseAudio_UnLock( pulseaudioHostApi->mainloop ); + lockTaken = 0; + PaPulseAudio_ReleaseOperation( pulseaudioHostApi, &pulseaudioOperation ); + PaPulseAudio_Lock( pulseaudioHostApi->mainloop ); + lockTaken = 1; + /* List PulseAudio sources. If found callback: PaPulseAudio_SourceListCb */ pulseaudioOperation = pa_context_get_source_info_list( pulseaudioHostApi->context, PaPulseAudio_SourceListCb, pulseaudioHostApi ); + PaPulseAudio_UnLock( pulseaudioHostApi->mainloop ); + lockTaken = 0; + PaPulseAudio_ReleaseOperation( pulseaudioHostApi, &pulseaudioOperation ); + PaPulseAudio_Lock( pulseaudioHostApi->mainloop ); + lockTaken = 1; + (*hostApi)->info.deviceCount = pulseaudioHostApi->deviceCount; if( pulseaudioHostApi->deviceCount > 0 ) diff --git a/src/hostapi/pulseaudio/pa_linux_pulseaudio_cb.c b/src/hostapi/pulseaudio/pa_linux_pulseaudio_cb.c index e05ec0a13..b298cf713 100644 --- a/src/hostapi/pulseaudio/pa_linux_pulseaudio_cb.c +++ b/src/hostapi/pulseaudio/pa_linux_pulseaudio_cb.c @@ -109,22 +109,38 @@ int PaPulseAudio_updateTimeInfo( pa_stream * s, void PaPulseAudio_ReleaseOperation(PaPulseAudio_HostApiRepresentation *hostapi, pa_operation **operation) { - unsigned int wait = 0; + unsigned int waitOperation = 1000; pa_operation *localOperation = (*operation); + pa_operation_state_t localOperationState = PA_OPERATION_RUNNING; + + // As mainly operation is done when running locally + // done after 1-3 then 1000 is enough to wait if + // something goes wrong - while( pa_operation_get_state( localOperation ) == PA_OPERATION_RUNNING ) + while( waitOperation > 0 ) { + PaPulseAudio_Lock( hostapi->mainloop ); pa_threaded_mainloop_wait( hostapi->mainloop ); + PaPulseAudio_UnLock( hostapi->mainloop ); - wait ++; - usleep( 1000 ); + localOperationState = pa_operation_get_state( localOperation ); - if( wait > 2000 ) + // No wait if operation have been DONE or CANCELLED + if( localOperationState != PA_OPERATION_RUNNING) { - PA_DEBUG( ( "Portaudio %s: Operation still running %d!\n", - __FUNCTION__, pa_operation_get_state( localOperation ) ) ); break; } + + waitOperation --; + + usleep( 1000 ); + } + + // No wait if operation have been DONE or CANCELLED + if( localOperationState == PA_OPERATION_RUNNING) + { + PA_DEBUG( ( "Portaudio %s: Operation still running %d!\n", + __FUNCTION__, localOperationState ) ); } PaPulseAudio_Lock( hostapi->mainloop ); @@ -895,7 +911,6 @@ static PaError RequestStop( PaPulseAudio_Stream * stream, PaError ret = paNoError; PaPulseAudio_HostApiRepresentation *pulseaudioHostApi = stream->hostapi; pa_operation *pulseaudioOperation = NULL; - int waitLoop = 0; PaPulseAudio_Lock( pulseaudioHostApi->mainloop ); @@ -918,8 +933,10 @@ static PaError RequestStop( PaPulseAudio_Stream * stream, PaPulseAudio_CorkSuccessCb, stream ); + PaPulseAudio_UnLock( pulseaudioHostApi->mainloop ); PaPulseAudio_ReleaseOperation( pulseaudioHostApi, &pulseaudioOperation ); + PaPulseAudio_Lock( pulseaudioHostApi->mainloop ); } requeststop_error: