From d41ba780b23d2c2e898892242adc67d44c7ac583 Mon Sep 17 00:00:00 2001 From: Ross Bencina Date: Fri, 2 Sep 2016 20:27:39 +1000 Subject: [PATCH] hotplug: added connectionId parameter to PaDeviceInfo and bumped struct version number. added PaUtil_MakeDeviceConnectionId() function and used it to initialize connectionId in all host APIs. updated patest_refresh_device_list to display connection id. NOTE: persistent connection ids have not been implemented in dsound and wdmks, so refreshing the device list will change connection ids. --- include/portaudio.h | 14 ++++++++++++-- src/common/pa_front.c | 6 ++++++ src/common/pa_hostapi.h | 3 +++ src/hostapi/alsa/pa_linux_alsa.c | 4 +++- src/hostapi/asihpi/pa_linux_asihpi.c | 6 ++++-- src/hostapi/asio/pa_asio.cpp | 3 ++- src/hostapi/coreaudio/pa_mac_core.c | 3 ++- src/hostapi/dsound/pa_win_ds.c | 6 ++++-- src/hostapi/jack/pa_jack.c | 4 +++- src/hostapi/oss/pa_unix_oss.c | 3 ++- src/hostapi/wasapi/pa_win_wasapi.c | 4 +++- src/hostapi/wdmks/pa_win_wdmks.c | 6 ++++-- src/hostapi/wmme/pa_win_wmme.c | 8 ++++++-- test/patest_refresh_device_list.c | 3 ++- 14 files changed, 56 insertions(+), 17 deletions(-) diff --git a/include/portaudio.h b/include/portaudio.h index 655c52d..e5a40d4 100644 --- a/include/portaudio.h +++ b/include/portaudio.h @@ -500,7 +500,7 @@ typedef void PaDevicesChangedCallback( void *userData ); @see PaStreamFinishedCallback */ -PaError Pa_SetDevicesChangedCallback( void *userData, PaStreamFinishedCallback* devicesChangedCallback ); +PaError Pa_SetDevicesChangedCallback( void *userData, PaDevicesChangedCallback* devicesChangedCallback ); /** The type used to represent monotonic time in seconds. PaTime is @@ -548,12 +548,20 @@ typedef unsigned long PaSampleFormat; #define paNonInterleaved ((PaSampleFormat) 0x80000000) /**< @see PaSampleFormat */ + +/** A unique stable identifier for the duration of device connection, + or PA initialize/terminate, whichever is shorter. + @see Pa_RefreshDeviceList() +*/ +typedef unsigned long PaDeviceConnectionId; + + /** A structure providing information and capabilities of PortAudio devices. Devices may support input, output or both input and output. */ typedef struct PaDeviceInfo { - int structVersion; /* this is struct version 2 */ + int structVersion; /* this is struct version 3 */ const char *name; PaHostApiIndex hostApi; /**< note this is a host API index, not a type id*/ @@ -568,6 +576,8 @@ typedef struct PaDeviceInfo PaTime defaultHighOutputLatency; double defaultSampleRate; + + PaDeviceConnectionId connectionId; /**< @see PaDeviceConnectionId */ } PaDeviceInfo; diff --git a/src/common/pa_front.c b/src/common/pa_front.c index def07e3..e552569 100644 --- a/src/common/pa_front.c +++ b/src/common/pa_front.c @@ -1955,3 +1955,9 @@ void PaUtil_DevicesChanged(unsigned state, void* pData) PaUtil_UnlockHotPlug(); } +static PaDeviceConnectionId nextDeviceConnectionId_ = 1000; + +PaDeviceConnectionId PaUtil_MakeDeviceConnectionId( void ) +{ + return nextDeviceConnectionId_++; +} diff --git a/src/common/pa_hostapi.h b/src/common/pa_hostapi.h index 79e3e88..92dc201 100644 --- a/src/common/pa_hostapi.h +++ b/src/common/pa_hostapi.h @@ -171,6 +171,9 @@ typedef struct PaUtilPrivatePaFrontHostApiInfo { }PaUtilPrivatePaFrontHostApiInfo; +PaDeviceConnectionId PaUtil_MakeDeviceConnectionId( void ); + + /** The common header for all data structures whose pointers are passed through the hostApiSpecificStreamInfo field of the PaStreamParameters structure. Note that in order to keep the public PortAudio interface clean, this structure diff --git a/src/hostapi/alsa/pa_linux_alsa.c b/src/hostapi/alsa/pa_linux_alsa.c index dbe2d04..bb16df6 100644 --- a/src/hostapi/alsa/pa_linux_alsa.c +++ b/src/hostapi/alsa/pa_linux_alsa.c @@ -1189,9 +1189,11 @@ static PaError FillInDevInfo( PaAlsaHostApiRepresentation *alsaApi, HwDevInfo* d } } - baseDeviceInfo->structVersion = 2; + baseDeviceInfo->structVersion = 3; baseDeviceInfo->hostApi = alsaApi->hostApiIndex; baseDeviceInfo->name = deviceHwInfo->name; + deviceInfo->connectionId = PaUtil_MakeDeviceConnectionId(); + devInfo->alsaName = deviceHwInfo->alsaName; devInfo->isPlug = deviceHwInfo->isPlug; diff --git a/src/hostapi/asihpi/pa_linux_asihpi.c b/src/hostapi/asihpi/pa_linux_asihpi.c index ab76d3c..d1a3f82 100644 --- a/src/hostapi/asihpi/pa_linux_asihpi.c +++ b/src/hostapi/asihpi/pa_linux_asihpi.c @@ -636,7 +636,7 @@ static PaError PaAsiHpi_BuildDeviceList( PaAsiHpiHostApiRepresentation *hpiHostA hpiDevice->streamIndex = j; hpiDevice->streamIsOutput = 0; /* Set common PortAudio device stats */ - baseDeviceInfo->structVersion = 2; + baseDeviceInfo->structVersion = 3; /* Make sure name string is owned by API info structure */ sprintf( srcName, "Adapter %d (%4X) - Input Stream %d", i+1, type, j+1 ); @@ -656,6 +656,7 @@ static PaError PaAsiHpi_BuildDeviceList( PaAsiHpiHostApiRepresentation *hpiHostA /* HPI interface can actually handle any sampling rate to 1 Hz accuracy, * so this default is as good as any */ baseDeviceInfo->defaultSampleRate = 44100; + baseDeviceInfo->connectionId = PaUtil_MakeDeviceConnectionId(); /* Store device in global PortAudio list */ hostApi->deviceInfos[deviceIndex++] = (PaDeviceInfo *) hpiDevice; @@ -678,7 +679,7 @@ static PaError PaAsiHpi_BuildDeviceList( PaAsiHpiHostApiRepresentation *hpiHostA hpiDevice->streamIndex = j; hpiDevice->streamIsOutput = 1; /* Set common PortAudio device stats */ - baseDeviceInfo->structVersion = 2; + baseDeviceInfo->structVersion = 3; /* Make sure name string is owned by API info structure */ sprintf( srcName, "Adapter %d (%4X) - Output Stream %d", i+1, type, j+1 ); @@ -698,6 +699,7 @@ static PaError PaAsiHpi_BuildDeviceList( PaAsiHpiHostApiRepresentation *hpiHostA /* HPI interface can actually handle any sampling rate to 1 Hz accuracy, * so this default is as good as any */ baseDeviceInfo->defaultSampleRate = 44100; + baseDeviceInfo->connectionId = PaUtil_MakeDeviceConnectionId(); /* Store device in global PortAudio list */ hostApi->deviceInfos[deviceIndex++] = (PaDeviceInfo *) hpiDevice; diff --git a/src/hostapi/asio/pa_asio.cpp b/src/hostapi/asio/pa_asio.cpp index 47c5761..fe6884c 100644 --- a/src/hostapi/asio/pa_asio.cpp +++ b/src/hostapi/asio/pa_asio.cpp @@ -1322,10 +1322,11 @@ PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex PaAsioDeviceInfo *asioDeviceInfo = &deviceInfoArray[ (*hostApi)->info.deviceCount ]; PaDeviceInfo *deviceInfo = &asioDeviceInfo->commonDeviceInfo; - deviceInfo->structVersion = 2; + deviceInfo->structVersion = 3; deviceInfo->hostApi = hostApiIndex; deviceInfo->name = names[i]; + deviceInfo->connectionId = PaUtil_MakeDeviceConnectionId(); if( InitPaDeviceInfoFromAsioDriver( asioHostApi, names[i], i, deviceInfo, asioDeviceInfo ) == paNoError ) { diff --git a/src/hostapi/coreaudio/pa_mac_core.c b/src/hostapi/coreaudio/pa_mac_core.c index 4e35266..8743066 100644 --- a/src/hostapi/coreaudio/pa_mac_core.c +++ b/src/hostapi/coreaudio/pa_mac_core.c @@ -659,7 +659,7 @@ static PaError InitializeDeviceInfo( PaMacAUHAL *auhalHostApi, memset(deviceInfo, 0, sizeof(PaDeviceInfo)); - deviceInfo->structVersion = 2; + deviceInfo->structVersion = 3; deviceInfo->hostApi = hostApiIndex; /* Get the device name using CFString */ @@ -693,6 +693,7 @@ static PaError InitializeDeviceInfo( PaMacAUHAL *auhalHostApi, CFRelease(nameRef); } deviceInfo->name = name; + deviceInfo->connectionId = PaUtil_MakeDeviceConnectionId(); /* Try to get the default sample rate. Don't fail if we can't get this. */ propSize = sizeof(Float64); diff --git a/src/hostapi/dsound/pa_win_ds.c b/src/hostapi/dsound/pa_win_ds.c index 0a40797..ffd95f9 100644 --- a/src/hostapi/dsound/pa_win_ds.c +++ b/src/hostapi/dsound/pa_win_ds.c @@ -993,6 +993,7 @@ static PaError AddOutputDeviceInfoFromDirectSound( } deviceInfo->name = name; + deviceInfo->connectionId = PaUtil_MakeDeviceConnectionId(); return result; @@ -1162,7 +1163,8 @@ http://www.winehq.com/hypermail/wine-patches/2003/01/0290.html } deviceInfo->name = name; - + deviceInfo->connectionId = PaUtil_MakeDeviceConnectionId(); + return result; error: @@ -1482,7 +1484,7 @@ static PaError ScanDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaH for( i = 0 ; i < maximumNewDeviceCount; ++i ) { PaDeviceInfo *deviceInfo = &deviceInfoArray[i].inheritedDeviceInfo; - deviceInfo->structVersion = 2; + deviceInfo->structVersion = 3; deviceInfo->hostApi = hostApiIndex; deviceInfo->name = 0; diff --git a/src/hostapi/jack/pa_jack.c b/src/hostapi/jack/pa_jack.c index ab6af78..792b0b4 100644 --- a/src/hostapi/jack/pa_jack.c +++ b/src/hostapi/jack/pa_jack.c @@ -573,7 +573,7 @@ static PaError BuildDeviceList( PaJackHostApiRepresentation *jackApi ) strlen(client_names[client_index]) + 1 ), paInsufficientMemory ); strcpy( (char *)curDevInfo->name, client_names[client_index] ); - curDevInfo->structVersion = 2; + curDevInfo->structVersion = 3; curDevInfo->hostApi = jackApi->hostApiIndex; /* JACK is very inflexible: there is one sample rate the whole @@ -634,6 +634,8 @@ static PaError BuildDeviceList( PaJackHostApiRepresentation *jackApi ) commonApi->info.defaultInputDevice = client_index; if( commonApi->info.defaultOutputDevice == paNoDevice && curDevInfo->maxOutputChannels > 0 ) commonApi->info.defaultOutputDevice = client_index; + + deviceInfo->connectionId = PaUtil_MakeDeviceConnectionId(); } error: diff --git a/src/hostapi/oss/pa_unix_oss.c b/src/hostapi/oss/pa_unix_oss.c index b0ce4c3..1a3d7bb 100644 --- a/src/hostapi/oss/pa_unix_oss.c +++ b/src/hostapi/oss/pa_unix_oss.c @@ -298,7 +298,7 @@ PaError PaUtil_InitializeDeviceInfo( PaDeviceInfo *deviceInfo, const char *name, { PaError result = paNoError; - deviceInfo->structVersion = 2; + deviceInfo->structVersion = 3; if( allocations ) { size_t len = strlen( name ) + 1; @@ -316,6 +316,7 @@ PaError PaUtil_InitializeDeviceInfo( PaDeviceInfo *deviceInfo, const char *name, deviceInfo->defaultHighInputLatency = defaultHighInputLatency; deviceInfo->defaultHighOutputLatency = defaultHighOutputLatency; deviceInfo->defaultSampleRate = defaultSampleRate; + deviceInfo->connectionId = PaUtil_MakeDeviceConnectionId(); error: return result; diff --git a/src/hostapi/wasapi/pa_win_wasapi.c b/src/hostapi/wasapi/pa_win_wasapi.c index 67618c8..d764324 100644 --- a/src/hostapi/wasapi/pa_win_wasapi.c +++ b/src/hostapi/wasapi/pa_win_wasapi.c @@ -1314,7 +1314,7 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd { DWORD state = 0; PaDeviceInfo *deviceInfo = &deviceInfoArray[i]; - deviceInfo->structVersion = 2; + deviceInfo->structVersion = 3; deviceInfo->hostApi = hostApiIndex; PA_DEBUG(("WASAPI: device idx: %02d\n", i)); @@ -1508,6 +1508,8 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd break; } + deviceInfo->connectionId = PaUtil_MakeDeviceConnectionId(); + (*hostApi)->deviceInfos[i] = deviceInfo; ++(*hostApi)->info.deviceCount; } diff --git a/src/hostapi/wdmks/pa_win_wdmks.c b/src/hostapi/wdmks/pa_win_wdmks.c index e01f249..44ec174 100644 --- a/src/hostapi/wdmks/pa_win_wdmks.c +++ b/src/hostapi/wdmks/pa_win_wdmks.c @@ -3530,7 +3530,7 @@ static PaError ScanDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaH for( i = 0 ; i < totalDeviceCount; ++i ) { PaDeviceInfo *deviceInfo = &deviceInfoArray[i].inheritedDeviceInfo; - deviceInfo->structVersion = 2; + deviceInfo->structVersion = 3; deviceInfo->hostApi = hostApiIndex; deviceInfo->name = 0; outArgument->deviceInfos[ i ] = deviceInfo; @@ -3573,11 +3573,13 @@ static PaError ScanDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaH wdmDeviceInfo->filter = pFilter; - deviceInfo->structVersion = 2; + deviceInfo->structVersion = 3; deviceInfo->hostApi = hostApiIndex; deviceInfo->name = wdmDeviceInfo->compositeName; /* deviceInfo->hostApiSpecificDeviceInfo = &pFilter->devInfo; */ + deviceInfo->connectionId = PaUtil_MakeDeviceConnectionId(); + wdmDeviceInfo->pin = pin->pinId; /* Get the name of the "device" */ diff --git a/src/hostapi/wmme/pa_win_wmme.c b/src/hostapi/wmme/pa_win_wmme.c index 4f4c872..5afaf8e 100644 --- a/src/hostapi/wmme/pa_win_wmme.c +++ b/src/hostapi/wmme/pa_win_wmme.c @@ -789,6 +789,8 @@ static PaError InitializeInputDeviceInfo( PaWinMmeHostApiRepresentation *winMmeH DetectDefaultSampleRate( winMmeDeviceInfo, winMmeInputDeviceId, QueryInputWaveFormatEx, deviceInfo->maxInputChannels ); + deviceInfo->connectionId = PaUtil_MakeDeviceConnectionId(); + *success = 1; error: @@ -924,6 +926,8 @@ static PaError InitializeOutputDeviceInfo( PaWinMmeHostApiRepresentation *winMme DetectDefaultSampleRate( winMmeDeviceInfo, winMmeOutputDeviceId, QueryOutputWaveFormatEx, deviceInfo->maxOutputChannels ); + deviceInfo->connectionId = PaUtil_MakeDeviceConnectionId(); + *success = 1; error: @@ -1069,7 +1073,7 @@ PaError PaWinMme_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd UINT winMmeDeviceId = (UINT)((i==-1) ? WAVE_MAPPER : i); PaWinMmeDeviceInfo *wmmeDeviceInfo = &deviceInfoArray[ (*hostApi)->info.deviceCount ]; PaDeviceInfo *deviceInfo = &wmmeDeviceInfo->inheritedDeviceInfo; - deviceInfo->structVersion = 2; + deviceInfo->structVersion = 3; deviceInfo->hostApi = hostApiIndex; deviceInfo->maxInputChannels = 0; @@ -1112,7 +1116,7 @@ PaError PaWinMme_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd UINT winMmeDeviceId = (UINT)((i==-1) ? WAVE_MAPPER : i); PaWinMmeDeviceInfo *wmmeDeviceInfo = &deviceInfoArray[ (*hostApi)->info.deviceCount ]; PaDeviceInfo *deviceInfo = &wmmeDeviceInfo->inheritedDeviceInfo; - deviceInfo->structVersion = 2; + deviceInfo->structVersion = 3; deviceInfo->hostApi = hostApiIndex; deviceInfo->maxInputChannels = 0; diff --git a/test/patest_refresh_device_list.c b/test/patest_refresh_device_list.c index 69adae9..6c138f0 100644 --- a/test/patest_refresh_device_list.c +++ b/test/patest_refresh_device_list.c @@ -13,8 +13,9 @@ void printDevices() const PaHostApiInfo *hostApiInfo = Pa_GetHostApiInfo( deviceInfo->hostApi ); assert( deviceInfo != 0 ); + assert( deviceInfo->structVersion >= 3 ); /* should be the case if all APIs have implemented connectionId */ - printf( "%d %s (%s)\n", i, deviceInfo->name, hostApiInfo->name ); + printf( "%d (conn id: %d) %s (%s)\n", i, deviceInfo->connectionId, deviceInfo->name, hostApiInfo->name ); } } -- 2.43.0