Compare commits

...
Sign in to create a new pull request.
7 changed files with 463 additions and 29 deletions

View file

@ -35,6 +35,10 @@ Pa_GetStreamReadAvailable @31
Pa_GetStreamWriteAvailable @32
Pa_GetSampleSize @33
Pa_Sleep @34
Pa_GetAvailableHostApisCount @35
Pa_GetAvailableHostApis @36
Pa_SelectHostApis @37
Pa_GetSelectedHostApis @38
PaAsio_GetAvailableBufferSizes @50
PaAsio_ShowControlPanel @51
PaUtil_InitializeX86PlainConverters @52

View file

@ -134,7 +134,8 @@ typedef enum PaErrorCode
paCanNotReadFromAnOutputOnlyStream,
paCanNotWriteToAnInputOnlyStream,
paIncompatibleStreamHostApi,
paBadBufferPtr
paBadBufferPtr,
paIsInitialized
} PaErrorCode;
@ -274,6 +275,103 @@ typedef enum PaHostApiTypeId
} PaHostApiTypeId;
/** Returns the number of compiled-in host APIs in this build of PortAudio.
The returned value is large enough that it can be used to dimension
arrays passed to Pa_GetAvailableHostApis and Pa_GetSelectedHostApis.
FIXME REVIEW The "Available" name should match whatever is chosen for
Pa_GetAvailableHostApis
@see Pa_GetAvailableHostApis, Pa_GetSelectedHostApis
*/
int Pa_GetAvailableHostApisCount( void );
/** Returns the type ids of all compiled-in host APIs in initialization order.
Note that the compiled-in host APIs are not necessarily those that are
installed on the system. It is possible for compiled-in dynamically loaded
host APIs to be not installed on the system, and it is possible for
installed audio APIs to not be supported (compiled in to) PortAudio.
@param hostApiTypes (OUT) An array that will be filled with
host API identifiers, having values belonging to the PaHostApiTypeId enumeration.
@param arrayCapacity The number of usable elements in the hostApiTypes array.
This value never need by greater than the value returned by
Pa_GetAvailableHostApisCount().
@param count (OUT) The number of host APIs, returned even on error.
Upon success, this will be the number of valid elements stored in hostApiTypes.
FIXME REVIEW: Consider a different name for this function, both "available"
and "supported" are ambiguous between what is available/supported on the
target platform and what is compiled into PA. Keep in mind that
Pa_IsFormatSupported refers to formats supported by a device.
Proposals:
GetConfiguredHostApis, GetCompiledHostApis
NOTE: also fix name oPa_GetAvailableHostApisCount
@see Pa_SelectHostApis
*/
PaError Pa_GetAvailableHostApis( PaHostApiTypeId *hostApiTypes, int arrayCapacity, int *count );
/** Select host APIs and their initialization order.
This function may only be called prior to calling Pa_Initialize()
or after calling Pa_Terminate(). The selected host APIs take effect the
next time that Pa_Initialize() is invoked.
@param hostApiTypes An array of host API identifiers, having values belonging
to the PaHostApiTypeId enumeration. The specified host APIs must selected
from thosed returned by Pa_GetAvailableHostApis(). For example, it would be an
error to specify a Windows host API while using PortAudio on Mac OS X.
@param count The number of elements in the hostApiTypes array. A count of
zero causes the default host API selection to be restored.
@return A PaErrorCode indicating whether the call succeeded or failed.
The paHostApiNotFound error code indicates that a host API specified by the
hostApiTypeIds parameter is not available.
The paInvalidHostApi error indicates that there was a problem with the
hostApiTypes array. E.g. it contained invalid or duplicate entries.
@note The host API initialization order determines default devices.
There is no predictable relationship between the order that host APIs appear
in hostApiTypes, and their hostApiIndexes assigned by Pa_Initialize().
@see PaHostApiTypeId
*/
PaError Pa_SelectHostApis( const PaHostApiTypeId *hostApiTypes, int count );
/** Returns the type ids of the selected host APIs in initialization order.
@param hostApiTypes (OUT) An array that will be filled with
host API identifiers, having values belonging to the PaHostApiTypeId enumeration.
@param arrayCapacity The number of usable elements in the hostApiTypes array.
This value never need by greater than the value returned by
Pa_GetAvailableHostApisCount().
@param count (OUT) The number of selected host APIs, returned even on error.
Upon success, this will be the number of valid elements stored in hostApiTypes.
@return A PaErrorCode indicating whether the call succeeded or failed.
The paInsufficientMemory error indicates that arrayCapacity was not large enough
to accommodate the list of selected host APIs. In this case, the needed
count is returned in the count parameter.
@see Pa_SelectHostApis
*/
PaError Pa_GetSelectedHostApis( PaHostApiTypeId *hostApiTypes, int arrayCapacity, int *count );
/** A structure containing information about a particular host API. */
typedef struct PaHostApiInfo

View file

@ -152,7 +152,6 @@ void PaUtil_SetLastHostErrorInfo( PaHostApiTypeId hostApiType, long errorCode,
}
static PaUtilHostApiRepresentation **hostApis_ = 0;
static int hostApisCount_ = 0;
static int defaultHostApiIndex_ = 0;
@ -161,20 +160,179 @@ static int deviceCount_ = 0;
PaUtilStreamRepresentation *firstOpenStream_ = NULL;
#define PA_IS_INITIALISED_ (initializationCount_ != 0)
/*
By default, selectedHostApiTypes_ == NULL and PortAudio initializes all
host APIs in the order that they are listed in paHostApiInitializers[].
If selectedHostApiTypes_ != NULL, then APIs are initialized in the
order specified in selectedHostApiTypes_.
*/
static PaHostApiTypeId *selectedHostApiTypes_ = NULL;
static int selectedHostApiCount_ = 0;
static int CountHostApiInitializers( void )
{
int result = 0;
while( paHostApiInitializers[ result ] != 0 )
while( paHostApiInitializers[ result ].initFunction != 0 )
++result;
return result;
}
static const PaUtilHostApiInitializerEntry* FindHostApiInitializerEntry( PaHostApiTypeId hostApiType )
{
int i = 0;
while( paHostApiInitializers[ i ].initFunction != 0 )
{
if( paHostApiInitializers[i].hostApiType == hostApiType )
return &paHostApiInitializers[i];
++i;
}
return NULL;
}
int Pa_GetAvailableHostApisCount( void )
{
return CountHostApiInitializers();
}
PaError Pa_GetAvailableHostApis( PaHostApiTypeId *hostApiTypes, int arrayCapacity, int *count )
{
int i;
int initializerCount = CountHostApiInitializers();
*count = initializerCount;
if( arrayCapacity >= initializerCount )
{
for( i=0; i < initializerCount; ++i )
hostApiTypes[i] = paHostApiInitializers[i].hostApiType;
}
else
{
return paInsufficientMemory;
}
return paNoError;
}
static int CountSelectedHostApis()
{
if( selectedHostApiTypes_ == NULL )
return CountHostApiInitializers();
else
return selectedHostApiCount_;
}
static const PaUtilHostApiInitializerEntry* GetSelectedHostApi( int index )
{
if( selectedHostApiTypes_ == NULL )
return &paHostApiInitializers[index];
else
return FindHostApiInitializerEntry( selectedHostApiTypes_[index] );
}
PaError Pa_SelectHostApis( const PaHostApiTypeId *hostApiTypes, int count )
{
int i, j;
PaHostApiTypeId *oldSelectedHostApiTypes = selectedHostApiTypes_;
PaHostApiTypeId *newSelectedHostApiTypes = NULL;
if( PA_IS_INITIALISED_ )
{
return paIsInitialized;
}
if( count == 0 )
{
/* revert to default state */
if( selectedHostApiTypes_ )
{
PaUtil_FreeMemory( selectedHostApiTypes_ );
selectedHostApiTypes_ = NULL;
selectedHostApiCount_ = 0;
}
return paNoError;
}
if( count < 0 )
return paInvalidHostApi;
if( hostApiTypes == NULL )
return paInvalidHostApi;
/* validation:
- verify that each hostApiTypes value is available (present in paHostApiInitializers)
- verify that hostApiTypes contains no duplicates
*/
for( i=0; i < count; ++i )
{
if( FindHostApiInitializerEntry( hostApiTypes[i] ) == NULL )
return paHostApiNotFound;
for( j=i+1; j < count; ++j )
{
if (hostApiTypes[i] == hostApiTypes[j])
return paInvalidHostApi;
}
}
/* allocate a newSelectedHostApiTypes, copy ids into it */
newSelectedHostApiTypes = (PaHostApiTypeId*)PaUtil_AllocateMemory(
sizeof(PaHostApiTypeId) * count );
if( newSelectedHostApiTypes == NULL )
return paInsufficientMemory;
memcpy( newSelectedHostApiTypes, hostApiTypes, count*sizeof(PaHostApiTypeId) );
/* install new selectedHostApis and free old selectedHostApis_ */
selectedHostApiTypes_ = newSelectedHostApiTypes;
selectedHostApiCount_ = count;
if( oldSelectedHostApiTypes != NULL )
{
PaUtil_FreeMemory( oldSelectedHostApiTypes );
oldSelectedHostApiTypes = NULL;
}
return paNoError;
}
PaError Pa_GetSelectedHostApis( PaHostApiTypeId *hostApiTypes, int arrayCapacity, int *count )
{
if( selectedHostApiTypes_ == NULL )
{
return Pa_GetAvailableHostApis( hostApiTypes, arrayCapacity, count );
}
else
{
*count = selectedHostApiCount_;
if( arrayCapacity >= selectedHostApiCount_ )
{
memcpy( hostApiTypes, selectedHostApiTypes_, selectedHostApiCount_*sizeof(PaHostApiTypeId) );
return paNoError;
}
else
{
return paInsufficientMemory;
}
}
}
static void TerminateHostApis( void )
{
/* terminate in reverse order from initialization */
@ -201,8 +359,9 @@ static PaError InitializeHostApis( void )
{
PaError result = paNoError;
int i, initializerCount, baseDeviceIndex;
const PaUtilHostApiInitializerEntry *hostApiInitializer;
initializerCount = CountHostApiInitializers();
initializerCount = CountSelectedHostApis();
hostApis_ = (PaUtilHostApiRepresentation**)PaUtil_AllocateMemory(
sizeof(PaUtilHostApiRepresentation*) * initializerCount );
@ -223,7 +382,9 @@ static PaError InitializeHostApis( void )
PA_DEBUG(( "before paHostApiInitializers[%d].\n",i));
result = paHostApiInitializers[i]( &hostApis_[hostApisCount_], hostApisCount_ );
hostApiInitializer = GetSelectedHostApi(i);
assert( hostApiInitializer != NULL );
result = hostApiInitializer->initFunction( &hostApis_[hostApisCount_], hostApisCount_ );
if( result != paNoError )
goto error;

View file

@ -338,12 +338,22 @@ typedef struct PaUtilHostApiRepresentation {
*/
typedef PaError PaUtilHostApiInitializer( PaUtilHostApiRepresentation**, PaHostApiIndex );
/** Associate a PaHostApiTypeId with each host API initialization function.
*/
typedef struct {
PaHostApiTypeId hostApiType;
PaUtilHostApiInitializer *initFunction;
} PaUtilHostApiInitializerEntry;
/** paHostApiInitializers is a NULL-terminated array of host API initialization
functions. These functions are called by pa_front.c to initialize the host APIs
when the client calls Pa_Initialize().
entries, each containing an initialization function. The initialization
functions are called by pa_front.c to initialize the host APIs when the client
calls Pa_Initialize().
The initialization functions are invoked in order.
By default initialization functions are invoked in order. The initialization
order may be modified by the client using Pa_SelectHostApis().
The first successfully initialized host API that has a default input *or* output
device is used as the default PortAudio host API. This is based on the logic that
@ -353,7 +363,7 @@ typedef PaError PaUtilHostApiInitializer( PaUtilHostApiRepresentation**, PaHostA
There is a platform specific file that defines paHostApiInitializers for that
platform, pa_win/pa_win_hostapis.c contains the Win32 definitions for example.
*/
extern PaUtilHostApiInitializer *paHostApiInitializers[];
extern PaUtilHostApiInitializerEntry paHostApiInitializers[];
#ifdef __cplusplus

View file

@ -55,49 +55,50 @@ PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiI
/** Note that on Linux, ALSA is placed before OSS so that the former is preferred over the latter.
*/
PaUtilHostApiInitializer *paHostApiInitializers[] =
PaUtilHostApiInitializerEntry paHostApiInitializers[] =
{
#ifdef __linux__
#if PA_USE_ALSA
PaAlsa_Initialize,
{ paALSA, PaAlsa_Initialize },
#endif
#if PA_USE_OSS
PaOSS_Initialize,
{ paOSS, PaOSS_Initialize },
#endif
#else /* __linux__ */
#if PA_USE_OSS
PaOSS_Initialize,
{ paOSS, PaOSS_Initialize },
#endif
#if PA_USE_ALSA
PaAlsa_Initialize,
{ paALSA, PaAlsa_Initialize },
#endif
#endif /* __linux__ */
#if PA_USE_JACK
PaJack_Initialize,
{ paJACK, PaJack_Initialize },
#endif
/* Added for IRIX, Pieter, oct 2, 2003: */
#if PA_USE_SGI
PaSGI_Initialize,
{ paAL, PaSGI_Initialize },
#endif
#if PA_USE_ASIHPI
PaAsiHpi_Initialize,
{ paAudioScienceHPI, PaAsiHpi_Initialize },
#endif
#if PA_USE_COREAUDIO
PaMacCore_Initialize,
{ paCoreAudio, PaMacCore_Initialize },
#endif
#if PA_USE_SKELETON
PaSkeleton_Initialize,
/* just for testing. last in list so it isn't marked as default. */
{ paInDevelopment, PaSkeleton_Initialize },
#endif
0 /* NULL terminated array */
{ -1, 0 }, /* NULL terminated array */
};

View file

@ -69,34 +69,35 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
#endif /* __cplusplus */
PaUtilHostApiInitializer *paHostApiInitializers[] =
PaUtilHostApiInitializerEntry paHostApiInitializers[] =
{
#if PA_USE_WMME
PaWinMme_Initialize,
{ paMME, PaWinMme_Initialize },
#endif
#if PA_USE_DS
PaWinDs_Initialize,
{ paDirectSound, PaWinDs_Initialize },
#endif
#if PA_USE_ASIO
PaAsio_Initialize,
{ paASIO, PaAsio_Initialize },
#endif
#if PA_USE_WASAPI
PaWasapi_Initialize,
{ paWASAPI, PaWasapi_Initialize },
#endif
#if PA_USE_WDMKS
PaWinWdm_Initialize,
{ paWDMKS, PaWinWdm_Initialize },
#endif
#if PA_USE_SKELETON
PaSkeleton_Initialize, /* just for testing. last in list so it isn't marked as default. */
/* just for testing. last in list so it isn't marked as default. */
{ paInDevelopment, PaSkeleton_Initialize },
#endif
0 /* NULL terminated array */
{ -1, 0 }, /* NULL terminated array */
};

View file

@ -0,0 +1,159 @@
/** @file patest_select_hostapis.c
@ingroup test_src
@brief Test of Pa_SelectHostApis
@author Ross Bencina <rossb@audiomulch.com>
*/
/*
* $Id$
*
* This program uses the PortAudio Portable Audio Library.
* For more information see: http://www.portaudio.com/
* Copyright (c) 1999-2016 Ross Bencina and 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 <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include "portaudio.h"
/*******************************************************************/
int main(void);
int main(void)
{
int i, j, k;
int availableHostApiCount, scratchHostApiCount;
int maxHostApiCount;
PaHostApiTypeId *availableHostApis;
PaHostApiTypeId *scratchHostApis;
PaError err;
maxHostApiCount = Pa_GetAvailableHostApisCount();
availableHostApis = (PaHostApiTypeId*)malloc( sizeof(PaHostApiTypeId) * maxHostApiCount );
assert( availableHostApis != NULL );
scratchHostApis = (PaHostApiTypeId*)malloc( sizeof(PaHostApiTypeId) * maxHostApiCount );
assert( scratchHostApis != NULL );
availableHostApiCount = 0;
err = Pa_GetAvailableHostApis( availableHostApis, maxHostApiCount, &availableHostApiCount );
assert( err == paNoError );
assert( availableHostApiCount > 0 );
printf("available host api type ids:\n");
for (i = 0; i < availableHostApiCount; ++i )
{
printf("%d\n", availableHostApis[i]);
}
err = Pa_Initialize();
assert( err == paNoError );
Pa_Terminate();
/* excercise Pa_SelectHostApis and Pa_GetSelectedHostApis */
/* each API in turn */
for(i = 0; i < availableHostApiCount; ++i)
{
PaHostApiTypeId hostApiType = availableHostApis[i];
printf("selecting api type %d\n", hostApiType);
err = Pa_SelectHostApis(&hostApiType, 1);
assert( err == paNoError );
/* read back and verify selected apis*/
err = Pa_GetSelectedHostApis( scratchHostApis, maxHostApiCount, &scratchHostApiCount );
assert( err == paNoError );
assert( scratchHostApiCount == 1 );
assert( scratchHostApis[0] == hostApiType );
err = Pa_Initialize();
assert( err == paNoError );
/* verify that all devices match the selected API */
for(j = 0; j < Pa_GetDeviceCount(); ++j)
{
const PaDeviceInfo *deviceInfo = Pa_GetDeviceInfo(j);
assert( deviceInfo != NULL );
assert( Pa_GetHostApiInfo(deviceInfo->hostApi)->type == hostApiType );
}
Pa_Terminate();
}
/* i counts 1 .. n simultaneously selected APIs */
for(i = 1; i < availableHostApiCount; ++i)
{
printf("selecting %d apis\n", i);
err = Pa_SelectHostApis(availableHostApis, i);
assert( err == paNoError );
/* read back and verify selected apis*/
err = Pa_GetSelectedHostApis( scratchHostApis, maxHostApiCount, &scratchHostApiCount );
assert( err == paNoError );
assert( scratchHostApiCount == i );
for( j = 0; j < i; ++j )
assert( scratchHostApis[j] == availableHostApis[j] );
err = Pa_Initialize();
assert( err == paNoError );
/* verify that all devices match one of the selected APIs */
for(j = 0; j < Pa_GetDeviceCount(); ++j)
{
const PaDeviceInfo *deviceInfo = Pa_GetDeviceInfo(j);
assert( deviceInfo != NULL );
/* search for whether the device's host API is one of the selected host APIs */
err = paHostApiNotFound;
for(k = 0; k < i; ++k)
{
PaHostApiTypeId hostApiType = availableHostApis[k];
if( Pa_GetHostApiInfo(deviceInfo->hostApi)->type == hostApiType )
{
err = paNoError;
break;
}
}
assert( err != paHostApiNotFound );
}
Pa_Terminate();
}
free(availableHostApis);
free(scratchHostApis);
}