Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ca24be18da | ||
|
|
2048a0a62f | ||
|
|
d485a4b36d | ||
|
|
5549bca961 | ||
|
|
82bdb95a6d | ||
|
|
c2175e14f1 | ||
|
|
b95f3bd6a2 | ||
|
|
231ecf77c7 | ||
|
|
0a290773de | ||
|
|
46f97c7c20 | ||
|
|
8e9e507e12 | ||
|
|
8d285faa5e | ||
|
|
6840cda9ad | ||
|
|
5c5d4fb711 | ||
|
|
9562fb8074 | ||
|
|
ec5b0687a8 | ||
|
|
b45ec9ed0a | ||
|
|
d41ba780b2 | ||
|
|
abfcd708b4 | ||
|
|
3f7c315f22 | ||
|
|
9761960aa5 | ||
|
|
23b4bdd49a | ||
|
|
89f8f75a27 |
19 changed files with 1484 additions and 368 deletions
|
|
@ -3,7 +3,7 @@ EXPORTS
|
||||||
;
|
;
|
||||||
Pa_GetVersion @1
|
Pa_GetVersion @1
|
||||||
Pa_GetVersionText @2
|
Pa_GetVersionText @2
|
||||||
Pa_GetErrorText @3
|
Pa_GetErrorText @3
|
||||||
Pa_Initialize @4
|
Pa_Initialize @4
|
||||||
Pa_Terminate @5
|
Pa_Terminate @5
|
||||||
Pa_GetHostApiCount @6
|
Pa_GetHostApiCount @6
|
||||||
|
|
@ -35,6 +35,8 @@ Pa_GetStreamReadAvailable @31
|
||||||
Pa_GetStreamWriteAvailable @32
|
Pa_GetStreamWriteAvailable @32
|
||||||
Pa_GetSampleSize @33
|
Pa_GetSampleSize @33
|
||||||
Pa_Sleep @34
|
Pa_Sleep @34
|
||||||
|
Pa_RefreshDeviceList @35
|
||||||
|
Pa_SetDevicesChangedCallback @36
|
||||||
PaAsio_GetAvailableBufferSizes @50
|
PaAsio_GetAvailableBufferSizes @50
|
||||||
PaAsio_ShowControlPanel @51
|
PaAsio_ShowControlPanel @51
|
||||||
PaUtil_InitializeX86PlainConverters @52
|
PaUtil_InitializeX86PlainConverters @52
|
||||||
|
|
|
||||||
|
|
@ -1827,6 +1827,10 @@
|
||||||
RelativePath="..\..\src\os\win\pa_win_wdmks_utils.c"
|
RelativePath="..\..\src\os\win\pa_win_wdmks_utils.c"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\src\os\win\pa_win_hotplug.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\src\os\win\pa_x86_plain_converters.c"
|
RelativePath="..\..\src\os\win\pa_x86_plain_converters.c"
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -155,9 +155,17 @@ const char *Pa_GetErrorText( PaError errorCode );
|
||||||
Pairs of calls to Pa_Initialize()/Pa_Terminate() may overlap, and are not
|
Pairs of calls to Pa_Initialize()/Pa_Terminate() may overlap, and are not
|
||||||
required to be fully nested.
|
required to be fully nested.
|
||||||
|
|
||||||
Note that if Pa_Initialize() returns an error code, Pa_Terminate() should
|
If Pa_Initialize() returns an error code, Pa_Terminate() should
|
||||||
NOT be called.
|
NOT be called.
|
||||||
|
|
||||||
|
@note The device list returned by Pa_GetDeviceCount() et al, default devices,
|
||||||
|
and the default host API are all frozen when Pa_Initialize() is called. The
|
||||||
|
device list is not automatically updated when hardware devices are connected or
|
||||||
|
disconnected. To refresh the list of devices, and default devices, either call
|
||||||
|
Pa_RefreshDeviceList() or uninitialize PortAudio using Pa_Terminate(),
|
||||||
|
and then reinitialize it by calling Pa_Initialize(). To register a callback
|
||||||
|
when native devices or defaults change, call Pa_SetDevicesChangedCallback().
|
||||||
|
|
||||||
@return paNoError if successful, otherwise an error code indicating the cause
|
@return paNoError if successful, otherwise an error code indicating the cause
|
||||||
of failure.
|
of failure.
|
||||||
|
|
||||||
|
|
@ -432,6 +440,77 @@ PaDeviceIndex Pa_GetDefaultInputDevice( void );
|
||||||
PaDeviceIndex Pa_GetDefaultOutputDevice( void );
|
PaDeviceIndex Pa_GetDefaultOutputDevice( void );
|
||||||
|
|
||||||
|
|
||||||
|
/** Refresh PortAudio's list of devices to reflect currently available
|
||||||
|
native audio devices. Also refreshes default devices and default host API.
|
||||||
|
|
||||||
|
PortAudio's list of devices is usually frozen when Pa_Initialize() is
|
||||||
|
called. Call Pa_RefreshDeviceList() to refresh PortAudio's device list
|
||||||
|
at any time while PortAudio is initialized.
|
||||||
|
|
||||||
|
@return an error code indicating whether the refresh was successful.
|
||||||
|
|
||||||
|
If the function succeeds, future calls to Pa_GetDeviceCount() may return
|
||||||
|
a different count than before, all device indexes may refer to
|
||||||
|
different devices, and any previously returned PaDeviceInfo pointers are
|
||||||
|
invalidated. Default devices reflected by PaHostApiInfo.defaultInputDevice,
|
||||||
|
PaHostApiInfo.defaultOutputDevice and global defaults returned by
|
||||||
|
Pa_GetDefaultHostApi(), Pa_GetDefaultInputDevice() and
|
||||||
|
Pa_GetDefaultOutputDevice() may changed.
|
||||||
|
|
||||||
|
If the function fails, the device list and defaults are unchanged.
|
||||||
|
|
||||||
|
@note Open streams will not be affected by calls to this function.
|
||||||
|
*/
|
||||||
|
PaError Pa_RefreshDeviceList( void );
|
||||||
|
|
||||||
|
|
||||||
|
/** Functions of type PaDevicesChangedCallback are implemented by PortAudio
|
||||||
|
clients. They can be registered with PortAudio using the Pa_SetDevicesChangedCallback
|
||||||
|
function. Once registered, a callback is invoked whenever available native audio
|
||||||
|
devices may have changed. For example, when a USB audio device is connected or
|
||||||
|
disconnected. The callback is also invoked whenever the native default device
|
||||||
|
selection changes.
|
||||||
|
|
||||||
|
When the callback is invoked, there is no change to the devices listed by
|
||||||
|
PortAudio. To update PortAudio's view of the device list, the client
|
||||||
|
must call Pa_RefreshDeviceList(). This must not be done from within
|
||||||
|
the callback.
|
||||||
|
|
||||||
|
The callback may occur on any thread. The client should not call other PortAudio
|
||||||
|
functions from within a PaDevicesChangedCallback. In particular, the client
|
||||||
|
should not directly call Pa_RefreshDeviceList() from within the notification
|
||||||
|
callback. Instead, the client should set an atomic flag, or queue a message to
|
||||||
|
notify a controller thread that would then call Pa_RefreshDeviceList().
|
||||||
|
|
||||||
|
@param userData The userData parameter supplied to Pa_SetDevicesChangedCallback()
|
||||||
|
|
||||||
|
@see Pa_SetDevicesChangedCallback
|
||||||
|
*/
|
||||||
|
typedef void PaDevicesChangedCallback( void *userData );
|
||||||
|
|
||||||
|
|
||||||
|
/** Register a callback function that will be called when native audio devices
|
||||||
|
become available or unavailable, and when native default devices change.
|
||||||
|
See the description of PaDevicesChangedCallback for further details about
|
||||||
|
when the callback will be called.
|
||||||
|
|
||||||
|
@param userData A client supplied pointer that is passed to the devices changed
|
||||||
|
callback.
|
||||||
|
|
||||||
|
@param devicesChangedCallback a pointer to a callback function with the same
|
||||||
|
signature as PaDevicesChangedCallback. Passing NULL for this parameter will
|
||||||
|
un-register a previously registered callback function.
|
||||||
|
|
||||||
|
@return on success returns paNoError, otherwise an error code indicating the
|
||||||
|
cause of the error.
|
||||||
|
|
||||||
|
@note Only one function pointer may be registered at a time.
|
||||||
|
|
||||||
|
@see PaDevicesChangedCallback
|
||||||
|
*/
|
||||||
|
PaError Pa_SetDevicesChangedCallback( void *userData, PaDevicesChangedCallback* devicesChangedCallback );
|
||||||
|
|
||||||
|
|
||||||
/** The type used to represent monotonic time in seconds. PaTime is
|
/** The type used to represent monotonic time in seconds. PaTime is
|
||||||
used for the fields of the PaStreamCallbackTimeInfo argument to the
|
used for the fields of the PaStreamCallbackTimeInfo argument to the
|
||||||
PaStreamCallback and as the result of Pa_GetStreamTime().
|
PaStreamCallback and as the result of Pa_GetStreamTime().
|
||||||
|
|
@ -477,12 +556,30 @@ typedef unsigned long PaSampleFormat;
|
||||||
|
|
||||||
#define paNonInterleaved ((PaSampleFormat) 0x80000000) /**< @see PaSampleFormat */
|
#define paNonInterleaved ((PaSampleFormat) 0x80000000) /**< @see PaSampleFormat */
|
||||||
|
|
||||||
|
|
||||||
|
/** An integer id that uniquely identifies a device, so long as the device is
|
||||||
|
plugged in and PortAudio is initialized. Its purpose is to identify (correlate)
|
||||||
|
devices across calls to Pa_RefreshDeviceList().
|
||||||
|
|
||||||
|
Each device reported by Pa_GetDeviceInfo() has a distinct connectionId.
|
||||||
|
|
||||||
|
PortAudio makes a best-effort to ensure that a persistent underlying device
|
||||||
|
has the same connectionId before and after a single call to Pa_RefreshDeviceList().
|
||||||
|
|
||||||
|
If a device is disconnected and later reconnected it may be assigned a new
|
||||||
|
connectionId.
|
||||||
|
|
||||||
|
@see Pa_RefreshDeviceList()
|
||||||
|
*/
|
||||||
|
typedef unsigned long PaDeviceConnectionId;
|
||||||
|
|
||||||
|
|
||||||
/** A structure providing information and capabilities of PortAudio devices.
|
/** A structure providing information and capabilities of PortAudio devices.
|
||||||
Devices may support input, output or both input and output.
|
Devices may support input, output or both input and output.
|
||||||
*/
|
*/
|
||||||
typedef struct PaDeviceInfo
|
typedef struct PaDeviceInfo
|
||||||
{
|
{
|
||||||
int structVersion; /* this is struct version 2 */
|
int structVersion; /* this is struct version 3 */
|
||||||
const char *name;
|
const char *name;
|
||||||
PaHostApiIndex hostApi; /**< note this is a host API index, not a type id*/
|
PaHostApiIndex hostApi; /**< note this is a host API index, not a type id*/
|
||||||
|
|
||||||
|
|
@ -497,6 +594,8 @@ typedef struct PaDeviceInfo
|
||||||
PaTime defaultHighOutputLatency;
|
PaTime defaultHighOutputLatency;
|
||||||
|
|
||||||
double defaultSampleRate;
|
double defaultSampleRate;
|
||||||
|
|
||||||
|
PaDeviceConnectionId connectionId; /**< @see PaDeviceConnectionId */
|
||||||
} PaDeviceInfo;
|
} PaDeviceInfo;
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1201,7 +1300,6 @@ PaError Pa_GetSampleSize( PaSampleFormat format );
|
||||||
void Pa_Sleep( long msec );
|
void Pa_Sleep( long msec );
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
|
|
||||||
|
|
@ -76,11 +76,13 @@
|
||||||
#include "pa_stream.h"
|
#include "pa_stream.h"
|
||||||
#include "pa_trace.h" /* still usefull?*/
|
#include "pa_trace.h" /* still usefull?*/
|
||||||
#include "pa_debugprint.h"
|
#include "pa_debugprint.h"
|
||||||
|
#include "pa_hotplug.h"
|
||||||
|
|
||||||
#ifndef PA_SVN_REVISION
|
#ifndef PA_SVN_REVISION
|
||||||
#include "pa_svnrevision.h"
|
#include "pa_svnrevision.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is incremented if we make incompatible API changes.
|
* This is incremented if we make incompatible API changes.
|
||||||
* This version scheme is based loosely on http://semver.org/
|
* This version scheme is based loosely on http://semver.org/
|
||||||
|
|
@ -161,6 +163,8 @@ static int deviceCount_ = 0;
|
||||||
|
|
||||||
PaUtilStreamRepresentation *firstOpenStream_ = NULL;
|
PaUtilStreamRepresentation *firstOpenStream_ = NULL;
|
||||||
|
|
||||||
|
PaDevicesChangedCallback* devicesChangedCallback_ = NULL;
|
||||||
|
void* devicesChangedCallbackUserData_ = NULL;
|
||||||
|
|
||||||
#define PA_IS_INITIALISED_ (initializationCount_ != 0)
|
#define PA_IS_INITIALISED_ (initializationCount_ != 0)
|
||||||
|
|
||||||
|
|
@ -371,6 +375,9 @@ PaError Pa_Initialize( void )
|
||||||
PaUtil_InitializeClock();
|
PaUtil_InitializeClock();
|
||||||
PaUtil_ResetTraceMessages();
|
PaUtil_ResetTraceMessages();
|
||||||
|
|
||||||
|
/* Initialize hot plug here, so all its internal info is setup */
|
||||||
|
PaUtil_InitializeHotPlug();
|
||||||
|
|
||||||
result = InitializeHostApis();
|
result = InitializeHostApis();
|
||||||
if( result == paNoError )
|
if( result == paNoError )
|
||||||
++initializationCount_;
|
++initializationCount_;
|
||||||
|
|
@ -396,6 +403,8 @@ PaError Pa_Terminate( void )
|
||||||
|
|
||||||
TerminateHostApis();
|
TerminateHostApis();
|
||||||
|
|
||||||
|
PaUtil_TerminateHotPlug();
|
||||||
|
|
||||||
PaUtil_DumpTraceMessages();
|
PaUtil_DumpTraceMessages();
|
||||||
}
|
}
|
||||||
result = paNoError;
|
result = paNoError;
|
||||||
|
|
@ -744,6 +753,166 @@ PaDeviceIndex Pa_GetDefaultOutputDevice( void )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PaError Pa_RefreshDeviceList( void )
|
||||||
|
{
|
||||||
|
PaError result = paNoError;
|
||||||
|
void **scanResults = NULL;
|
||||||
|
int *deviceCounts = NULL;
|
||||||
|
int i;
|
||||||
|
int baseDeviceIndex;
|
||||||
|
|
||||||
|
PA_LOGAPI_ENTER( "Pa_UpdateAvailableDeviceList" );
|
||||||
|
if( !PA_IS_INITIALISED_ )
|
||||||
|
{
|
||||||
|
result = paNotInitialized;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate data structures used in 2-stage commit */
|
||||||
|
scanResults = (void **) PaUtil_AllocateMemory( sizeof(void*) * hostApisCount_ );
|
||||||
|
if( !scanResults )
|
||||||
|
{
|
||||||
|
result = paInsufficientMemory;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
deviceCounts = ( int * ) PaUtil_AllocateMemory( sizeof( int ) * hostApisCount_ );
|
||||||
|
if( !deviceCounts )
|
||||||
|
{
|
||||||
|
result = paInsufficientMemory;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Phase 1: Perform a scan of new devices */
|
||||||
|
for( i = 0 ; i < hostApisCount_ ; ++i )
|
||||||
|
{
|
||||||
|
PaUtilHostApiRepresentation *hostApi = hostApis_[i];
|
||||||
|
if( hostApi->ScanDeviceInfos == NULL )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
PA_DEBUG(( "Scanning new device list for host api %d.\n",i));
|
||||||
|
result = hostApi->ScanDeviceInfos( hostApi, i, &scanResults[ i ], &deviceCounts[ i ] );
|
||||||
|
if( result != paNoError )
|
||||||
|
{
|
||||||
|
/* On error, dispose scan results already obtained, then return. */
|
||||||
|
int j = 0;
|
||||||
|
for( j = 0 ; j < i ; ++j )
|
||||||
|
{
|
||||||
|
PaUtilHostApiRepresentation *hostApi = hostApis_[j];
|
||||||
|
if( hostApi->DisposeDeviceInfos == NULL )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
PA_DEBUG(( "Performing rollback for device list scan for host api %d.\n",i));
|
||||||
|
hostApi->DisposeDeviceInfos( hostApi, scanResults[ j ], deviceCounts[ j ] );
|
||||||
|
}
|
||||||
|
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------- Can't fail from here on -------------- */
|
||||||
|
|
||||||
|
/* Phase 2: Commit the scan changes to each back-end */
|
||||||
|
|
||||||
|
defaultHostApiIndex_ = -1; /* indicates that we haven't determined the default host API yet */
|
||||||
|
baseDeviceIndex = 0;
|
||||||
|
deviceCount_ = 0;
|
||||||
|
for( i = 0 ; i < hostApisCount_ ; ++i )
|
||||||
|
{
|
||||||
|
PaUtilHostApiRepresentation *hostApi = hostApis_[i];
|
||||||
|
if( hostApi->CommitDeviceInfos == NULL )
|
||||||
|
{
|
||||||
|
/* Not yet implemented for this backend. Just
|
||||||
|
assume that the baseDeviceIndex and the deviceCount_ are
|
||||||
|
incremented according to the values in the info */
|
||||||
|
baseDeviceIndex += hostApi->info.deviceCount;
|
||||||
|
deviceCount_ += hostApi->info.deviceCount;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
PA_DEBUG(( "Committing device list scan for host api %d.\n",i));
|
||||||
|
if( hostApi->CommitDeviceInfos( hostApi, i, scanResults[ i ], deviceCounts[ i ] ) != paNoError )
|
||||||
|
{
|
||||||
|
PA_DEBUG(( "Committing failed (shouldn't happen) %d.\n",i));
|
||||||
|
result = paInternalError;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert( hostApi->info.defaultInputDevice < hostApi->info.deviceCount );
|
||||||
|
assert( hostApi->info.defaultOutputDevice < hostApi->info.deviceCount );
|
||||||
|
|
||||||
|
/* the first successfully initialized host API with a default input *or*
|
||||||
|
output device is used as the default host API.
|
||||||
|
*/
|
||||||
|
if( (defaultHostApiIndex_ == -1) &&
|
||||||
|
( hostApi->info.defaultInputDevice != paNoDevice
|
||||||
|
|| hostApi->info.defaultOutputDevice != paNoDevice ) )
|
||||||
|
{
|
||||||
|
defaultHostApiIndex_ = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
hostApi->privatePaFrontInfo.baseDeviceIndex = baseDeviceIndex;
|
||||||
|
|
||||||
|
if( hostApi->info.defaultInputDevice != paNoDevice )
|
||||||
|
hostApi->info.defaultInputDevice += baseDeviceIndex;
|
||||||
|
|
||||||
|
if( hostApi->info.defaultOutputDevice != paNoDevice )
|
||||||
|
hostApi->info.defaultOutputDevice += baseDeviceIndex;
|
||||||
|
|
||||||
|
baseDeviceIndex += hostApi->info.deviceCount;
|
||||||
|
deviceCount_ += hostApi->info.deviceCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if no host APIs have devices, the default host API is the first initialized host API */
|
||||||
|
if( defaultHostApiIndex_ == -1 )
|
||||||
|
defaultHostApiIndex_ = 0;
|
||||||
|
|
||||||
|
done:
|
||||||
|
|
||||||
|
if( scanResults )
|
||||||
|
PaUtil_FreeMemory( scanResults );
|
||||||
|
|
||||||
|
if( deviceCounts )
|
||||||
|
PaUtil_FreeMemory( deviceCounts );
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PaError Pa_SetDevicesChangedCallback( void *userData, PaStreamFinishedCallback* devicesChangedCallback )
|
||||||
|
{
|
||||||
|
PaUtil_LockHotPlug();
|
||||||
|
devicesChangedCallback_ = devicesChangedCallback;
|
||||||
|
devicesChangedCallbackUserData_ = userData;
|
||||||
|
PaUtil_UnlockHotPlug();
|
||||||
|
return paNoError;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called by platform hotplug implementation whenever a OS audio device change has been detected */
|
||||||
|
void PaUtil_DevicesChanged(unsigned state, void* pData)
|
||||||
|
{
|
||||||
|
(void)state;
|
||||||
|
(void)pData;
|
||||||
|
PaUtil_LockHotPlug();
|
||||||
|
if (devicesChangedCallback_)
|
||||||
|
{
|
||||||
|
(devicesChangedCallback_)(devicesChangedCallbackUserData_);
|
||||||
|
}
|
||||||
|
PaUtil_UnlockHotPlug();
|
||||||
|
}
|
||||||
|
|
||||||
|
static PaDeviceConnectionId nextDeviceConnectionId_ = 1000;
|
||||||
|
|
||||||
|
PaDeviceConnectionId PaUtil_MakeDeviceConnectionId( void )
|
||||||
|
{
|
||||||
|
/* FIXME: if the counter wraps around we may want to ensure that
|
||||||
|
we are not issuing an ID that belongs to a current device.
|
||||||
|
we need to honor the invariant "no two devices have the same connection id"
|
||||||
|
*/
|
||||||
|
return nextDeviceConnectionId_++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceIndex device )
|
const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceIndex device )
|
||||||
{
|
{
|
||||||
int hostSpecificDeviceIndex;
|
int hostSpecificDeviceIndex;
|
||||||
|
|
@ -1806,4 +1975,3 @@ PaError Pa_GetSampleSize( PaSampleFormat format )
|
||||||
|
|
||||||
return (PaError) result;
|
return (PaError) result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -171,6 +171,9 @@ typedef struct PaUtilPrivatePaFrontHostApiInfo {
|
||||||
}PaUtilPrivatePaFrontHostApiInfo;
|
}PaUtilPrivatePaFrontHostApiInfo;
|
||||||
|
|
||||||
|
|
||||||
|
PaDeviceConnectionId PaUtil_MakeDeviceConnectionId( void );
|
||||||
|
|
||||||
|
|
||||||
/** The common header for all data structures whose pointers are passed through
|
/** The common header for all data structures whose pointers are passed through
|
||||||
the hostApiSpecificStreamInfo field of the PaStreamParameters structure.
|
the hostApiSpecificStreamInfo field of the PaStreamParameters structure.
|
||||||
Note that in order to keep the public PortAudio interface clean, this structure
|
Note that in order to keep the public PortAudio interface clean, this structure
|
||||||
|
|
@ -322,6 +325,119 @@ typedef struct PaUtilHostApiRepresentation {
|
||||||
const PaStreamParameters *inputParameters,
|
const PaStreamParameters *inputParameters,
|
||||||
const PaStreamParameters *outputParameters,
|
const PaStreamParameters *outputParameters,
|
||||||
double sampleRate );
|
double sampleRate );
|
||||||
|
|
||||||
|
/** ScanDeviceInfos, CommitDeviceInfos, DisposeDeviceInfos are used to refresh the device list.
|
||||||
|
|
||||||
|
You can think of the caller doing something like:
|
||||||
|
|
||||||
|
void *scanResults = 0;
|
||||||
|
int newDeviceCount = 0;
|
||||||
|
if( hostApi->ScanDeviceInfos(hostApi, hostApiIndex, &scanResults, &newDeviceCount) == paNoError )
|
||||||
|
{
|
||||||
|
... do other stuff ...
|
||||||
|
|
||||||
|
if( ok to commit )
|
||||||
|
{
|
||||||
|
hostApi->CommitDeviceInfos(hostApi, hostApiIndex, scanResults, newDeviceCount);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hostApi->DisposeDeviceInfos(hostApi, hostApiIndex, scanResults, newDeviceCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NB: ScanDeviceInfos may be called on all host APIs first, prior to pa_front
|
||||||
|
deciding whether to commit or cleanup.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
Scan for current native device information and compute a new device count.
|
||||||
|
Preparation step of a two-stage transaction that updates the active device list.
|
||||||
|
|
||||||
|
@param hostApi The target host API.
|
||||||
|
|
||||||
|
@param index The host API index of the target host API.
|
||||||
|
|
||||||
|
@param scanResults (OUT) Result parameter. Upon success, set to point to an
|
||||||
|
opaque structure containing collected device information. Ignored on failure.
|
||||||
|
|
||||||
|
@param newDeviceCount (Out) Result parameter. Upon success, set to the
|
||||||
|
number of discovered devices. Ignored on failure.
|
||||||
|
|
||||||
|
@return on success returns paNoError, otherwise an error code indicating
|
||||||
|
the cause of the error.
|
||||||
|
|
||||||
|
This function should not make any visible changes to the host API's internal
|
||||||
|
state. In particular, it should not update the active device list, device
|
||||||
|
information or device count.
|
||||||
|
|
||||||
|
If the function returns successfully, the caller will either (1) pass
|
||||||
|
scanResults and newDeviceCount to CommitDeviceInfos() to complete the
|
||||||
|
transaction, or (2) pass scanResults and newDeviceCount to
|
||||||
|
DisposeDeviceInfos() to abort the transaction.
|
||||||
|
|
||||||
|
@note CommitDeviceInfos and DisposeDeviceInfos should not fail, therefore
|
||||||
|
ScanDeviceInfos should perform all necessary preparations,
|
||||||
|
such as memory allocation, so that CommitDeviceInfos can always execute
|
||||||
|
without failure.
|
||||||
|
|
||||||
|
@see CommitDeviceInfos, DisposeDeviceInfos
|
||||||
|
*/
|
||||||
|
PaError (*ScanDeviceInfos)( struct PaUtilHostApiRepresentation *hostApi,
|
||||||
|
PaHostApiIndex index,
|
||||||
|
void **scanResults,
|
||||||
|
int *newDeviceCount );
|
||||||
|
|
||||||
|
/**
|
||||||
|
Update the active device list with new device information that was
|
||||||
|
returned by ScanDeviceInfos(). This is the final commit step of a two-stage
|
||||||
|
transaction that updates the active device list.
|
||||||
|
|
||||||
|
As this function is not permitted to fail, it should be very simple:
|
||||||
|
swap in new device information and free the old information.
|
||||||
|
|
||||||
|
@param hostApi The target host API.
|
||||||
|
|
||||||
|
@param index The host API index of the target host API.
|
||||||
|
|
||||||
|
@param scanResults An opaque structure containing collected device
|
||||||
|
information previously returned by ScanDeviceInfos. This is the information
|
||||||
|
that will be installed into the active device list.
|
||||||
|
|
||||||
|
@param newDeviceCount The number of discovered devices previously returned
|
||||||
|
by ScanDeviceInfos. This is the new number of devices in the active device
|
||||||
|
list.
|
||||||
|
|
||||||
|
@note This function is not permitted to fail. It should always return paNoError.
|
||||||
|
|
||||||
|
@see ScanDeviceInfos, DisposeDeviceInfos
|
||||||
|
*/
|
||||||
|
PaError (*CommitDeviceInfos)( struct PaUtilHostApiRepresentation *hostApi,
|
||||||
|
PaHostApiIndex index,
|
||||||
|
void *scanResults,
|
||||||
|
int deviceCount );
|
||||||
|
|
||||||
|
/**
|
||||||
|
Free device information that was returned by ScanDeviceInfos. This is
|
||||||
|
used in the cleanup process for a failed two-stage transaction.
|
||||||
|
|
||||||
|
@param hostApi The target host API.
|
||||||
|
|
||||||
|
@param index The host API index of the target host API.
|
||||||
|
|
||||||
|
@param scanResults An opaque structure containing collected device
|
||||||
|
information previously returned by ScanDeviceInfos. scanResults will be
|
||||||
|
freed by this function.
|
||||||
|
|
||||||
|
@param newDeviceCount The number of discovered devices previously returned
|
||||||
|
by ScanDeviceInfos.
|
||||||
|
|
||||||
|
@note This function is not permitted to fail. It should always return paNoError.
|
||||||
|
|
||||||
|
@see CommitDeviceInfos, ScanDeviceInfos
|
||||||
|
*/
|
||||||
|
PaError (*DisposeDeviceInfos)( struct PaUtilHostApiRepresentation *hostApi, void *scanResults, int deviceCount );
|
||||||
|
|
||||||
} PaUtilHostApiRepresentation;
|
} PaUtilHostApiRepresentation;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
98
src/common/pa_hotplug.h
Normal file
98
src/common/pa_hotplug.h
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
#ifndef PA_HOTPLUG_H
|
||||||
|
#define PA_HOTPLUG_H
|
||||||
|
/*
|
||||||
|
* $Id$
|
||||||
|
* Portable Audio I/O Library
|
||||||
|
* hotplug interface and utilities
|
||||||
|
*
|
||||||
|
* Based on the Open Source API proposed by Ross Bencina
|
||||||
|
* Copyright (c) 1999-2016 Ross Bencina, Phil Burk
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files
|
||||||
|
* (the "Software"), to deal in the Software without restriction,
|
||||||
|
* including without limitation the rights to use, copy, modify, merge,
|
||||||
|
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||||
|
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||||
|
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text above constitutes the entire PortAudio license; however,
|
||||||
|
* the PortAudio community also makes the following non-binding requests:
|
||||||
|
*
|
||||||
|
* Any person wishing to distribute modifications to the Software is
|
||||||
|
* requested to send the modifications to the original developer so that
|
||||||
|
* they can be incorporated into the canonical version. It is also
|
||||||
|
* requested that these non-binding requests be included along with the
|
||||||
|
* license above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
@ingroup common_src
|
||||||
|
|
||||||
|
@brief Utilities for implementing hotplug support.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "portaudio.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
/** Init/terminate hotplug notification engine.
|
||||||
|
|
||||||
|
At the moment there is on hotplug implementation per platform.
|
||||||
|
It is responsible for posting devices changed notifications
|
||||||
|
by calling PaUtil_DevicesChanged.
|
||||||
|
|
||||||
|
Once we support multiple notification mechanisms we'll probably
|
||||||
|
have the host APIs init and terminate their own notification
|
||||||
|
engines (using reference counting?) e.g. wasapi will have its own,
|
||||||
|
but other windows APIs will use the global windows notifier.
|
||||||
|
|
||||||
|
Implemented in pa_win_hotplug.c
|
||||||
|
*/
|
||||||
|
void PaUtil_InitializeHotPlug();
|
||||||
|
void PaUtil_TerminateHotPlug();
|
||||||
|
|
||||||
|
|
||||||
|
/** Invoke the client's registered devices changed notification.
|
||||||
|
|
||||||
|
@param first 0 = unknown, 1 = insertion, 2 = removal
|
||||||
|
@param second Host specific device change info (in windows it is the (unicode) device path)
|
||||||
|
|
||||||
|
Parameters are currently ignored. TODO REVIEW
|
||||||
|
|
||||||
|
Implemented in pa_front.c
|
||||||
|
*/
|
||||||
|
void PaUtil_DevicesChanged(unsigned, void*);
|
||||||
|
|
||||||
|
|
||||||
|
/** Lock/unlock a mutex used to protect the devices changed callback.
|
||||||
|
Used by pa_front.c to synchronise notification callbacks and client
|
||||||
|
requests to set/clear the device callback.
|
||||||
|
|
||||||
|
Coded like this because we don't have a cross-platform mutex.
|
||||||
|
|
||||||
|
Implemented in pa_win_hotplug.c
|
||||||
|
*/
|
||||||
|
void PaUtil_LockHotPlug();
|
||||||
|
void PaUtil_UnlockHotPlug();
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
#endif /* PA_HOTPLUG_H */
|
||||||
|
|
@ -757,6 +757,9 @@ PaError PaAlsa_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex
|
||||||
(*hostApi)->Terminate = Terminate;
|
(*hostApi)->Terminate = Terminate;
|
||||||
(*hostApi)->OpenStream = OpenStream;
|
(*hostApi)->OpenStream = OpenStream;
|
||||||
(*hostApi)->IsFormatSupported = IsFormatSupported;
|
(*hostApi)->IsFormatSupported = IsFormatSupported;
|
||||||
|
(*hostApi)->ScanDeviceInfos = 0;
|
||||||
|
(*hostApi)->CommitDeviceInfos = 0;
|
||||||
|
(*hostApi)->DisposeDeviceInfos = 0;
|
||||||
|
|
||||||
/** If AlsaErrorHandler is to be used, do not forget to unregister callback pointer in
|
/** If AlsaErrorHandler is to be used, do not forget to unregister callback pointer in
|
||||||
Terminate function.
|
Terminate function.
|
||||||
|
|
@ -1186,9 +1189,11 @@ static PaError FillInDevInfo( PaAlsaHostApiRepresentation *alsaApi, HwDevInfo* d
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
baseDeviceInfo->structVersion = 2;
|
baseDeviceInfo->structVersion = 3;
|
||||||
baseDeviceInfo->hostApi = alsaApi->hostApiIndex;
|
baseDeviceInfo->hostApi = alsaApi->hostApiIndex;
|
||||||
baseDeviceInfo->name = deviceHwInfo->name;
|
baseDeviceInfo->name = deviceHwInfo->name;
|
||||||
|
deviceInfo->connectionId = PaUtil_MakeDeviceConnectionId();
|
||||||
|
|
||||||
devInfo->alsaName = deviceHwInfo->alsaName;
|
devInfo->alsaName = deviceHwInfo->alsaName;
|
||||||
devInfo->isPlug = deviceHwInfo->isPlug;
|
devInfo->isPlug = deviceHwInfo->isPlug;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -636,7 +636,7 @@ static PaError PaAsiHpi_BuildDeviceList( PaAsiHpiHostApiRepresentation *hpiHostA
|
||||||
hpiDevice->streamIndex = j;
|
hpiDevice->streamIndex = j;
|
||||||
hpiDevice->streamIsOutput = 0;
|
hpiDevice->streamIsOutput = 0;
|
||||||
/* Set common PortAudio device stats */
|
/* Set common PortAudio device stats */
|
||||||
baseDeviceInfo->structVersion = 2;
|
baseDeviceInfo->structVersion = 3;
|
||||||
/* Make sure name string is owned by API info structure */
|
/* Make sure name string is owned by API info structure */
|
||||||
sprintf( srcName,
|
sprintf( srcName,
|
||||||
"Adapter %d (%4X) - Input Stream %d", i+1, type, j+1 );
|
"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,
|
/* HPI interface can actually handle any sampling rate to 1 Hz accuracy,
|
||||||
* so this default is as good as any */
|
* so this default is as good as any */
|
||||||
baseDeviceInfo->defaultSampleRate = 44100;
|
baseDeviceInfo->defaultSampleRate = 44100;
|
||||||
|
baseDeviceInfo->connectionId = PaUtil_MakeDeviceConnectionId();
|
||||||
|
|
||||||
/* Store device in global PortAudio list */
|
/* Store device in global PortAudio list */
|
||||||
hostApi->deviceInfos[deviceIndex++] = (PaDeviceInfo *) hpiDevice;
|
hostApi->deviceInfos[deviceIndex++] = (PaDeviceInfo *) hpiDevice;
|
||||||
|
|
@ -678,7 +679,7 @@ static PaError PaAsiHpi_BuildDeviceList( PaAsiHpiHostApiRepresentation *hpiHostA
|
||||||
hpiDevice->streamIndex = j;
|
hpiDevice->streamIndex = j;
|
||||||
hpiDevice->streamIsOutput = 1;
|
hpiDevice->streamIsOutput = 1;
|
||||||
/* Set common PortAudio device stats */
|
/* Set common PortAudio device stats */
|
||||||
baseDeviceInfo->structVersion = 2;
|
baseDeviceInfo->structVersion = 3;
|
||||||
/* Make sure name string is owned by API info structure */
|
/* Make sure name string is owned by API info structure */
|
||||||
sprintf( srcName,
|
sprintf( srcName,
|
||||||
"Adapter %d (%4X) - Output Stream %d", i+1, type, j+1 );
|
"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,
|
/* HPI interface can actually handle any sampling rate to 1 Hz accuracy,
|
||||||
* so this default is as good as any */
|
* so this default is as good as any */
|
||||||
baseDeviceInfo->defaultSampleRate = 44100;
|
baseDeviceInfo->defaultSampleRate = 44100;
|
||||||
|
baseDeviceInfo->connectionId = PaUtil_MakeDeviceConnectionId();
|
||||||
|
|
||||||
/* Store device in global PortAudio list */
|
/* Store device in global PortAudio list */
|
||||||
hostApi->deviceInfos[deviceIndex++] = (PaDeviceInfo *) hpiDevice;
|
hostApi->deviceInfos[deviceIndex++] = (PaDeviceInfo *) hpiDevice;
|
||||||
|
|
@ -771,6 +773,9 @@ PaError PaAsiHpi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
|
||||||
(*hostApi)->Terminate = Terminate;
|
(*hostApi)->Terminate = Terminate;
|
||||||
(*hostApi)->OpenStream = OpenStream;
|
(*hostApi)->OpenStream = OpenStream;
|
||||||
(*hostApi)->IsFormatSupported = IsFormatSupported;
|
(*hostApi)->IsFormatSupported = IsFormatSupported;
|
||||||
|
(*hostApi)->ScanDeviceInfos = 0;
|
||||||
|
(*hostApi)->CommitDeviceInfos = 0;
|
||||||
|
(*hostApi)->DisposeDeviceInfos = 0;
|
||||||
|
|
||||||
PaUtil_InitializeStreamInterface( &hpiHostApi->callbackStreamInterface, CloseStream, StartStream,
|
PaUtil_InitializeStreamInterface( &hpiHostApi->callbackStreamInterface, CloseStream, StartStream,
|
||||||
StopStream, AbortStream, IsStreamStopped, IsStreamActive,
|
StopStream, AbortStream, IsStreamStopped, IsStreamActive,
|
||||||
|
|
|
||||||
|
|
@ -1322,10 +1322,11 @@ PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex
|
||||||
PaAsioDeviceInfo *asioDeviceInfo = &deviceInfoArray[ (*hostApi)->info.deviceCount ];
|
PaAsioDeviceInfo *asioDeviceInfo = &deviceInfoArray[ (*hostApi)->info.deviceCount ];
|
||||||
PaDeviceInfo *deviceInfo = &asioDeviceInfo->commonDeviceInfo;
|
PaDeviceInfo *deviceInfo = &asioDeviceInfo->commonDeviceInfo;
|
||||||
|
|
||||||
deviceInfo->structVersion = 2;
|
deviceInfo->structVersion = 3;
|
||||||
deviceInfo->hostApi = hostApiIndex;
|
deviceInfo->hostApi = hostApiIndex;
|
||||||
|
|
||||||
deviceInfo->name = names[i];
|
deviceInfo->name = names[i];
|
||||||
|
deviceInfo->connectionId = PaUtil_MakeDeviceConnectionId();
|
||||||
|
|
||||||
if( InitPaDeviceInfoFromAsioDriver( asioHostApi, names[i], i, deviceInfo, asioDeviceInfo ) == paNoError )
|
if( InitPaDeviceInfoFromAsioDriver( asioHostApi, names[i], i, deviceInfo, asioDeviceInfo ) == paNoError )
|
||||||
{
|
{
|
||||||
|
|
@ -1356,6 +1357,9 @@ PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex
|
||||||
(*hostApi)->Terminate = Terminate;
|
(*hostApi)->Terminate = Terminate;
|
||||||
(*hostApi)->OpenStream = OpenStream;
|
(*hostApi)->OpenStream = OpenStream;
|
||||||
(*hostApi)->IsFormatSupported = IsFormatSupported;
|
(*hostApi)->IsFormatSupported = IsFormatSupported;
|
||||||
|
(*hostApi)->ScanDeviceInfos = 0;
|
||||||
|
(*hostApi)->CommitDeviceInfos = 0;
|
||||||
|
(*hostApi)->DisposeDeviceInfos = 0;
|
||||||
|
|
||||||
PaUtil_InitializeStreamInterface( &asioHostApi->callbackStreamInterface, CloseStream, StartStream,
|
PaUtil_InitializeStreamInterface( &asioHostApi->callbackStreamInterface, CloseStream, StartStream,
|
||||||
StopStream, AbortStream, IsStreamStopped, IsStreamActive,
|
StopStream, AbortStream, IsStreamStopped, IsStreamActive,
|
||||||
|
|
|
||||||
|
|
@ -659,7 +659,7 @@ static PaError InitializeDeviceInfo( PaMacAUHAL *auhalHostApi,
|
||||||
|
|
||||||
memset(deviceInfo, 0, sizeof(PaDeviceInfo));
|
memset(deviceInfo, 0, sizeof(PaDeviceInfo));
|
||||||
|
|
||||||
deviceInfo->structVersion = 2;
|
deviceInfo->structVersion = 3;
|
||||||
deviceInfo->hostApi = hostApiIndex;
|
deviceInfo->hostApi = hostApiIndex;
|
||||||
|
|
||||||
/* Get the device name using CFString */
|
/* Get the device name using CFString */
|
||||||
|
|
@ -693,6 +693,7 @@ static PaError InitializeDeviceInfo( PaMacAUHAL *auhalHostApi,
|
||||||
CFRelease(nameRef);
|
CFRelease(nameRef);
|
||||||
}
|
}
|
||||||
deviceInfo->name = name;
|
deviceInfo->name = name;
|
||||||
|
deviceInfo->connectionId = PaUtil_MakeDeviceConnectionId();
|
||||||
|
|
||||||
/* Try to get the default sample rate. Don't fail if we can't get this. */
|
/* Try to get the default sample rate. Don't fail if we can't get this. */
|
||||||
propSize = sizeof(Float64);
|
propSize = sizeof(Float64);
|
||||||
|
|
@ -825,6 +826,9 @@ PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIn
|
||||||
(*hostApi)->Terminate = Terminate;
|
(*hostApi)->Terminate = Terminate;
|
||||||
(*hostApi)->OpenStream = OpenStream;
|
(*hostApi)->OpenStream = OpenStream;
|
||||||
(*hostApi)->IsFormatSupported = IsFormatSupported;
|
(*hostApi)->IsFormatSupported = IsFormatSupported;
|
||||||
|
(*hostApi)->ScanDeviceInfos = 0;
|
||||||
|
(*hostApi)->CommitDeviceInfos = 0;
|
||||||
|
(*hostApi)->DisposeDeviceInfos = 0;
|
||||||
|
|
||||||
PaUtil_InitializeStreamInterface( &auhalHostApi->callbackStreamInterface,
|
PaUtil_InitializeStreamInterface( &auhalHostApi->callbackStreamInterface,
|
||||||
CloseStream, StartStream,
|
CloseStream, StartStream,
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -573,7 +573,7 @@ static PaError BuildDeviceList( PaJackHostApiRepresentation *jackApi )
|
||||||
strlen(client_names[client_index]) + 1 ), paInsufficientMemory );
|
strlen(client_names[client_index]) + 1 ), paInsufficientMemory );
|
||||||
strcpy( (char *)curDevInfo->name, client_names[client_index] );
|
strcpy( (char *)curDevInfo->name, client_names[client_index] );
|
||||||
|
|
||||||
curDevInfo->structVersion = 2;
|
curDevInfo->structVersion = 3;
|
||||||
curDevInfo->hostApi = jackApi->hostApiIndex;
|
curDevInfo->hostApi = jackApi->hostApiIndex;
|
||||||
|
|
||||||
/* JACK is very inflexible: there is one sample rate the whole
|
/* 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;
|
commonApi->info.defaultInputDevice = client_index;
|
||||||
if( commonApi->info.defaultOutputDevice == paNoDevice && curDevInfo->maxOutputChannels > 0 )
|
if( commonApi->info.defaultOutputDevice == paNoDevice && curDevInfo->maxOutputChannels > 0 )
|
||||||
commonApi->info.defaultOutputDevice = client_index;
|
commonApi->info.defaultOutputDevice = client_index;
|
||||||
|
|
||||||
|
deviceInfo->connectionId = PaUtil_MakeDeviceConnectionId();
|
||||||
}
|
}
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
|
@ -756,6 +758,9 @@ PaError PaJack_Initialize( PaUtilHostApiRepresentation **hostApi,
|
||||||
(*hostApi)->Terminate = Terminate;
|
(*hostApi)->Terminate = Terminate;
|
||||||
(*hostApi)->OpenStream = OpenStream;
|
(*hostApi)->OpenStream = OpenStream;
|
||||||
(*hostApi)->IsFormatSupported = IsFormatSupported;
|
(*hostApi)->IsFormatSupported = IsFormatSupported;
|
||||||
|
(*hostApi)->ScanDeviceInfos = 0;
|
||||||
|
(*hostApi)->CommitDeviceInfos = 0;
|
||||||
|
(*hostApi)->DisposeDeviceInfos = 0;
|
||||||
|
|
||||||
PaUtil_InitializeStreamInterface( &jackHostApi->callbackStreamInterface,
|
PaUtil_InitializeStreamInterface( &jackHostApi->callbackStreamInterface,
|
||||||
CloseStream, StartStream,
|
CloseStream, StartStream,
|
||||||
|
|
|
||||||
|
|
@ -256,6 +256,9 @@ PaError PaOSS_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex
|
||||||
(*hostApi)->Terminate = Terminate;
|
(*hostApi)->Terminate = Terminate;
|
||||||
(*hostApi)->OpenStream = OpenStream;
|
(*hostApi)->OpenStream = OpenStream;
|
||||||
(*hostApi)->IsFormatSupported = IsFormatSupported;
|
(*hostApi)->IsFormatSupported = IsFormatSupported;
|
||||||
|
(*hostApi)->ScanDeviceInfos = 0;
|
||||||
|
(*hostApi)->CommitDeviceInfos = 0;
|
||||||
|
(*hostApi)->DisposeDeviceInfos = 0;
|
||||||
|
|
||||||
PA_ENSURE( BuildDeviceList( ossHostApi ) );
|
PA_ENSURE( BuildDeviceList( ossHostApi ) );
|
||||||
|
|
||||||
|
|
@ -295,7 +298,7 @@ PaError PaUtil_InitializeDeviceInfo( PaDeviceInfo *deviceInfo, const char *name,
|
||||||
{
|
{
|
||||||
PaError result = paNoError;
|
PaError result = paNoError;
|
||||||
|
|
||||||
deviceInfo->structVersion = 2;
|
deviceInfo->structVersion = 3;
|
||||||
if( allocations )
|
if( allocations )
|
||||||
{
|
{
|
||||||
size_t len = strlen( name ) + 1;
|
size_t len = strlen( name ) + 1;
|
||||||
|
|
@ -313,6 +316,7 @@ PaError PaUtil_InitializeDeviceInfo( PaDeviceInfo *deviceInfo, const char *name,
|
||||||
deviceInfo->defaultHighInputLatency = defaultHighInputLatency;
|
deviceInfo->defaultHighInputLatency = defaultHighInputLatency;
|
||||||
deviceInfo->defaultHighOutputLatency = defaultHighOutputLatency;
|
deviceInfo->defaultHighOutputLatency = defaultHighOutputLatency;
|
||||||
deviceInfo->defaultSampleRate = defaultSampleRate;
|
deviceInfo->defaultSampleRate = defaultSampleRate;
|
||||||
|
deviceInfo->connectionId = PaUtil_MakeDeviceConnectionId();
|
||||||
|
|
||||||
error:
|
error:
|
||||||
return result;
|
return result;
|
||||||
|
|
|
||||||
|
|
@ -209,6 +209,9 @@ PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiI
|
||||||
(*hostApi)->Terminate = Terminate;
|
(*hostApi)->Terminate = Terminate;
|
||||||
(*hostApi)->OpenStream = OpenStream;
|
(*hostApi)->OpenStream = OpenStream;
|
||||||
(*hostApi)->IsFormatSupported = IsFormatSupported;
|
(*hostApi)->IsFormatSupported = IsFormatSupported;
|
||||||
|
(*hostApi)->ScanDeviceInfos = 0;
|
||||||
|
(*hostApi)->CommitDeviceInfos = 0;
|
||||||
|
(*hostApi)->DisposeDeviceInfos = 0;
|
||||||
|
|
||||||
PaUtil_InitializeStreamInterface( &skeletonHostApi->callbackStreamInterface, CloseStream, StartStream,
|
PaUtil_InitializeStreamInterface( &skeletonHostApi->callbackStreamInterface, CloseStream, StartStream,
|
||||||
StopStream, AbortStream, IsStreamStopped, IsStreamActive,
|
StopStream, AbortStream, IsStreamStopped, IsStreamActive,
|
||||||
|
|
|
||||||
|
|
@ -1563,7 +1563,7 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
|
||||||
for (i = 0; i < paWasapi->deviceCount; ++i)
|
for (i = 0; i < paWasapi->deviceCount; ++i)
|
||||||
{
|
{
|
||||||
PaDeviceInfo *deviceInfo = &deviceInfoArray[i];
|
PaDeviceInfo *deviceInfo = &deviceInfoArray[i];
|
||||||
deviceInfo->structVersion = 2;
|
deviceInfo->structVersion = 3;
|
||||||
deviceInfo->hostApi = hostApiIndex;
|
deviceInfo->hostApi = hostApiIndex;
|
||||||
|
|
||||||
PA_DEBUG(("WASAPI: device idx: %02d\n", i));
|
PA_DEBUG(("WASAPI: device idx: %02d\n", i));
|
||||||
|
|
@ -1796,6 +1796,8 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deviceInfo->connectionId = PaUtil_MakeDeviceConnectionId();
|
||||||
|
|
||||||
(*hostApi)->deviceInfos[i] = deviceInfo;
|
(*hostApi)->deviceInfos[i] = deviceInfo;
|
||||||
++(*hostApi)->info.deviceCount;
|
++(*hostApi)->info.deviceCount;
|
||||||
}
|
}
|
||||||
|
|
@ -1804,6 +1806,9 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
|
||||||
(*hostApi)->Terminate = Terminate;
|
(*hostApi)->Terminate = Terminate;
|
||||||
(*hostApi)->OpenStream = OpenStream;
|
(*hostApi)->OpenStream = OpenStream;
|
||||||
(*hostApi)->IsFormatSupported = IsFormatSupported;
|
(*hostApi)->IsFormatSupported = IsFormatSupported;
|
||||||
|
(*hostApi)->ScanDeviceInfos = 0;
|
||||||
|
(*hostApi)->CommitDeviceInfos = 0;
|
||||||
|
(*hostApi)->DisposeDeviceInfos = 0;
|
||||||
|
|
||||||
PaUtil_InitializeStreamInterface( &paWasapi->callbackStreamInterface, CloseStream, StartStream,
|
PaUtil_InitializeStreamInterface( &paWasapi->callbackStreamInterface, CloseStream, StartStream,
|
||||||
StopStream, AbortStream, IsStreamStopped, IsStreamActive,
|
StopStream, AbortStream, IsStreamStopped, IsStreamActive,
|
||||||
|
|
|
||||||
|
|
@ -3442,6 +3442,22 @@ static unsigned GetNameIndex(PaNameHashObject* obj, const wchar_t* name, const B
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void FreeHostApiDeviceInfos( PaUtilAllocationGroup *allocations, PaDeviceInfo **deviceInfos, int deviceCount )
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < deviceCount; ++i)
|
||||||
|
{
|
||||||
|
PaWinWdmDeviceInfo* pDevice = (PaWinWdmDeviceInfo*)deviceInfos[i];
|
||||||
|
if (pDevice->filter != 0)
|
||||||
|
{
|
||||||
|
FilterFree(pDevice->filter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PaUtil_GroupFreeMemory( allocations, deviceInfos[0] ); /* all device info structs are allocated in a block so we can destroy them here */
|
||||||
|
PaUtil_GroupFreeMemory( allocations, deviceInfos );
|
||||||
|
}
|
||||||
|
|
||||||
static PaError ScanDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex hostApiIndex, void **scanResults, int *newDeviceCount )
|
static PaError ScanDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex hostApiIndex, void **scanResults, int *newDeviceCount )
|
||||||
{
|
{
|
||||||
PaWinWdmHostApiRepresentation *wdmHostApi = (PaWinWdmHostApiRepresentation*)hostApi;
|
PaWinWdmHostApiRepresentation *wdmHostApi = (PaWinWdmHostApiRepresentation*)hostApi;
|
||||||
|
|
@ -3514,7 +3530,7 @@ static PaError ScanDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaH
|
||||||
for( i = 0 ; i < totalDeviceCount; ++i )
|
for( i = 0 ; i < totalDeviceCount; ++i )
|
||||||
{
|
{
|
||||||
PaDeviceInfo *deviceInfo = &deviceInfoArray[i].inheritedDeviceInfo;
|
PaDeviceInfo *deviceInfo = &deviceInfoArray[i].inheritedDeviceInfo;
|
||||||
deviceInfo->structVersion = 2;
|
deviceInfo->structVersion = 3;
|
||||||
deviceInfo->hostApi = hostApiIndex;
|
deviceInfo->hostApi = hostApiIndex;
|
||||||
deviceInfo->name = 0;
|
deviceInfo->name = 0;
|
||||||
outArgument->deviceInfos[ i ] = deviceInfo;
|
outArgument->deviceInfos[ i ] = deviceInfo;
|
||||||
|
|
@ -3557,11 +3573,13 @@ static PaError ScanDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaH
|
||||||
|
|
||||||
wdmDeviceInfo->filter = pFilter;
|
wdmDeviceInfo->filter = pFilter;
|
||||||
|
|
||||||
deviceInfo->structVersion = 2;
|
deviceInfo->structVersion = 3;
|
||||||
deviceInfo->hostApi = hostApiIndex;
|
deviceInfo->hostApi = hostApiIndex;
|
||||||
deviceInfo->name = wdmDeviceInfo->compositeName;
|
deviceInfo->name = wdmDeviceInfo->compositeName;
|
||||||
/* deviceInfo->hostApiSpecificDeviceInfo = &pFilter->devInfo; */
|
/* deviceInfo->hostApiSpecificDeviceInfo = &pFilter->devInfo; */
|
||||||
|
|
||||||
|
deviceInfo->connectionId = PaUtil_MakeDeviceConnectionId();
|
||||||
|
|
||||||
wdmDeviceInfo->pin = pin->pinId;
|
wdmDeviceInfo->pin = pin->pinId;
|
||||||
|
|
||||||
/* Get the name of the "device" */
|
/* Get the name of the "device" */
|
||||||
|
|
@ -3706,22 +3724,17 @@ static PaError CommitDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, P
|
||||||
{
|
{
|
||||||
PaWinWdmHostApiRepresentation *wdmHostApi = (PaWinWdmHostApiRepresentation*)hostApi;
|
PaWinWdmHostApiRepresentation *wdmHostApi = (PaWinWdmHostApiRepresentation*)hostApi;
|
||||||
|
|
||||||
hostApi->info.deviceCount = 0;
|
|
||||||
hostApi->info.defaultInputDevice = paNoDevice;
|
|
||||||
hostApi->info.defaultOutputDevice = paNoDevice;
|
|
||||||
|
|
||||||
/* Free any old memory which might be in the device info */
|
/* Free any old memory which might be in the device info */
|
||||||
if( hostApi->deviceInfos )
|
if( hostApi->deviceInfos )
|
||||||
{
|
{
|
||||||
PaWinWDMScanDeviceInfosResults* localScanResults = (PaWinWDMScanDeviceInfosResults*)PaUtil_GroupAllocateMemory(
|
FreeHostApiDeviceInfos( wdmHostApi->allocations, hostApi->deviceInfos, hostApi->info.deviceCount );
|
||||||
wdmHostApi->allocations, sizeof(PaWinWDMScanDeviceInfosResults));
|
|
||||||
localScanResults->deviceInfos = hostApi->deviceInfos;
|
|
||||||
|
|
||||||
DisposeDeviceInfos(hostApi, &localScanResults, hostApi->info.deviceCount);
|
|
||||||
|
|
||||||
hostApi->deviceInfos = NULL;
|
hostApi->deviceInfos = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hostApi->info.deviceCount = 0;
|
||||||
|
hostApi->info.defaultInputDevice = paNoDevice;
|
||||||
|
hostApi->info.defaultOutputDevice = paNoDevice;
|
||||||
|
|
||||||
if( scanResults != NULL )
|
if( scanResults != NULL )
|
||||||
{
|
{
|
||||||
PaWinWDMScanDeviceInfosResults *scanDeviceInfosResults = ( PaWinWDMScanDeviceInfosResults * ) scanResults;
|
PaWinWDMScanDeviceInfosResults *scanDeviceInfosResults = ( PaWinWDMScanDeviceInfosResults * ) scanResults;
|
||||||
|
|
@ -3746,7 +3759,7 @@ static PaError CommitDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, P
|
||||||
|
|
||||||
static PaError DisposeDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, void *scanResults, int deviceCount )
|
static PaError DisposeDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, void *scanResults, int deviceCount )
|
||||||
{
|
{
|
||||||
PaWinWdmHostApiRepresentation *winDsHostApi = (PaWinWdmHostApiRepresentation*)hostApi;
|
PaWinWdmHostApiRepresentation *wdmHostApi = (PaWinWdmHostApiRepresentation*)hostApi;
|
||||||
|
|
||||||
if( scanResults != NULL )
|
if( scanResults != NULL )
|
||||||
{
|
{
|
||||||
|
|
@ -3754,21 +3767,10 @@ static PaError DisposeDeviceInfos( struct PaUtilHostApiRepresentation *hostApi,
|
||||||
|
|
||||||
if( scanDeviceInfosResults->deviceInfos )
|
if( scanDeviceInfosResults->deviceInfos )
|
||||||
{
|
{
|
||||||
int i;
|
FreeHostApiDeviceInfos( wdmHostApi->allocations, scanDeviceInfosResults->deviceInfos, hostApi->info.deviceCount );
|
||||||
for (i = 0; i < deviceCount; ++i)
|
|
||||||
{
|
|
||||||
PaWinWdmDeviceInfo* pDevice = (PaWinWdmDeviceInfo*)scanDeviceInfosResults->deviceInfos[i];
|
|
||||||
if (pDevice->filter != 0)
|
|
||||||
{
|
|
||||||
FilterFree(pDevice->filter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PaUtil_GroupFreeMemory( winDsHostApi->allocations, scanDeviceInfosResults->deviceInfos[0] ); /* all device info structs are allocated in a block so we can destroy them here */
|
|
||||||
PaUtil_GroupFreeMemory( winDsHostApi->allocations, scanDeviceInfosResults->deviceInfos );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PaUtil_GroupFreeMemory( winDsHostApi->allocations, scanDeviceInfosResults );
|
PaUtil_GroupFreeMemory( wdmHostApi->allocations, scanDeviceInfosResults );
|
||||||
}
|
}
|
||||||
|
|
||||||
return paNoError;
|
return paNoError;
|
||||||
|
|
@ -3853,11 +3855,10 @@ PaError PaWinWdm_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
|
||||||
(*hostApi)->Terminate = Terminate;
|
(*hostApi)->Terminate = Terminate;
|
||||||
(*hostApi)->OpenStream = OpenStream;
|
(*hostApi)->OpenStream = OpenStream;
|
||||||
(*hostApi)->IsFormatSupported = IsFormatSupported;
|
(*hostApi)->IsFormatSupported = IsFormatSupported;
|
||||||
/* In preparation for hotplug
|
|
||||||
(*hostApi)->ScanDeviceInfos = ScanDeviceInfos;
|
(*hostApi)->ScanDeviceInfos = ScanDeviceInfos;
|
||||||
(*hostApi)->CommitDeviceInfos = CommitDeviceInfos;
|
(*hostApi)->CommitDeviceInfos = CommitDeviceInfos;
|
||||||
(*hostApi)->DisposeDeviceInfos = DisposeDeviceInfos;
|
(*hostApi)->DisposeDeviceInfos = DisposeDeviceInfos;
|
||||||
*/
|
|
||||||
PaUtil_InitializeStreamInterface( &wdmHostApi->callbackStreamInterface, CloseStream, StartStream,
|
PaUtil_InitializeStreamInterface( &wdmHostApi->callbackStreamInterface, CloseStream, StartStream,
|
||||||
StopStream, AbortStream, IsStreamStopped, IsStreamActive,
|
StopStream, AbortStream, IsStreamStopped, IsStreamActive,
|
||||||
GetStreamTime, GetStreamCpuLoad,
|
GetStreamTime, GetStreamCpuLoad,
|
||||||
|
|
@ -3900,10 +3901,11 @@ static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
|
||||||
|
|
||||||
if( wdmHostApi)
|
if( wdmHostApi)
|
||||||
{
|
{
|
||||||
PaWinWDMScanDeviceInfosResults* localScanResults = (PaWinWDMScanDeviceInfosResults*)PaUtil_GroupAllocateMemory(
|
if( hostApi->deviceInfos )
|
||||||
wdmHostApi->allocations, sizeof(PaWinWDMScanDeviceInfosResults));
|
{
|
||||||
localScanResults->deviceInfos = hostApi->deviceInfos;
|
FreeHostApiDeviceInfos( wdmHostApi->allocations, hostApi->deviceInfos, hostApi->info.deviceCount );
|
||||||
DisposeDeviceInfos(hostApi, localScanResults, hostApi->info.deviceCount);
|
hostApi->deviceInfos = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if( wdmHostApi->allocations )
|
if( wdmHostApi->allocations )
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -789,6 +789,8 @@ static PaError InitializeInputDeviceInfo( PaWinMmeHostApiRepresentation *winMmeH
|
||||||
DetectDefaultSampleRate( winMmeDeviceInfo, winMmeInputDeviceId,
|
DetectDefaultSampleRate( winMmeDeviceInfo, winMmeInputDeviceId,
|
||||||
QueryInputWaveFormatEx, deviceInfo->maxInputChannels );
|
QueryInputWaveFormatEx, deviceInfo->maxInputChannels );
|
||||||
|
|
||||||
|
deviceInfo->connectionId = PaUtil_MakeDeviceConnectionId();
|
||||||
|
|
||||||
*success = 1;
|
*success = 1;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
|
@ -924,6 +926,8 @@ static PaError InitializeOutputDeviceInfo( PaWinMmeHostApiRepresentation *winMme
|
||||||
DetectDefaultSampleRate( winMmeDeviceInfo, winMmeOutputDeviceId,
|
DetectDefaultSampleRate( winMmeDeviceInfo, winMmeOutputDeviceId,
|
||||||
QueryOutputWaveFormatEx, deviceInfo->maxOutputChannels );
|
QueryOutputWaveFormatEx, deviceInfo->maxOutputChannels );
|
||||||
|
|
||||||
|
deviceInfo->connectionId = PaUtil_MakeDeviceConnectionId();
|
||||||
|
|
||||||
*success = 1;
|
*success = 1;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
|
@ -1069,7 +1073,7 @@ PaError PaWinMme_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
|
||||||
UINT winMmeDeviceId = (UINT)((i==-1) ? WAVE_MAPPER : i);
|
UINT winMmeDeviceId = (UINT)((i==-1) ? WAVE_MAPPER : i);
|
||||||
PaWinMmeDeviceInfo *wmmeDeviceInfo = &deviceInfoArray[ (*hostApi)->info.deviceCount ];
|
PaWinMmeDeviceInfo *wmmeDeviceInfo = &deviceInfoArray[ (*hostApi)->info.deviceCount ];
|
||||||
PaDeviceInfo *deviceInfo = &wmmeDeviceInfo->inheritedDeviceInfo;
|
PaDeviceInfo *deviceInfo = &wmmeDeviceInfo->inheritedDeviceInfo;
|
||||||
deviceInfo->structVersion = 2;
|
deviceInfo->structVersion = 3;
|
||||||
deviceInfo->hostApi = hostApiIndex;
|
deviceInfo->hostApi = hostApiIndex;
|
||||||
|
|
||||||
deviceInfo->maxInputChannels = 0;
|
deviceInfo->maxInputChannels = 0;
|
||||||
|
|
@ -1112,7 +1116,7 @@ PaError PaWinMme_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
|
||||||
UINT winMmeDeviceId = (UINT)((i==-1) ? WAVE_MAPPER : i);
|
UINT winMmeDeviceId = (UINT)((i==-1) ? WAVE_MAPPER : i);
|
||||||
PaWinMmeDeviceInfo *wmmeDeviceInfo = &deviceInfoArray[ (*hostApi)->info.deviceCount ];
|
PaWinMmeDeviceInfo *wmmeDeviceInfo = &deviceInfoArray[ (*hostApi)->info.deviceCount ];
|
||||||
PaDeviceInfo *deviceInfo = &wmmeDeviceInfo->inheritedDeviceInfo;
|
PaDeviceInfo *deviceInfo = &wmmeDeviceInfo->inheritedDeviceInfo;
|
||||||
deviceInfo->structVersion = 2;
|
deviceInfo->structVersion = 3;
|
||||||
deviceInfo->hostApi = hostApiIndex;
|
deviceInfo->hostApi = hostApiIndex;
|
||||||
|
|
||||||
deviceInfo->maxInputChannels = 0;
|
deviceInfo->maxInputChannels = 0;
|
||||||
|
|
@ -1155,6 +1159,9 @@ PaError PaWinMme_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
|
||||||
(*hostApi)->Terminate = Terminate;
|
(*hostApi)->Terminate = Terminate;
|
||||||
(*hostApi)->OpenStream = OpenStream;
|
(*hostApi)->OpenStream = OpenStream;
|
||||||
(*hostApi)->IsFormatSupported = IsFormatSupported;
|
(*hostApi)->IsFormatSupported = IsFormatSupported;
|
||||||
|
(*hostApi)->ScanDeviceInfos = 0;
|
||||||
|
(*hostApi)->CommitDeviceInfos = 0;
|
||||||
|
(*hostApi)->DisposeDeviceInfos = 0;
|
||||||
|
|
||||||
PaUtil_InitializeStreamInterface( &winMmeHostApi->callbackStreamInterface, CloseStream, StartStream,
|
PaUtil_InitializeStreamInterface( &winMmeHostApi->callbackStreamInterface, CloseStream, StartStream,
|
||||||
StopStream, AbortStream, IsStreamStopped, IsStreamActive,
|
StopStream, AbortStream, IsStreamStopped, IsStreamActive,
|
||||||
|
|
|
||||||
348
src/os/win/pa_win_hotplug.c
Normal file
348
src/os/win/pa_win_hotplug.c
Normal file
|
|
@ -0,0 +1,348 @@
|
||||||
|
/*
|
||||||
|
* $Id$
|
||||||
|
* Portable Audio I/O Library
|
||||||
|
* Hotplug interface and utilities
|
||||||
|
* Copyright (c) 2011-2016 Robert Bielik
|
||||||
|
*
|
||||||
|
* Based on the Open Source API proposed by Ross Bencina
|
||||||
|
* Copyright (c) 1999-2016 Ross Bencina, Phil Burk
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files
|
||||||
|
* (the "Software"), to deal in the Software without restriction,
|
||||||
|
* including without limitation the rights to use, copy, modify, merge,
|
||||||
|
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||||
|
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||||
|
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text above constitutes the entire PortAudio license; however,
|
||||||
|
* the PortAudio community also makes the following non-binding requests:
|
||||||
|
*
|
||||||
|
* Any person wishing to distribute modifications to the Software is
|
||||||
|
* requested to send the modifications to the original developer so that
|
||||||
|
* they can be incorporated into the canonical version. It is also
|
||||||
|
* requested that these non-binding requests be included along with the
|
||||||
|
* license above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "pa_hotplug.h"
|
||||||
|
#include "pa_util.h"
|
||||||
|
#include "pa_debugprint.h"
|
||||||
|
#include "pa_allocation.h"
|
||||||
|
|
||||||
|
#include "pa_win_wdmks_utils.h"
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <dbt.h>
|
||||||
|
#include <process.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <ks.h>
|
||||||
|
#include <ksmedia.h>
|
||||||
|
|
||||||
|
#include <setupapi.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#if (defined(WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) /* MSC version 6 and above */
|
||||||
|
#pragma comment( lib, "setupapi.lib" )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* use CreateThread for CYGWIN/Windows Mobile, _beginthreadex for all others */
|
||||||
|
#if !defined(__CYGWIN__) && !defined(_WIN32_WCE)
|
||||||
|
#define CREATE_THREAD_FUNCTION (HANDLE)_beginthreadex
|
||||||
|
#define PA_THREAD_FUNC static unsigned WINAPI
|
||||||
|
#else
|
||||||
|
#define CREATE_THREAD_FUNCTION CreateThread
|
||||||
|
#define PA_THREAD_FUNC static DWORD WINAPI
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct PaHotPlugDeviceInfo
|
||||||
|
{
|
||||||
|
wchar_t name[MAX_PATH];
|
||||||
|
struct PaHotPlugDeviceInfo* next;
|
||||||
|
} PaHotPlugDeviceInfo;
|
||||||
|
|
||||||
|
typedef struct PaHotPlugDeviceEventHandlerInfo
|
||||||
|
{
|
||||||
|
HANDLE hWnd;
|
||||||
|
HANDLE hMsgThread;
|
||||||
|
HANDLE hNotify;
|
||||||
|
CRITICAL_SECTION lock;
|
||||||
|
PaUtilAllocationGroup* cacheAllocGroup;
|
||||||
|
PaHotPlugDeviceInfo* cache;
|
||||||
|
|
||||||
|
} PaHotPlugDeviceEventHandlerInfo;
|
||||||
|
|
||||||
|
|
||||||
|
static BOOL RemoveDeviceFromCache(PaHotPlugDeviceEventHandlerInfo* pInfo, const wchar_t* name)
|
||||||
|
{
|
||||||
|
if (pInfo->cache != NULL)
|
||||||
|
{
|
||||||
|
PaHotPlugDeviceInfo* lastEntry = 0;
|
||||||
|
PaHotPlugDeviceInfo* entry = pInfo->cache;
|
||||||
|
while (entry != NULL)
|
||||||
|
{
|
||||||
|
if (_wcsicmp(entry->name, name) == 0)
|
||||||
|
{
|
||||||
|
if (lastEntry)
|
||||||
|
{
|
||||||
|
lastEntry->next = entry->next;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pInfo->cache = NULL;
|
||||||
|
}
|
||||||
|
PaUtil_GroupFreeMemory(pInfo->cacheAllocGroup, entry);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastEntry = entry;
|
||||||
|
entry = entry->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void InsertDeviceIntoCache(PaHotPlugDeviceEventHandlerInfo* pInfo, const wchar_t* name)
|
||||||
|
{
|
||||||
|
PaHotPlugDeviceInfo** ppEntry = NULL;
|
||||||
|
|
||||||
|
/* Remove it first (if possible) so we don't accidentally get duplicates */
|
||||||
|
RemoveDeviceFromCache(pInfo, name);
|
||||||
|
|
||||||
|
if (pInfo->cache == NULL)
|
||||||
|
{
|
||||||
|
ppEntry = &pInfo->cache;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PaHotPlugDeviceInfo* entry = pInfo->cache;
|
||||||
|
while (entry->next != NULL)
|
||||||
|
{
|
||||||
|
entry = entry->next;
|
||||||
|
}
|
||||||
|
ppEntry = &entry->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
*ppEntry = (PaHotPlugDeviceInfo*)PaUtil_GroupAllocateMemory(pInfo->cacheAllocGroup, sizeof(PaHotPlugDeviceInfo));
|
||||||
|
wcsncpy((*ppEntry)->name, name, MAX_PATH-1);
|
||||||
|
(*ppEntry)->next = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL IsDeviceAudio(const wchar_t* deviceName)
|
||||||
|
{
|
||||||
|
int channelCnt = 0;
|
||||||
|
channelCnt += PaWin_WDMKS_QueryFilterMaximumChannelCount((void*)deviceName, 1);
|
||||||
|
channelCnt += PaWin_WDMKS_QueryFilterMaximumChannelCount((void*)deviceName, 0);
|
||||||
|
return (channelCnt > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void PopulateCacheWithAvailableAudioDevices(PaHotPlugDeviceEventHandlerInfo* pInfo)
|
||||||
|
{
|
||||||
|
HDEVINFO handle = NULL;
|
||||||
|
const int sizeInterface = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) + (MAX_PATH * sizeof(WCHAR));
|
||||||
|
SP_DEVICE_INTERFACE_DETAIL_DATA_W* devInterfaceDetails = (SP_DEVICE_INTERFACE_DETAIL_DATA_W*)PaUtil_AllocateMemory(sizeInterface);
|
||||||
|
|
||||||
|
if (devInterfaceDetails)
|
||||||
|
{
|
||||||
|
devInterfaceDetails->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
|
||||||
|
|
||||||
|
/* Open a handle to search for devices (filters) */
|
||||||
|
handle = SetupDiGetClassDevsW(&KSCATEGORY_AUDIO,NULL,NULL,DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
|
||||||
|
if( handle != NULL )
|
||||||
|
{
|
||||||
|
int device;
|
||||||
|
|
||||||
|
/* Iterate through the devices */
|
||||||
|
for( device = 0;;device++ )
|
||||||
|
{
|
||||||
|
SP_DEVICE_INTERFACE_DATA interfaceData;
|
||||||
|
SP_DEVINFO_DATA devInfoData;
|
||||||
|
int noError;
|
||||||
|
|
||||||
|
interfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
|
||||||
|
interfaceData.Reserved = 0;
|
||||||
|
devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
|
||||||
|
devInfoData.Reserved = 0;
|
||||||
|
|
||||||
|
noError = SetupDiEnumDeviceInterfaces(handle,NULL,&KSCATEGORY_AUDIO,device,&interfaceData);
|
||||||
|
if( !noError )
|
||||||
|
break; /* No more devices */
|
||||||
|
|
||||||
|
noError = SetupDiGetDeviceInterfaceDetailW(handle,&interfaceData,devInterfaceDetails,sizeInterface,NULL,&devInfoData);
|
||||||
|
if( noError )
|
||||||
|
{
|
||||||
|
if (IsDeviceAudio(devInterfaceDetails->DevicePath))
|
||||||
|
{
|
||||||
|
PA_DEBUG(("Hotplug cache populated with: '%S'\n", devInterfaceDetails->DevicePath));
|
||||||
|
InsertDeviceIntoCache(pInfo, devInterfaceDetails->DevicePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SetupDiDestroyDeviceInfoList(handle);
|
||||||
|
}
|
||||||
|
PaUtil_FreeMemory(devInterfaceDetails);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static LRESULT CALLBACK PaMsgWinProcW(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
PaHotPlugDeviceEventHandlerInfo* pInfo = (PaHotPlugDeviceEventHandlerInfo*)( GetWindowLongPtr(hWnd, GWLP_USERDATA) );
|
||||||
|
switch(msg)
|
||||||
|
{
|
||||||
|
case WM_DEVICECHANGE:
|
||||||
|
switch(wParam)
|
||||||
|
{
|
||||||
|
case DBT_DEVICEARRIVAL:
|
||||||
|
{
|
||||||
|
PDEV_BROADCAST_DEVICEINTERFACE_W ptr = (PDEV_BROADCAST_DEVICEINTERFACE_W)lParam;
|
||||||
|
if (ptr->dbcc_devicetype != DBT_DEVTYP_DEVICEINTERFACE)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!IsEqualGUID(&ptr->dbcc_classguid, &KSCATEGORY_AUDIO))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (IsDeviceAudio(ptr->dbcc_name))
|
||||||
|
{
|
||||||
|
PA_DEBUG(("Device inserted : %S\n", ptr->dbcc_name));
|
||||||
|
InsertDeviceIntoCache(pInfo, ptr->dbcc_name);
|
||||||
|
PaUtil_DevicesChanged(1, ptr->dbcc_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DBT_DEVICEREMOVECOMPLETE:
|
||||||
|
{
|
||||||
|
PDEV_BROADCAST_DEVICEINTERFACE_W ptr = (PDEV_BROADCAST_DEVICEINTERFACE_W)lParam;
|
||||||
|
if (ptr->dbcc_devicetype != DBT_DEVTYP_DEVICEINTERFACE)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!IsEqualGUID(&ptr->dbcc_classguid, &KSCATEGORY_AUDIO))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (RemoveDeviceFromCache(pInfo, ptr->dbcc_name))
|
||||||
|
{
|
||||||
|
PA_DEBUG(("Device removed : %S\n", ptr->dbcc_name));
|
||||||
|
PaUtil_DevicesChanged(2, ptr->dbcc_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return DefWindowProcW(hWnd, msg, wParam, lParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
PA_THREAD_FUNC PaRunMessageLoop(void* ptr)
|
||||||
|
{
|
||||||
|
PaHotPlugDeviceEventHandlerInfo* pInfo = (PaHotPlugDeviceEventHandlerInfo*)ptr;
|
||||||
|
WNDCLASSW wnd = { 0 };
|
||||||
|
HMODULE hInstance = GetModuleHandleW(NULL);
|
||||||
|
|
||||||
|
wnd.lpfnWndProc = PaMsgWinProcW;
|
||||||
|
wnd.hInstance = hInstance;
|
||||||
|
wnd.lpszClassName = L"{1E0D4F5A-B31F-4dcc-AE3C-4F30A47BD521}"; /* Using a GUID as class name */
|
||||||
|
pInfo->hWnd = CreateWindowW((LPCWSTR)MAKEINTATOM(RegisterClassW(&wnd)), NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, hInstance, NULL);
|
||||||
|
if (pInfo->hWnd)
|
||||||
|
{
|
||||||
|
DEV_BROADCAST_DEVICEINTERFACE_W NotificationFilter = { sizeof(DEV_BROADCAST_DEVICEINTERFACE_W) };
|
||||||
|
NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
|
||||||
|
|
||||||
|
#ifndef DEVICE_NOTIFY_ALL_INTERFACE_CLASSES
|
||||||
|
#define DEVICE_NOTIFY_ALL_INTERFACE_CLASSES 0x00000004
|
||||||
|
#endif
|
||||||
|
|
||||||
|
pInfo->hNotify = RegisterDeviceNotificationW(
|
||||||
|
pInfo->hWnd,
|
||||||
|
&NotificationFilter,
|
||||||
|
DEVICE_NOTIFY_WINDOW_HANDLE|DEVICE_NOTIFY_ALL_INTERFACE_CLASSES
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(pInfo->hNotify);
|
||||||
|
|
||||||
|
SetWindowLongPtr(pInfo->hWnd, GWLP_USERDATA, (LONG_PTR)pInfo);
|
||||||
|
|
||||||
|
if (pInfo->hNotify)
|
||||||
|
{
|
||||||
|
MSG msg;
|
||||||
|
BOOL result;
|
||||||
|
while((result = GetMessageW(&msg, pInfo->hWnd, 0, 0)) != 0)
|
||||||
|
{
|
||||||
|
if (result == -1)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
TranslateMessage(&msg);
|
||||||
|
DispatchMessageW(&msg);
|
||||||
|
}
|
||||||
|
UnregisterDeviceNotification(pInfo->hNotify);
|
||||||
|
pInfo->hNotify = 0;
|
||||||
|
}
|
||||||
|
DestroyWindow(pInfo->hWnd);
|
||||||
|
pInfo->hWnd = 0;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PaHotPlugDeviceEventHandlerInfo* s_handler = 0;
|
||||||
|
|
||||||
|
void PaUtil_InitializeHotPlug()
|
||||||
|
{
|
||||||
|
if (s_handler == 0)
|
||||||
|
{
|
||||||
|
s_handler = (PaHotPlugDeviceEventHandlerInfo*)PaUtil_AllocateMemory(sizeof(PaHotPlugDeviceEventHandlerInfo));
|
||||||
|
if (s_handler)
|
||||||
|
{
|
||||||
|
s_handler->cacheAllocGroup = PaUtil_CreateAllocationGroup();
|
||||||
|
InitializeCriticalSection(&s_handler->lock);
|
||||||
|
PopulateCacheWithAvailableAudioDevices(s_handler);
|
||||||
|
/* Start message thread */
|
||||||
|
s_handler->hMsgThread = CREATE_THREAD_FUNCTION(NULL, 0, PaRunMessageLoop, s_handler, 0, NULL);
|
||||||
|
assert(s_handler->hMsgThread != 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PaUtil_TerminateHotPlug()
|
||||||
|
{
|
||||||
|
if (s_handler != 0)
|
||||||
|
{
|
||||||
|
if (s_handler->hWnd)
|
||||||
|
{
|
||||||
|
PostMessage(s_handler->hWnd, WM_QUIT, 0, 0);
|
||||||
|
if (WaitForSingleObject(s_handler->hMsgThread, 1000) == WAIT_TIMEOUT)
|
||||||
|
{
|
||||||
|
TerminateThread(s_handler->hMsgThread, (DWORD)-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DeleteCriticalSection(&s_handler->lock);
|
||||||
|
PaUtil_FreeAllAllocations( s_handler->cacheAllocGroup );
|
||||||
|
PaUtil_DestroyAllocationGroup( s_handler->cacheAllocGroup );
|
||||||
|
PaUtil_FreeMemory( s_handler );
|
||||||
|
s_handler = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PaUtil_LockHotPlug()
|
||||||
|
{
|
||||||
|
EnterCriticalSection(&s_handler->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PaUtil_UnlockHotPlug()
|
||||||
|
{
|
||||||
|
LeaveCriticalSection(&s_handler->lock);
|
||||||
|
}
|
||||||
50
test/patest_refresh_device_list.c
Normal file
50
test/patest_refresh_device_list.c
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "portaudio.h"
|
||||||
|
|
||||||
|
void printDevices()
|
||||||
|
{
|
||||||
|
int deviceCount = Pa_GetDeviceCount();
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for( i=0; i < deviceCount; ++i ){
|
||||||
|
const PaDeviceInfo *deviceInfo = Pa_GetDeviceInfo(i);
|
||||||
|
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 (conn id: %lu) %s (%s)\n", i, deviceInfo->connectionId, deviceInfo->name, hostApiInfo->name );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void devicesChangedCallback(void* p)
|
||||||
|
{
|
||||||
|
(void)p;
|
||||||
|
|
||||||
|
printf( "Portaudio device list have changed!\n" );
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void);
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
Pa_Initialize();
|
||||||
|
|
||||||
|
Pa_SetDevicesChangedCallback(NULL, devicesChangedCallback);
|
||||||
|
|
||||||
|
for(;;){
|
||||||
|
printDevices();
|
||||||
|
|
||||||
|
printf( "press [enter] to update the device list. or q + [enter] to quit.\n" );
|
||||||
|
if( getchar() == 'q' )
|
||||||
|
break;
|
||||||
|
|
||||||
|
Pa_RefreshDeviceList();
|
||||||
|
}
|
||||||
|
|
||||||
|
Pa_Terminate();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
Loading…
Reference in a new issue