Adds portaudio sources [adds hotplug support for pa_linux_alsa,
pa_mac_core, plus some other tweaks] damencho committed on Mar 29, 2012 d2076b1 from https://github.com/jitsi/libsrc/commits/master/portaudio.zip
This commit is contained in:
parent
d13fcd8ea9
commit
b77a1f828c
17 changed files with 671 additions and 125 deletions
|
|
@ -107,6 +107,7 @@ TESTS = \
|
|||
bin/patest_wire \
|
||||
bin/patest_write_sine \
|
||||
bin/patest_write_sine_nonint \
|
||||
bin/patest_update_available_device_list \
|
||||
bin/pa_devs \
|
||||
bin/pa_fuzz \
|
||||
bin/pa_minlat
|
||||
|
|
@ -146,6 +147,7 @@ SRC_DIRS = \
|
|||
src/hostapi/wdmks \
|
||||
src/hostapi/wmme \
|
||||
src/os/unix \
|
||||
src/os/mac_osx \
|
||||
src/os/win
|
||||
|
||||
SUBDIRS =
|
||||
|
|
|
|||
BIN
configure
vendored
BIN
configure
vendored
Binary file not shown.
|
|
@ -216,7 +216,7 @@ case "${host_os}" in
|
|||
fi
|
||||
SHARED_FLAGS="$LIBS -dynamiclib $mac_arches $mac_sysroot $mac_version_min"
|
||||
CFLAGS="-std=c99 $CFLAGS $mac_arches $mac_sysroot $mac_version_min"
|
||||
OTHER_OBJS="src/os/unix/pa_unix_hostapis.o src/os/unix/pa_unix_util.o src/hostapi/coreaudio/pa_mac_core.o src/hostapi/coreaudio/pa_mac_core_utilities.o src/hostapi/coreaudio/pa_mac_core_blocking.o src/common/pa_ringbuffer.o"
|
||||
OTHER_OBJS="src/os/unix/pa_unix_hostapis.o src/os/unix/pa_unix_util.o src/hostapi/coreaudio/pa_mac_core.o src/hostapi/coreaudio/pa_mac_core_utilities.o src/hostapi/coreaudio/pa_mac_core_blocking.o src/common/pa_ringbuffer.o src/os/mac_osx/pa_osx_hotplug.o"
|
||||
PADLL="libportaudio.dylib"
|
||||
;;
|
||||
|
||||
|
|
@ -230,7 +230,7 @@ case "${host_os}" in
|
|||
|
||||
if [[ "x$with_directx" = "xyes" ]]; then
|
||||
DXDIR="$with_dxdir"
|
||||
add_objects src/hostapi/dsound/pa_win_ds.o src/hostapi/dsound/pa_win_ds_dynlink.o src/os/win/pa_win_hostapis.o src/os/win/pa_win_util.o src/os/win/pa_win_waveformat.o
|
||||
add_objects src/hostapi/dsound/pa_win_ds.o src/hostapi/dsound/pa_win_ds_dynlink.o src/os/win/pa_win_hostapis.o src/os/win/pa_win_util.o src/os/win/pa_win_waveformat.o src/os/win/pa_win_hotplug.o
|
||||
LIBS="-lwinmm -lm -ldsound -lole32"
|
||||
DLL_LIBS="${DLL_LIBS} -lwinmm -lm -L$DXDIR/lib -ldsound -lole32"
|
||||
#VC98="\"/c/Program Files/Microsoft Visual Studio/VC98/Include\""
|
||||
|
|
@ -249,7 +249,7 @@ case "${host_os}" in
|
|||
|
||||
if [[ "x$with_wdmks" = "xyes" ]]; then
|
||||
DXDIR="$with_dxdir"
|
||||
add_objects src/hostapi/wdmks/pa_win_wdmks.o src/os/win/pa_win_hostapis.o src/os/win/pa_win_util.o
|
||||
add_objects src/hostapi/wdmks/pa_win_wdmks.o src/os/win/pa_win_hostapis.o src/os/win/pa_win_util.o src/os/win/pa_win_wdmks_utils.o
|
||||
LIBS="-lwinmm -lm -luuid -lsetupapi -lole32"
|
||||
DLL_LIBS="${DLL_LIBS} -lwinmm -lm -L$DXDIR/lib -luuid -lsetupapi -lole32"
|
||||
#VC98="\"/c/Program Files/Microsoft Visual Studio/VC98/Include\""
|
||||
|
|
@ -319,7 +319,7 @@ case "${host_os}" in
|
|||
if [[ "$have_alsa" = "yes" ] && [ "$with_alsa" != "no" ]] ; then
|
||||
DLL_LIBS="$DLL_LIBS -lasound"
|
||||
LIBS="$LIBS -lasound"
|
||||
OTHER_OBJS="$OTHER_OBJS src/hostapi/alsa/pa_linux_alsa.o"
|
||||
OTHER_OBJS="$OTHER_OBJS src/hostapi/alsa/pa_linux_alsa.o src/os/unix/pa_linux_hotplug.o"
|
||||
INCLUDES="$INCLUDES pa_linux_alsa.h"
|
||||
AC_DEFINE(PA_USE_ALSA)
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -737,13 +737,12 @@ PaError Pa_UpdateAvailableDeviceList( void )
|
|||
for( i = 0 ; i < paInternalInfo_.hostApisCount_ ; ++i )
|
||||
{
|
||||
PaUtilHostApiRepresentation *hostApi = paInternalInfo_.hostApis_[i];
|
||||
PA_DEBUG(( "Scanning new device list for host api %d.\n",i));
|
||||
if( hostApi->ScanDeviceInfos == NULL )
|
||||
continue;
|
||||
|
||||
PA_DEBUG(( "Scanning new device list for host api %d.\n",i));
|
||||
if( hostApi->ScanDeviceInfos( hostApi, i, &scanResults[ i ], &deviceCounts[ i ] ) != paNoError )
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
/* Check the result of the scan operation */
|
||||
|
|
|
|||
|
|
@ -668,6 +668,15 @@ typedef struct PaAlsaDeviceInfo
|
|||
}
|
||||
PaAlsaDeviceInfo;
|
||||
|
||||
/* used for tranferring device infos during scanning / rescanning */
|
||||
typedef struct PaLinuxScanDeviceInfosResults
|
||||
{
|
||||
PaDeviceInfo **deviceInfos;
|
||||
PaDeviceIndex defaultInputDevice;
|
||||
PaDeviceIndex defaultOutputDevice;
|
||||
int deviceCount;
|
||||
} PaLinuxScanDeviceInfosResults;
|
||||
|
||||
/* prototypes for functions declared in this file */
|
||||
|
||||
static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
|
||||
|
|
@ -692,10 +701,17 @@ static PaError IsStreamStopped( PaStream *s );
|
|||
static PaError IsStreamActive( PaStream *stream );
|
||||
static PaTime GetStreamTime( PaStream *stream );
|
||||
static double GetStreamCpuLoad( PaStream* stream );
|
||||
static PaError BuildDeviceList( PaAlsaHostApiRepresentation *hostApi );
|
||||
static PaError BuildDeviceList( PaAlsaHostApiRepresentation *hostApi, void** scanResults, int* deviceCount );
|
||||
static int SetApproximateSampleRate( snd_pcm_t *pcm, snd_pcm_hw_params_t *hwParams, double sampleRate );
|
||||
static int GetExactSampleRate( snd_pcm_hw_params_t *hwParams, double *sampleRate );
|
||||
|
||||
static PaError ScanDeviceInfos(struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index,
|
||||
void **newDeviceInfos, int *newDeviceCount );
|
||||
static PaError CommitDeviceInfos(struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index,
|
||||
void *deviceInfos, int deviceCount);
|
||||
static PaError DisposeDeviceInfos(struct PaUtilHostApiRepresentation *hostApi, void *deviceInfos,
|
||||
int deviceCount );
|
||||
|
||||
/* Callback prototypes */
|
||||
static void *CallbackThreadFunc( void *userData );
|
||||
|
||||
|
|
@ -722,6 +738,8 @@ PaError PaAlsa_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex
|
|||
{
|
||||
PaError result = paNoError;
|
||||
PaAlsaHostApiRepresentation *alsaHostApi = NULL;
|
||||
void* scanResults = NULL;
|
||||
int deviceCount = 0;
|
||||
|
||||
/* Try loading Alsa library. */
|
||||
if (!PaAlsa_LoadLibrary())
|
||||
|
|
@ -733,20 +751,29 @@ PaError PaAlsa_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex
|
|||
alsaHostApi->hostApiIndex = hostApiIndex;
|
||||
|
||||
*hostApi = (PaUtilHostApiRepresentation*)alsaHostApi;
|
||||
(*hostApi)->deviceInfos = NULL;
|
||||
(*hostApi)->info.structVersion = 1;
|
||||
(*hostApi)->info.type = paALSA;
|
||||
(*hostApi)->info.name = "ALSA";
|
||||
|
||||
(*hostApi)->ScanDeviceInfos = NULL;
|
||||
(*hostApi)->CommitDeviceInfos = NULL;
|
||||
(*hostApi)->DisposeDeviceInfos = NULL;
|
||||
(*hostApi)->Terminate = Terminate;
|
||||
(*hostApi)->OpenStream = OpenStream;
|
||||
(*hostApi)->IsFormatSupported = IsFormatSupported;
|
||||
(*hostApi)->ScanDeviceInfos = ScanDeviceInfos;
|
||||
(*hostApi)->CommitDeviceInfos = CommitDeviceInfos;
|
||||
(*hostApi)->DisposeDeviceInfos = DisposeDeviceInfos;
|
||||
|
||||
/** If AlsaErrorHandler is to be used, do not forget to unregister callback pointer in
|
||||
Terminate function.
|
||||
*/
|
||||
/*ENSURE_( snd_lib_error_set_handler(AlsaErrorHandler), paUnanticipatedHostError );*/
|
||||
|
||||
PA_ENSURE( BuildDeviceList( alsaHostApi ) );
|
||||
ScanDeviceInfos(&alsaHostApi->baseHostApiRep, hostApiIndex, &scanResults,
|
||||
&deviceCount);
|
||||
CommitDeviceInfos(&alsaHostApi->baseHostApiRep, hostApiIndex, scanResults, deviceCount);
|
||||
|
||||
PaUtil_InitializeStreamInterface( &alsaHostApi->callbackStreamInterface,
|
||||
CloseStream, StartStream,
|
||||
|
|
@ -802,7 +829,11 @@ static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
|
|||
}
|
||||
|
||||
PaUtil_FreeMemory( alsaHostApi );
|
||||
alsa_snd_config_update_free_global();
|
||||
// damencho, removed fo compability with pulseaudio versions before 0.9.16
|
||||
// segfault application:
|
||||
// bugtrack alsa: 0002124: snd_config_update_free_global kills applications using user space alsa plugins
|
||||
// snd_config_update_free_global();
|
||||
// alsa_snd_config_update_free_global();
|
||||
|
||||
/* Close Alsa library. */
|
||||
PaAlsa_CloseLibrary();
|
||||
|
|
@ -1075,7 +1106,7 @@ static int OpenPcm( snd_pcm_t **pcmp, const char *name, snd_pcm_stream_t stream,
|
|||
}
|
||||
|
||||
static PaError FillInDevInfo( PaAlsaHostApiRepresentation *alsaApi, HwDevInfo* deviceName, int blocking,
|
||||
PaAlsaDeviceInfo* devInfo, int* devIdx )
|
||||
PaAlsaDeviceInfo* devInfo, int* devIdx, PaLinuxScanDeviceInfosResults* out )
|
||||
{
|
||||
PaError result = 0;
|
||||
PaDeviceInfo *baseDeviceInfo = &devInfo->baseDeviceInfo;
|
||||
|
|
@ -1128,20 +1159,20 @@ static PaError FillInDevInfo( PaAlsaHostApiRepresentation *alsaApi, HwDevInfo* d
|
|||
if( baseDeviceInfo->maxInputChannels > 0 || baseDeviceInfo->maxOutputChannels > 0 )
|
||||
{
|
||||
/* Make device default if there isn't already one or it is the ALSA "default" device */
|
||||
if( (baseApi->info.defaultInputDevice == paNoDevice || !strcmp(deviceName->alsaName,
|
||||
if( (out->defaultInputDevice == paNoDevice || !strcmp(deviceName->alsaName,
|
||||
"default" )) && baseDeviceInfo->maxInputChannels > 0 )
|
||||
{
|
||||
baseApi->info.defaultInputDevice = *devIdx;
|
||||
out->defaultInputDevice = *devIdx;
|
||||
PA_DEBUG(("Default input device: %s\n", deviceName->name));
|
||||
}
|
||||
if( (baseApi->info.defaultOutputDevice == paNoDevice || !strcmp(deviceName->alsaName,
|
||||
if( (out->defaultOutputDevice == paNoDevice || !strcmp(deviceName->alsaName,
|
||||
"default" )) && baseDeviceInfo->maxOutputChannels > 0 )
|
||||
{
|
||||
baseApi->info.defaultOutputDevice = *devIdx;
|
||||
out->defaultOutputDevice = *devIdx;
|
||||
PA_DEBUG(("Default output device: %s\n", deviceName->name));
|
||||
}
|
||||
PA_DEBUG(("%s: Adding device %s: %d\n", __FUNCTION__, deviceName->name, *devIdx));
|
||||
baseApi->deviceInfos[*devIdx] = (PaDeviceInfo *) devInfo;
|
||||
out->deviceInfos[*devIdx] = (PaDeviceInfo *) devInfo;
|
||||
(*devIdx) += 1;
|
||||
}
|
||||
else
|
||||
|
|
@ -1154,9 +1185,10 @@ end:
|
|||
}
|
||||
|
||||
/* Build PaDeviceInfo list, ignore devices for which we cannot determine capabilities (possibly busy, sigh) */
|
||||
static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi )
|
||||
static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi, void** scanResults, int* count)
|
||||
{
|
||||
PaUtilHostApiRepresentation *baseApi = &alsaApi->baseHostApiRep;
|
||||
PaLinuxScanDeviceInfosResults *outArgument = NULL;
|
||||
PaAlsaDeviceInfo *deviceInfoArray;
|
||||
int cardIdx = -1, devIdx = 0;
|
||||
snd_ctl_card_info_t *cardInfo;
|
||||
|
|
@ -1171,13 +1203,11 @@ static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi )
|
|||
#ifdef PA_ENABLE_DEBUG_OUTPUT
|
||||
PaTime startTime = PaUtil_GetTime();
|
||||
#endif
|
||||
PaLinuxScanDeviceInfosResults* out = NULL;
|
||||
|
||||
if( getenv( "PA_ALSA_INITIALIZE_BLOCK" ) && atoi( getenv( "PA_ALSA_INITIALIZE_BLOCK" ) ) )
|
||||
blocking = 0;
|
||||
|
||||
/* These two will be set to the first working input and output device, respectively */
|
||||
baseApi->info.defaultInputDevice = paNoDevice;
|
||||
baseApi->info.defaultOutputDevice = paNoDevice;
|
||||
|
||||
/* Gather info about hw devices
|
||||
|
||||
|
|
@ -1341,8 +1371,14 @@ static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi )
|
|||
else
|
||||
PA_DEBUG(( "%s: Iterating over ALSA plugins failed: %s\n", __FUNCTION__, alsa_snd_strerror( res ) ));
|
||||
|
||||
out = (PaLinuxScanDeviceInfosResults *) PaUtil_GroupAllocateMemory(
|
||||
alsaApi->allocations, sizeof(PaLinuxScanDeviceInfosResults) );
|
||||
|
||||
out->defaultInputDevice = paNoDevice;
|
||||
out->defaultOutputDevice = paNoDevice;
|
||||
|
||||
/* allocate deviceInfo memory based on the number of devices */
|
||||
PA_UNLESS( baseApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
|
||||
PA_UNLESS( out->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
|
||||
alsaApi->allocations, sizeof(PaDeviceInfo*) * (numDeviceNames) ), paInsufficientMemory );
|
||||
|
||||
/* allocate all device info structs in a contiguous block */
|
||||
|
|
@ -1367,7 +1403,7 @@ static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi )
|
|||
continue;
|
||||
}
|
||||
|
||||
PA_ENSURE( FillInDevInfo( alsaApi, hwInfo, blocking, devInfo, &devIdx ) );
|
||||
PA_ENSURE( FillInDevInfo( alsaApi, hwInfo, blocking, devInfo, &devIdx, out ) );
|
||||
}
|
||||
assert( devIdx < numDeviceNames );
|
||||
/* Now inspect 'dmix' and 'default' plugins */
|
||||
|
|
@ -1381,11 +1417,13 @@ static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi )
|
|||
}
|
||||
|
||||
PA_ENSURE( FillInDevInfo( alsaApi, hwInfo, blocking, devInfo,
|
||||
&devIdx ) );
|
||||
&devIdx, out ) );
|
||||
}
|
||||
free( hwDevInfos );
|
||||
|
||||
baseApi->info.deviceCount = devIdx; /* Number of successfully queried devices */
|
||||
out->deviceCount = devIdx; /* Number of successfully queried devices */
|
||||
*scanResults = out;
|
||||
*count = out->deviceCount;
|
||||
|
||||
#ifdef PA_ENABLE_DEBUG_OUTPUT
|
||||
PA_DEBUG(( "%s: Building device list took %f seconds\n", __FUNCTION__, PaUtil_GetTime() - startTime ));
|
||||
|
|
@ -2037,7 +2075,7 @@ static PaError PaAlsaStreamComponent_FinishConfigure( PaAlsaStreamComponent *sel
|
|||
|
||||
ENSURE_( alsa_snd_pcm_sw_params_set_avail_min( self->pcm, swParams, self->framesPerBuffer ), paUnanticipatedHostError );
|
||||
ENSURE_( alsa_snd_pcm_sw_params_set_xfer_align( self->pcm, swParams, 1 ), paUnanticipatedHostError );
|
||||
ENSURE_( alsa_snd_pcm_sw_params_set_tstamp_mode( self->pcm, swParams, SND_PCM_TSTAMP_ENABLE ), paUnanticipatedHostError );
|
||||
ENSURE_( alsa_snd_pcm_sw_params_set_tstamp_mode( self->pcm, swParams, SND_PCM_TSTAMP_MMAP ), paUnanticipatedHostError );
|
||||
|
||||
/* Set the parameters! */
|
||||
ENSURE_( alsa_snd_pcm_sw_params( self->pcm, swParams ), paUnanticipatedHostError );
|
||||
|
|
@ -3544,8 +3582,19 @@ static PaError PaAlsaStreamComponent_GetAvailableFrames( PaAlsaStreamComponent *
|
|||
snd_pcm_sframes_t framesAvail = alsa_snd_pcm_avail_update( self->pcm );
|
||||
*xrunOccurred = 0;
|
||||
|
||||
if( -EPIPE == framesAvail )
|
||||
{
|
||||
/* Get pcm_state and check for xrun condition. On playback I often see
|
||||
* xrun but avail_update does not return -EPIPE but framesAvail larger
|
||||
* than bufferSize. In case of xrun status set xrun flag, leave framesize
|
||||
* as reported by avail_update, will be fixed below. In case avail_update
|
||||
* returns -EPIPE process as usual. wd-xxx
|
||||
*/
|
||||
snd_pcm_state_t state = snd_pcm_state( self->pcm ); /* wd-xxx */
|
||||
if (state == SND_PCM_STATE_XRUN) {
|
||||
// printf("xrun, fav %d\n", framesAvail); fflush(stdout); // DEBUG-WD
|
||||
*xrunOccurred = 1;
|
||||
}
|
||||
if( -EPIPE == framesAvail) {
|
||||
// printf("xrun-1, fav %d\n", framesAvail); fflush(stdout); // DEBUG-WD
|
||||
*xrunOccurred = 1;
|
||||
framesAvail = 0;
|
||||
}
|
||||
|
|
@ -3554,6 +3603,11 @@ static PaError PaAlsaStreamComponent_GetAvailableFrames( PaAlsaStreamComponent *
|
|||
ENSURE_( framesAvail, paUnanticipatedHostError );
|
||||
}
|
||||
|
||||
/* Fix frames avail, should not be bigger than bufferSize wd-xxx */
|
||||
if (framesAvail > self->bufferSize) {
|
||||
// printf("xrun-2, fav %d\n", framesAvail); fflush(stdout); // DEBUG-WD
|
||||
framesAvail = self->bufferSize;
|
||||
}
|
||||
*numFrames = framesAvail;
|
||||
|
||||
error:
|
||||
|
|
@ -3603,6 +3657,13 @@ static PaError PaAlsaStreamComponent_EndPolling( PaAlsaStreamComponent* self, st
|
|||
|
||||
*shouldPoll = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// not actually used
|
||||
unsigned long framesAvail = 0;
|
||||
// now check for xrun
|
||||
PaAlsaStreamComponent_GetAvailableFrames(self, &framesAvail, xrun );
|
||||
}
|
||||
|
||||
error:
|
||||
return result;
|
||||
|
|
@ -3693,6 +3754,10 @@ static PaError PaAlsaStream_WaitForFrames( PaAlsaStream *self, unsigned long *fr
|
|||
framesAvail, &xrun ) );
|
||||
if( xrun )
|
||||
{
|
||||
if(*framesAvail == 0)
|
||||
{
|
||||
result = paInternalError;
|
||||
}
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
|
@ -3740,6 +3805,7 @@ static PaError PaAlsaStream_WaitForFrames( PaAlsaStream *self, unsigned long *fr
|
|||
Pa_Sleep( 1 ); /* avoid hot loop */
|
||||
continue;
|
||||
}
|
||||
result = paInternalError;
|
||||
|
||||
/* TODO: Add macro for checking system calls */
|
||||
PA_ENSURE( paInternalError );
|
||||
|
|
@ -3769,6 +3835,7 @@ static PaError PaAlsaStream_WaitForFrames( PaAlsaStream *self, unsigned long *fr
|
|||
xrun = 1; /* try recovering device */
|
||||
|
||||
PA_DEBUG(( "%s: poll timed out\n", __FUNCTION__, timeouts ));
|
||||
result = paTimedOut;
|
||||
goto end;/*PA_ENSURE( paTimedOut );*/
|
||||
}
|
||||
}
|
||||
|
|
@ -4326,9 +4393,24 @@ static PaError ReadStream( PaStream* s, void *buffer, unsigned long frames )
|
|||
while( frames > 0 )
|
||||
{
|
||||
int xrun = 0;
|
||||
PA_ENSURE( PaAlsaStream_WaitForFrames( stream, &framesAvail, &xrun ) );
|
||||
framesGot = PA_MIN( framesAvail, frames );
|
||||
PA_ENSURE( PaAlsaStream_WaitForFrames( stream, &framesAvail, &xrun ) );
|
||||
/*
|
||||
* In case of overrun WaitForFrames leaves the capture stream in STATE_PREPARED
|
||||
* most of the time. handleXrun() restarts the ALSA stream only in case
|
||||
* snd_pcm_recover() fails, which usually does not happen.
|
||||
* Here we start the pcm stream again and go for another try. Another
|
||||
* option is: set result to paOverrun and return to caller. Then
|
||||
* the caller needs to call ReadStream again. This takes more time and
|
||||
* we lose even more frames.
|
||||
*/
|
||||
if (xrun) { /* wd-xxx */
|
||||
if( snd_pcm_state( stream->capture.pcm ) == SND_PCM_STATE_PREPARED ) {
|
||||
ENSURE_( snd_pcm_start( stream->capture.pcm ), paUnanticipatedHostError );
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
framesGot = PA_MIN( framesAvail, frames );
|
||||
PA_ENSURE( PaAlsaStream_SetUpBuffers( stream, &framesGot, &xrun ) );
|
||||
if( framesGot > 0 )
|
||||
{
|
||||
|
|
@ -4546,3 +4628,75 @@ PaError PaAlsa_SetRetriesBusy( int retries )
|
|||
busyRetries_ = retries;
|
||||
return paNoError;
|
||||
}
|
||||
|
||||
static PaError ScanDeviceInfos(struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex hostApiIndex,
|
||||
void **scanResults, int *newDeviceCount)
|
||||
{
|
||||
PaAlsaHostApiRepresentation* alsaHostApi = (PaAlsaHostApiRepresentation*)hostApi;
|
||||
PaError result = paNoError;
|
||||
PA_ENSURE(BuildDeviceList( alsaHostApi, scanResults, newDeviceCount ));
|
||||
|
||||
return paNoError;
|
||||
|
||||
error:
|
||||
return result;
|
||||
}
|
||||
|
||||
static PaError CommitDeviceInfos(struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index,
|
||||
void *scanResults, int deviceCount)
|
||||
{
|
||||
PaAlsaHostApiRepresentation* alsaHostApi = (PaAlsaHostApiRepresentation*)hostApi;
|
||||
PaError result = paNoError;
|
||||
|
||||
/* These two will be set to the first working input and output device, respectively */
|
||||
hostApi->info.defaultInputDevice = paNoDevice;
|
||||
hostApi->info.defaultOutputDevice = paNoDevice;
|
||||
|
||||
/* Free any old memory which might be in the device info */
|
||||
if( hostApi->deviceInfos )
|
||||
{
|
||||
/* all device info structs are allocated in a block so we can destroy them here */
|
||||
PaUtil_GroupFreeMemory( alsaHostApi->allocations, hostApi->deviceInfos[0] );
|
||||
PaUtil_GroupFreeMemory( alsaHostApi->allocations, hostApi->deviceInfos );
|
||||
hostApi->deviceInfos = NULL;
|
||||
}
|
||||
|
||||
if( scanResults != NULL )
|
||||
{
|
||||
PaLinuxScanDeviceInfosResults *scanDeviceInfosResults = ( PaLinuxScanDeviceInfosResults * ) scanResults;
|
||||
|
||||
if( deviceCount > 0 )
|
||||
{
|
||||
/* use the array allocated in ScanDeviceInfos() as our deviceInfos */
|
||||
hostApi->deviceInfos = scanDeviceInfosResults->deviceInfos;
|
||||
hostApi->info.defaultInputDevice = scanDeviceInfosResults->defaultInputDevice;
|
||||
hostApi->info.defaultOutputDevice = scanDeviceInfosResults->defaultOutputDevice;
|
||||
hostApi->info.deviceCount = deviceCount;
|
||||
}
|
||||
|
||||
PaUtil_GroupFreeMemory( alsaHostApi->allocations, scanDeviceInfosResults );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static PaError DisposeDeviceInfos(struct PaUtilHostApiRepresentation *hostApi, void *scanResults, int deviceCount)
|
||||
{
|
||||
PaAlsaHostApiRepresentation *alsaHostApi = (PaAlsaHostApiRepresentation*)hostApi;
|
||||
|
||||
if( scanResults != NULL )
|
||||
{
|
||||
PaLinuxScanDeviceInfosResults *scanDeviceInfosResults = ( PaLinuxScanDeviceInfosResults * ) scanResults;
|
||||
if( scanDeviceInfosResults->deviceInfos )
|
||||
{
|
||||
/* all device info structs are allocated in a block so we can destroy them here */
|
||||
PaUtil_GroupFreeMemory( alsaHostApi->allocations, scanDeviceInfosResults->deviceInfos[0] );
|
||||
PaUtil_GroupFreeMemory( alsaHostApi->allocations, scanDeviceInfosResults->deviceInfos );
|
||||
}
|
||||
|
||||
PaUtil_GroupFreeMemory(alsaHostApi->allocations, scanDeviceInfosResults );
|
||||
}
|
||||
|
||||
return paNoError;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* $Id$
|
||||
* $Id: pa_asio.cpp 1661 2011-04-28 18:54:46Z rob_bielik $
|
||||
* Portable Audio I/O Library for ASIO Drivers
|
||||
*
|
||||
* Author: Stephane Letz
|
||||
|
|
@ -1315,6 +1315,9 @@ PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex
|
|||
}
|
||||
|
||||
|
||||
(*hostApi)->ScanDeviceInfos = NULL;
|
||||
(*hostApi)->CommitDeviceInfos = NULL;
|
||||
(*hostApi)->DisposeDeviceInfos = NULL;
|
||||
(*hostApi)->Terminate = Terminate;
|
||||
(*hostApi)->OpenStream = OpenStream;
|
||||
(*hostApi)->IsFormatSupported = IsFormatSupported;
|
||||
|
|
|
|||
|
|
@ -80,6 +80,27 @@ extern "C"
|
|||
/* prototypes for functions declared in this file */
|
||||
|
||||
PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
|
||||
static PaError ScanDeviceInfos(struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index,
|
||||
void **newDeviceInfos, int *newDeviceCount );
|
||||
static PaError CommitDeviceInfos(struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index,
|
||||
void *deviceInfos, int deviceCount);
|
||||
static PaError DisposeDeviceInfos(struct PaUtilHostApiRepresentation *hostApi, void *deviceInfos,
|
||||
int deviceCount );
|
||||
|
||||
/* structures */
|
||||
|
||||
/* used for tranferring device infos during scanning / rescanning */
|
||||
typedef struct PaMacScanDeviceInfosResults
|
||||
{
|
||||
PaDeviceInfo **deviceInfos;
|
||||
PaDeviceIndex defaultInputDevice;
|
||||
PaDeviceIndex defaultOutputDevice;
|
||||
|
||||
AudioDeviceID* devIds;
|
||||
int devCount;
|
||||
AudioDeviceID devInputDevice;
|
||||
AudioDeviceID devOutputDevice;
|
||||
} PaMacScanDeviceInfosResults;
|
||||
|
||||
/*
|
||||
* Function declared in pa_mac_core.h. Sets up a PaMacCoreStreamInfoStruct
|
||||
|
|
@ -132,7 +153,6 @@ const char *PaMacCore_GetChannelName( int device, int channelIndex, bool input )
|
|||
return NULL;
|
||||
PaMacAUHAL *macCoreHostApi = (PaMacAUHAL*)hostApi;
|
||||
AudioDeviceID hostApiDevice = macCoreHostApi->devIds[device];
|
||||
|
||||
UInt32 size = 0;
|
||||
|
||||
error = AudioDeviceGetPropertyInfo( hostApiDevice,
|
||||
|
|
@ -311,46 +331,57 @@ static void startStopCallback(
|
|||
}
|
||||
|
||||
|
||||
/*currently, this is only used in initialization, but it might be modified
|
||||
to be used when the list of devices changes.*/
|
||||
static PaError gatherDeviceInfo(PaMacAUHAL *auhalHostApi)
|
||||
//static PaError gatherDeviceInfo(PaMacAUHAL *auhalHostApi)
|
||||
static PaError gatherDeviceInfo(PaMacAUHAL* auhalHostApi, void** scanResults, int* count)
|
||||
{
|
||||
UInt32 size;
|
||||
UInt32 propsize;
|
||||
VVDBUG(("gatherDeviceInfo()\n"));
|
||||
/* -- free any previous allocations -- */
|
||||
if( auhalHostApi->devIds )
|
||||
PaUtil_GroupFreeMemory(auhalHostApi->allocations, auhalHostApi->devIds);
|
||||
auhalHostApi->devIds = NULL;
|
||||
UInt32 propsize = 0;
|
||||
UInt32 size = sizeof(AudioDeviceID);
|
||||
PaMacScanDeviceInfosResults *outArgument = NULL;
|
||||
PaError result = paNoError;
|
||||
|
||||
VVDBUG(("gatherDeviceInfo()\n"));
|
||||
/* -- figure out how many devices there are -- */
|
||||
AudioHardwareGetPropertyInfo( kAudioHardwarePropertyDevices,
|
||||
&propsize,
|
||||
NULL );
|
||||
auhalHostApi->devCount = propsize / sizeof( AudioDeviceID );
|
||||
*count = (propsize / sizeof(AudioDeviceID));
|
||||
|
||||
VDBUG( ( "Found %ld device(s).\n", auhalHostApi->devCount ) );
|
||||
VDBUG( ( "Found %ld device(s).\n", *count ) );
|
||||
|
||||
if(*count == 0)
|
||||
return paNoError;
|
||||
|
||||
/* Allocate the out param for all the info we need */
|
||||
outArgument = (PaMacScanDeviceInfosResults *) PaUtil_GroupAllocateMemory(
|
||||
auhalHostApi->allocations, sizeof(PaMacScanDeviceInfosResults) );
|
||||
|
||||
if( !outArgument )
|
||||
{
|
||||
result = paInsufficientMemory;
|
||||
return result;
|
||||
}
|
||||
|
||||
outArgument->devCount = *count;
|
||||
|
||||
/* -- copy the device IDs -- */
|
||||
auhalHostApi->devIds = (AudioDeviceID *)PaUtil_GroupAllocateMemory(
|
||||
outArgument->devIds = (AudioDeviceID *)PaUtil_GroupAllocateMemory(
|
||||
auhalHostApi->allocations,
|
||||
propsize );
|
||||
if( !auhalHostApi->devIds )
|
||||
if( !outArgument->devIds )
|
||||
return paInsufficientMemory;
|
||||
AudioHardwareGetProperty( kAudioHardwarePropertyDevices,
|
||||
&propsize,
|
||||
auhalHostApi->devIds );
|
||||
outArgument->devIds );
|
||||
#ifdef MAC_CORE_VERBOSE_DEBUG
|
||||
{
|
||||
int i;
|
||||
for( i=0; i<auhalHostApi->devCount; ++i )
|
||||
printf( "Device %d\t: %ld\n", i, auhalHostApi->devIds[i] );
|
||||
for( i=0; i<outArgument->devCount; ++i )
|
||||
printf( "Device %d\t: %ld\n", i, outArgument->devIds[i] );
|
||||
}
|
||||
#endif
|
||||
|
||||
size = sizeof(AudioDeviceID);
|
||||
auhalHostApi->defaultIn = kAudioDeviceUnknown;
|
||||
auhalHostApi->defaultOut = kAudioDeviceUnknown;
|
||||
outArgument->devInputDevice = kAudioDeviceUnknown;
|
||||
outArgument->devOutputDevice = kAudioDeviceUnknown;
|
||||
|
||||
/* determine the default device. */
|
||||
/* I am not sure how these calls to AudioHardwareGetProperty()
|
||||
|
|
@ -358,42 +389,44 @@ static PaError gatherDeviceInfo(PaMacAUHAL *auhalHostApi)
|
|||
device as the default. */
|
||||
if( 0 != AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice,
|
||||
&size,
|
||||
&auhalHostApi->defaultIn) ) {
|
||||
&outArgument->devInputDevice) ) {
|
||||
int i;
|
||||
auhalHostApi->defaultIn = kAudioDeviceUnknown;
|
||||
outArgument->devInputDevice = kAudioDeviceUnknown;
|
||||
VDBUG(("Failed to get default input device from OS."));
|
||||
VDBUG((" I will substitute the first available input Device."));
|
||||
for( i=0; i<auhalHostApi->devCount; ++i ) {
|
||||
|
||||
for( i=0; i< outArgument->devCount; ++i ) {
|
||||
PaDeviceInfo devInfo;
|
||||
if( 0 != GetChannelInfo( auhalHostApi, &devInfo,
|
||||
auhalHostApi->devIds[i], TRUE ) )
|
||||
outArgument->devIds[i], TRUE ) )
|
||||
if( devInfo.maxInputChannels ) {
|
||||
auhalHostApi->defaultIn = auhalHostApi->devIds[i];
|
||||
outArgument->devInputDevice = outArgument->devIds[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( 0 != AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice,
|
||||
&size,
|
||||
&auhalHostApi->defaultOut) ) {
|
||||
&outArgument->devOutputDevice) ) {
|
||||
int i;
|
||||
auhalHostApi->defaultIn = kAudioDeviceUnknown;
|
||||
outArgument->devOutputDevice = kAudioDeviceUnknown;
|
||||
VDBUG(("Failed to get default output device from OS."));
|
||||
VDBUG((" I will substitute the first available output Device."));
|
||||
for( i=0; i<auhalHostApi->devCount; ++i ) {
|
||||
for( i=0; i<outArgument->devCount; ++i ) {
|
||||
PaDeviceInfo devInfo;
|
||||
if( 0 != GetChannelInfo( auhalHostApi, &devInfo,
|
||||
auhalHostApi->devIds[i], FALSE ) )
|
||||
outArgument->devIds[i], FALSE ) )
|
||||
if( devInfo.maxOutputChannels ) {
|
||||
auhalHostApi->defaultOut = auhalHostApi->devIds[i];
|
||||
outArgument->devOutputDevice = outArgument->devIds[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VDBUG( ( "Default in : %ld\n", auhalHostApi->defaultIn ) );
|
||||
VDBUG( ( "Default out: %ld\n", auhalHostApi->defaultOut ) );
|
||||
VDBUG( ( "Default in : %ld\n", outArgument->devInputDevice ) );
|
||||
VDBUG( ( "Default out: %ld\n", outArgument->devOutputDevice ) );
|
||||
|
||||
*scanResults = outArgument;
|
||||
return paNoError;
|
||||
}
|
||||
|
||||
|
|
@ -402,9 +435,9 @@ static PaError GetChannelInfo( PaMacAUHAL *auhalHostApi,
|
|||
AudioDeviceID macCoreDeviceId,
|
||||
int isInput)
|
||||
{
|
||||
UInt32 propSize;
|
||||
UInt32 propSize = 0;
|
||||
PaError err = paNoError;
|
||||
UInt32 i;
|
||||
UInt32 i = 0;
|
||||
int numChannels = 0;
|
||||
AudioBufferList *buflist = NULL;
|
||||
UInt32 frameLatency;
|
||||
|
|
@ -528,10 +561,10 @@ static PaError InitializeDeviceInfo( PaMacAUHAL *auhalHostApi,
|
|||
PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
|
||||
{
|
||||
PaError result = paNoError;
|
||||
int i;
|
||||
PaMacAUHAL *auhalHostApi = NULL;
|
||||
PaDeviceInfo *deviceInfoArray;
|
||||
int unixErr;
|
||||
void* scanResults = NULL;
|
||||
int deviceCount = 0;
|
||||
|
||||
VVDBUG(("PaMacCore_Initialize(): hostApiIndex=%d\n", hostApiIndex));
|
||||
|
||||
|
|
@ -572,65 +605,29 @@ PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIn
|
|||
auhalHostApi->devIds = NULL;
|
||||
auhalHostApi->devCount = 0;
|
||||
|
||||
/* get the info we need about the devices */
|
||||
result = gatherDeviceInfo( auhalHostApi );
|
||||
if( result != paNoError )
|
||||
goto error;
|
||||
|
||||
*hostApi = &auhalHostApi->inheritedHostApiRep;
|
||||
(*hostApi)->info.structVersion = 1;
|
||||
(*hostApi)->info.type = paCoreAudio;
|
||||
(*hostApi)->info.name = "Core Audio";
|
||||
|
||||
|
||||
(*hostApi)->deviceInfos = NULL;
|
||||
|
||||
(*hostApi)->info.defaultInputDevice = paNoDevice;
|
||||
(*hostApi)->info.defaultOutputDevice = paNoDevice;
|
||||
|
||||
(*hostApi)->info.deviceCount = 0;
|
||||
|
||||
if( auhalHostApi->devCount > 0 )
|
||||
{
|
||||
(*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
|
||||
auhalHostApi->allocations, sizeof(PaDeviceInfo*) * auhalHostApi->devCount);
|
||||
if( !(*hostApi)->deviceInfos )
|
||||
{
|
||||
result = paInsufficientMemory;
|
||||
goto error;
|
||||
}
|
||||
(*hostApi)->ScanDeviceInfos = ScanDeviceInfos;
|
||||
(*hostApi)->CommitDeviceInfos = CommitDeviceInfos;
|
||||
(*hostApi)->DisposeDeviceInfos = DisposeDeviceInfos;
|
||||
|
||||
/* allocate all device info structs in a contiguous block */
|
||||
deviceInfoArray = (PaDeviceInfo*)PaUtil_GroupAllocateMemory(
|
||||
auhalHostApi->allocations, sizeof(PaDeviceInfo) * auhalHostApi->devCount );
|
||||
if( !deviceInfoArray )
|
||||
{
|
||||
result = paInsufficientMemory;
|
||||
goto error;
|
||||
}
|
||||
result = ScanDeviceInfos(&auhalHostApi->inheritedHostApiRep, hostApiIndex, &scanResults,
|
||||
&deviceCount);
|
||||
|
||||
for( i=0; i < auhalHostApi->devCount; ++i )
|
||||
{
|
||||
int err;
|
||||
err = InitializeDeviceInfo( auhalHostApi, &deviceInfoArray[i],
|
||||
auhalHostApi->devIds[i],
|
||||
hostApiIndex );
|
||||
if (err == paNoError)
|
||||
{ /* copy some info and set the defaults */
|
||||
(*hostApi)->deviceInfos[(*hostApi)->info.deviceCount] = &deviceInfoArray[i];
|
||||
if (auhalHostApi->devIds[i] == auhalHostApi->defaultIn)
|
||||
(*hostApi)->info.defaultInputDevice = (*hostApi)->info.deviceCount;
|
||||
if (auhalHostApi->devIds[i] == auhalHostApi->defaultOut)
|
||||
(*hostApi)->info.defaultOutputDevice = (*hostApi)->info.deviceCount;
|
||||
(*hostApi)->info.deviceCount++;
|
||||
}
|
||||
else
|
||||
{ /* there was an error. we need to shift the devices down, so we ignore this one */
|
||||
int j;
|
||||
auhalHostApi->devCount--;
|
||||
for( j=i; j<auhalHostApi->devCount; ++j )
|
||||
auhalHostApi->devIds[j] = auhalHostApi->devIds[j+1];
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(result != paNoError)
|
||||
goto error;
|
||||
|
||||
/* FIXME for now we ignore the result of CommitDeviceInfos(), it should probably be an atomic non-failing operation */
|
||||
CommitDeviceInfos( &auhalHostApi->inheritedHostApiRep, hostApiIndex, scanResults, deviceCount );
|
||||
|
||||
(*hostApi)->Terminate = Terminate;
|
||||
(*hostApi)->OpenStream = OpenStream;
|
||||
|
|
@ -2468,3 +2465,148 @@ static double GetStreamCpuLoad( PaStream* s )
|
|||
|
||||
return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
|
||||
}
|
||||
|
||||
static PaError ScanDeviceInfos(struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex hostApiIndex,
|
||||
void **scanResults, int *newDeviceCount)
|
||||
{
|
||||
PaMacAUHAL* auhalHostApi = (PaMacAUHAL*)hostApi;
|
||||
PaDeviceInfo *deviceInfoArray = NULL;
|
||||
PaError result = paNoError;
|
||||
int i = 0;
|
||||
PaMacScanDeviceInfosResults* out = NULL;
|
||||
|
||||
/* get the info we need about the devices */
|
||||
result = gatherDeviceInfo( auhalHostApi, scanResults, newDeviceCount );
|
||||
|
||||
if( result != paNoError )
|
||||
return result;
|
||||
|
||||
out = (PaMacScanDeviceInfosResults*)*scanResults;
|
||||
|
||||
if( out->devCount > 0 )
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
/* allocate array for pointers to PaDeviceInfo structs */
|
||||
out->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
|
||||
auhalHostApi->allocations, sizeof(PaDeviceInfo*) * out->devCount);
|
||||
if( !out->deviceInfos )
|
||||
{
|
||||
result = paInsufficientMemory;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* allocate all device info structs in a contiguous block */
|
||||
deviceInfoArray = (PaDeviceInfo*)PaUtil_GroupAllocateMemory(
|
||||
auhalHostApi->allocations, sizeof(PaDeviceInfo) * out->devCount );
|
||||
if( !deviceInfoArray )
|
||||
{
|
||||
result = paInsufficientMemory;
|
||||
return result;
|
||||
}
|
||||
|
||||
for( i=0; i < out->devCount; ++i )
|
||||
{
|
||||
int err;
|
||||
err = InitializeDeviceInfo( auhalHostApi, &deviceInfoArray[i],
|
||||
out->devIds[i],
|
||||
hostApiIndex );
|
||||
if (err == paNoError)
|
||||
{
|
||||
/* copy some info and set the defaults */
|
||||
out->deviceInfos[count] = &deviceInfoArray[i];
|
||||
|
||||
if (out->devIds[i] == out->devInputDevice)
|
||||
{
|
||||
out->defaultInputDevice = count;
|
||||
}
|
||||
if (out->devIds[i] == out->devOutputDevice)
|
||||
{
|
||||
out->defaultOutputDevice = count;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* there was an error. we need to shift the devices down, so we ignore this one */
|
||||
int j;
|
||||
out->devCount--;
|
||||
for( j=i; j<out->devCount; ++j )
|
||||
out->devIds[j] = out->devIds[j+1];
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
*newDeviceCount = out->devCount;
|
||||
|
||||
return paNoError;
|
||||
}
|
||||
|
||||
static PaError CommitDeviceInfos(struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index,
|
||||
void *scanResults, int deviceCount)
|
||||
{
|
||||
PaMacAUHAL* auhalHostApi = (PaMacAUHAL*)hostApi;
|
||||
PaError result = paNoError;
|
||||
|
||||
hostApi->info.deviceCount = 0;
|
||||
hostApi->info.defaultInputDevice = paNoDevice;
|
||||
hostApi->info.defaultOutputDevice = paNoDevice;
|
||||
|
||||
/* -- free any previous allocations -- */
|
||||
if( auhalHostApi->devIds )
|
||||
{
|
||||
PaUtil_GroupFreeMemory(auhalHostApi->allocations, auhalHostApi->devIds);
|
||||
}
|
||||
auhalHostApi->devIds = NULL;
|
||||
|
||||
/* Free any old memory which might be in the device info */
|
||||
if( hostApi->deviceInfos )
|
||||
{
|
||||
PaUtil_GroupFreeMemory( auhalHostApi->allocations, hostApi->deviceInfos[0] );
|
||||
PaUtil_GroupFreeMemory( auhalHostApi->allocations, hostApi->deviceInfos );
|
||||
hostApi->deviceInfos = NULL;
|
||||
}
|
||||
|
||||
if( scanResults != NULL )
|
||||
{
|
||||
PaMacScanDeviceInfosResults *scanDeviceInfosResults = ( PaMacScanDeviceInfosResults * ) scanResults;
|
||||
|
||||
if( deviceCount > 0 )
|
||||
{
|
||||
/* use the array allocated in ScanDeviceInfos() as our deviceInfos */
|
||||
hostApi->deviceInfos = scanDeviceInfosResults->deviceInfos;
|
||||
hostApi->info.defaultInputDevice = scanDeviceInfosResults->defaultInputDevice;
|
||||
hostApi->info.defaultOutputDevice = scanDeviceInfosResults->defaultOutputDevice;
|
||||
hostApi->info.deviceCount = deviceCount;
|
||||
auhalHostApi->devIds = scanDeviceInfosResults->devIds;
|
||||
auhalHostApi->devCount = scanDeviceInfosResults->devCount;
|
||||
auhalHostApi->defaultIn = scanDeviceInfosResults->devInputDevice;
|
||||
auhalHostApi->defaultOut = scanDeviceInfosResults->devOutputDevice;
|
||||
}
|
||||
|
||||
PaUtil_GroupFreeMemory( auhalHostApi->allocations, scanDeviceInfosResults );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static PaError DisposeDeviceInfos(struct PaUtilHostApiRepresentation *hostApi, void *scanResults, int deviceCount)
|
||||
{
|
||||
PaMacAUHAL *auhalHostApi = (PaMacAUHAL*)hostApi;
|
||||
|
||||
if( scanResults != NULL )
|
||||
{
|
||||
PaMacScanDeviceInfosResults *scanDeviceInfosResults = ( PaMacScanDeviceInfosResults * ) scanResults;
|
||||
if( scanDeviceInfosResults->deviceInfos )
|
||||
{
|
||||
/* all device info structs are allocated in a block so we can destroy them here */
|
||||
PaUtil_GroupFreeMemory( auhalHostApi->allocations, scanDeviceInfosResults->deviceInfos[0] );
|
||||
PaUtil_GroupFreeMemory( auhalHostApi->allocations, scanDeviceInfosResults->deviceInfos );
|
||||
}
|
||||
|
||||
PaUtil_GroupFreeMemory(auhalHostApi->allocations, scanDeviceInfosResults );
|
||||
}
|
||||
|
||||
return paNoError;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* $Id$
|
||||
* $Id: pa_jack.c 1661 2011-04-28 18:54:46Z rob_bielik $
|
||||
* PortAudio Portable Real-Time Audio Library
|
||||
* Latest Version at: http://www.portaudio.com
|
||||
* JACK Implementation by Joshua Haberman
|
||||
|
|
@ -749,6 +749,9 @@ PaError PaJack_Initialize( PaUtilHostApiRepresentation **hostApi,
|
|||
|
||||
/* Register functions */
|
||||
|
||||
(*hostApi)->ScanDeviceInfos = NULL;
|
||||
(*hostApi)->CommitDeviceInfos = NULL;
|
||||
(*hostApi)->DisposeDeviceInfos = NULL;
|
||||
(*hostApi)->Terminate = Terminate;
|
||||
(*hostApi)->OpenStream = OpenStream;
|
||||
(*hostApi)->IsFormatSupported = IsFormatSupported;
|
||||
|
|
@ -1181,7 +1184,7 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
|
|||
minimum_buffer_frames = jackHostApi->jack_buffer_size * 3;
|
||||
|
||||
/* setup blocking API data structures (FIXME: can fail) */
|
||||
BlockingBegin( stream, minimum_buffer_frames );
|
||||
BlockingBegin( stream, minimum_buffer_frames );
|
||||
|
||||
/* install our own callback for the blocking API */
|
||||
streamCallback = BlockingCallback;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* $Id$
|
||||
* $Id: pa_unix_oss.c 1661 2011-04-28 18:54:46Z rob_bielik $
|
||||
* PortAudio Portable Real-Time Audio Library
|
||||
* Latest Version at: http://www.portaudio.com
|
||||
* OSS implementation by:
|
||||
|
|
@ -256,6 +256,9 @@ PaError PaOSS_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex
|
|||
(*hostApi)->Terminate = Terminate;
|
||||
(*hostApi)->OpenStream = OpenStream;
|
||||
(*hostApi)->IsFormatSupported = IsFormatSupported;
|
||||
(*hostApi)->ScanDeviceInfos = NULL;
|
||||
(*hostApi)->CommitDeviceInfos = NULL;
|
||||
(*hostApi)->DisposeDeviceInfos = NULL;
|
||||
|
||||
PA_ENSURE( BuildDeviceList( ossHostApi ) );
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* $Id$
|
||||
* $Id: pa_hostapi_skeleton.c 1661 2011-04-28 18:54:46Z rob_bielik $
|
||||
* Portable Audio I/O Library skeleton implementation
|
||||
* demonstrates how to use the common functions to implement support
|
||||
* for a host API
|
||||
|
|
@ -206,9 +206,15 @@ PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiI
|
|||
}
|
||||
}
|
||||
|
||||
(*hostApi)->ScanDeviceInfos = NULL;
|
||||
(*hostApi)->CommitDeviceInfos = NULL;
|
||||
(*hostApi)->DisposeDeviceInfos = NULL;
|
||||
(*hostApi)->Terminate = Terminate;
|
||||
(*hostApi)->OpenStream = OpenStream;
|
||||
(*hostApi)->IsFormatSupported = IsFormatSupported;
|
||||
(*hostApi)->ScanDeviceInfos = NULL;
|
||||
(*hostApi)->CommitDeviceInfos = NULL;
|
||||
(*hostApi)->DisposeDeviceInfos = NULL;
|
||||
|
||||
PaUtil_InitializeStreamInterface( &skeletonHostApi->callbackStreamInterface, CloseStream, StartStream,
|
||||
StopStream, AbortStream, IsStreamStopped, IsStreamActive,
|
||||
|
|
|
|||
|
|
@ -1386,6 +1386,9 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
|
|||
}
|
||||
}
|
||||
|
||||
(*hostApi)->ScanDeviceInfos = NULL;
|
||||
(*hostApi)->CommitDeviceInfos = NULL;
|
||||
(*hostApi)->DisposeDeviceInfos = NULL;
|
||||
(*hostApi)->Terminate = Terminate;
|
||||
(*hostApi)->OpenStream = OpenStream;
|
||||
(*hostApi)->IsFormatSupported = IsFormatSupported;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* $Id$
|
||||
* $Id: pa_win_wdmks.c 1661 2011-04-28 18:54:46Z rob_bielik $
|
||||
* PortAudio Windows WDM-KS interface
|
||||
*
|
||||
* Author: Andrew Baldwin
|
||||
|
|
@ -1885,6 +1885,9 @@ PaError PaWinWdm_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
|
|||
|
||||
(*hostApi)->info.deviceCount = deviceCount;
|
||||
|
||||
(*hostApi)->ScanDeviceInfos = NULL;
|
||||
(*hostApi)->CommitDeviceInfos = NULL;
|
||||
(*hostApi)->DisposeDeviceInfos = NULL;
|
||||
(*hostApi)->Terminate = Terminate;
|
||||
(*hostApi)->OpenStream = OpenStream;
|
||||
(*hostApi)->IsFormatSupported = IsFormatSupported;
|
||||
|
|
@ -3305,4 +3308,4 @@ static signed long GetStreamWriteAvailable( PaStream* s )
|
|||
/* IMPLEMENT ME, see portaudio.h for required behavior*/
|
||||
PA_LOGL_;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
76
src/os/mac_osx/pa_osx_hotplug.c
Normal file
76
src/os/mac_osx/pa_osx_hotplug.c
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
|
||||
#include "pa_util.h"
|
||||
#include "pa_debugprint.h"
|
||||
#include "pa_allocation.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <AudioUnit/AudioUnit.h>
|
||||
#include <AudioToolbox/AudioToolbox.h>
|
||||
|
||||
/* Implemented in pa_front.c
|
||||
@param first 0 = unknown, 1 = insertion, 2 = removal
|
||||
@param second Host specific device change info (in windows it is the (unicode) device path)
|
||||
*/
|
||||
extern void PaUtil_DevicesChanged(unsigned, void*);
|
||||
|
||||
/* Callback for audio hardware property changes. */
|
||||
static OSStatus audioPropertyCallback(AudioHardwarePropertyID inPropertyID,
|
||||
void *refCon)
|
||||
{
|
||||
(void)refCon;
|
||||
switch (inPropertyID)
|
||||
{
|
||||
/*
|
||||
* These are the other types of notifications we might receive, however, they are beyond
|
||||
* the scope of this sample and we ignore them.
|
||||
*/
|
||||
case kAudioHardwarePropertyDefaultInputDevice:
|
||||
PA_DEBUG(("audioPropertyCallback: default input device changed\n"));
|
||||
break;
|
||||
case kAudioHardwarePropertyDefaultOutputDevice:
|
||||
PA_DEBUG(("audioPropertyCallback: default output device changed\n"));
|
||||
break;
|
||||
case kAudioHardwarePropertyDefaultSystemOutputDevice:
|
||||
PA_DEBUG(("audioPropertyCallback: default system output device changed\n"));
|
||||
break;
|
||||
case kAudioHardwarePropertyDevices:
|
||||
PA_DEBUG(("audioPropertyCallback: device list changed\n"));
|
||||
PaUtil_DevicesChanged(1, NULL);
|
||||
break;
|
||||
default:
|
||||
PA_DEBUG(("audioPropertyCallback: unknown message id=%08lx\n", inPropertyID));
|
||||
break;
|
||||
}
|
||||
|
||||
return noErr;
|
||||
}
|
||||
|
||||
void PaUtil_InitializeHotPlug()
|
||||
{
|
||||
AudioHardwareAddPropertyListener(kAudioHardwarePropertyDevices,
|
||||
audioPropertyCallback, NULL);
|
||||
AudioHardwareAddPropertyListener(kAudioHardwarePropertyDefaultInputDevice,
|
||||
audioPropertyCallback, NULL);
|
||||
AudioHardwareAddPropertyListener(kAudioHardwarePropertyDefaultOutputDevice,
|
||||
audioPropertyCallback, NULL);
|
||||
}
|
||||
|
||||
void PaUtil_TerminateHotPlug()
|
||||
{
|
||||
AudioHardwareRemovePropertyListener(kAudioHardwarePropertyDevices,
|
||||
audioPropertyCallback);
|
||||
AudioHardwareRemovePropertyListener(kAudioHardwarePropertyDefaultInputDevice,
|
||||
audioPropertyCallback);
|
||||
AudioHardwareRemovePropertyListener(kAudioHardwarePropertyDefaultOutputDevice,
|
||||
audioPropertyCallback);
|
||||
}
|
||||
|
||||
void PaUtil_LockHotPlug()
|
||||
{
|
||||
}
|
||||
|
||||
void PaUtil_UnlockHotPlug()
|
||||
{
|
||||
}
|
||||
|
||||
147
src/os/unix/pa_linux_hotplug.c
Normal file
147
src/os/unix/pa_linux_hotplug.c
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
|
||||
#include "pa_util.h"
|
||||
#include "pa_debugprint.h"
|
||||
#include "pa_allocation.h"
|
||||
#include "pa_linux_alsa.h"
|
||||
#include "pa_hostapi.h"
|
||||
|
||||
#include <alsa/asoundlib.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <pthread.h>
|
||||
|
||||
/* Implemented in pa_front.c
|
||||
@param first 0 = unknown, 1 = insertion, 2 = removal
|
||||
@param second Host specific device change info (in windows it is the (unicode) device path)
|
||||
*/
|
||||
extern void PaUtil_DevicesChanged(unsigned, void*);
|
||||
|
||||
static pthread_t g_thread_id;
|
||||
static pthread_mutex_t g_mutex;
|
||||
static volatile sig_atomic_t g_run = 0;
|
||||
|
||||
static int device_list_size(void)
|
||||
{
|
||||
snd_ctl_t *handle;
|
||||
int card, err, dev, idx;
|
||||
int nb = 0;
|
||||
snd_ctl_card_info_t *info;
|
||||
snd_pcm_info_t *pcminfo;
|
||||
snd_ctl_card_info_alloca(&info);
|
||||
snd_pcm_info_alloca(&pcminfo);
|
||||
|
||||
card = -1;
|
||||
if (snd_card_next(&card) < 0 || card < 0)
|
||||
{
|
||||
return nb;
|
||||
}
|
||||
|
||||
while (card >= 0)
|
||||
{
|
||||
char name[32];
|
||||
|
||||
sprintf(name, "hw:%d", card);
|
||||
if ((err = snd_ctl_open(&handle, name, 0)) < 0)
|
||||
{
|
||||
goto next_card;
|
||||
}
|
||||
if ((err = snd_ctl_card_info(handle, info)) < 0)
|
||||
{
|
||||
snd_ctl_close(handle);
|
||||
goto next_card;
|
||||
}
|
||||
dev = -1;
|
||||
while (1)
|
||||
{
|
||||
unsigned int count;
|
||||
int hasPlayback = 0;
|
||||
int hasCapture = 0;
|
||||
|
||||
snd_ctl_pcm_next_device(handle, &dev);
|
||||
|
||||
if (dev < 0)
|
||||
break;
|
||||
snd_pcm_info_set_device(pcminfo, dev);
|
||||
snd_pcm_info_set_subdevice(pcminfo, 0);
|
||||
snd_pcm_info_set_stream(pcminfo, SND_PCM_STREAM_CAPTURE);
|
||||
if ((err = snd_ctl_pcm_info(handle, pcminfo)) >= 0)
|
||||
{
|
||||
hasCapture = 1;
|
||||
}
|
||||
|
||||
snd_pcm_info_set_stream(pcminfo, SND_PCM_STREAM_PLAYBACK);
|
||||
if ((err = snd_ctl_pcm_info(handle, pcminfo)) >= 0)
|
||||
{
|
||||
hasPlayback = 1;
|
||||
|
||||
count = snd_pcm_info_get_subdevices_count(pcminfo);
|
||||
}
|
||||
|
||||
if(hasPlayback == 0 && hasCapture == 0)
|
||||
continue;
|
||||
|
||||
nb++;
|
||||
}
|
||||
snd_ctl_close(handle);
|
||||
next_card:
|
||||
if (snd_card_next(&card) < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return nb;
|
||||
}
|
||||
|
||||
static void* thread_fcn(void* data)
|
||||
{
|
||||
int currentDevices = 0;
|
||||
|
||||
currentDevices = device_list_size();
|
||||
|
||||
while(g_run)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
sleep(1);
|
||||
count = device_list_size();
|
||||
if(count != currentDevices)
|
||||
{
|
||||
/* 1 = add device, 2 = remove device */
|
||||
int add = (count > currentDevices) ? 1 : 2;
|
||||
|
||||
currentDevices = count;
|
||||
|
||||
PaUtil_DevicesChanged(add, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void PaUtil_InitializeHotPlug()
|
||||
{
|
||||
pthread_mutex_init(&g_mutex, NULL);
|
||||
g_run = 1;
|
||||
pthread_create(&g_thread_id, NULL, thread_fcn, NULL);
|
||||
}
|
||||
|
||||
void PaUtil_TerminateHotPlug()
|
||||
{
|
||||
void* ret = NULL;
|
||||
|
||||
g_run = 0;
|
||||
pthread_join(g_thread_id, &ret);
|
||||
pthread_mutex_destroy(&g_mutex);
|
||||
}
|
||||
|
||||
void PaUtil_LockHotPlug()
|
||||
{
|
||||
pthread_mutex_lock(&g_mutex);
|
||||
}
|
||||
|
||||
void PaUtil_UnlockHotPlug()
|
||||
{
|
||||
pthread_mutex_unlock(&g_mutex);
|
||||
}
|
||||
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* $Id$
|
||||
* $Id: pa_win_hostapis.c 1661 2011-04-28 18:54:46Z rob_bielik $
|
||||
* Portable Audio I/O Library Windows initialization table
|
||||
*
|
||||
* Based on the Open Source API proposed by Ross Bencina
|
||||
|
|
@ -81,7 +81,7 @@ PaUtilHostApiInitializer *paHostApiInitializers[] =
|
|||
#endif
|
||||
|
||||
#if PA_USE_WDMKS
|
||||
PaWinWdm_Initialize,
|
||||
//PaWinWdm_Initialize,
|
||||
#endif
|
||||
|
||||
#if PA_USE_SKELETON
|
||||
|
|
|
|||
|
|
@ -186,6 +186,8 @@ static LRESULT CALLBACK PaMsgWinProcW(HWND hWnd, UINT msg, WPARAM wParam, LPARAM
|
|||
{
|
||||
PA_DEBUG(("Device inserted : %S\n", ptr->dbcc_name));
|
||||
InsertDeviceIntoCache(pInfo, ptr->dbcc_name);
|
||||
/* yield some seconds because added device may not be completely configured */
|
||||
Sleep(2000);
|
||||
PaUtil_DevicesChanged(1, ptr->dbcc_name);
|
||||
}
|
||||
}
|
||||
|
|
@ -202,6 +204,7 @@ static LRESULT CALLBACK PaMsgWinProcW(HWND hWnd, UINT msg, WPARAM wParam, LPARAM
|
|||
if (RemoveDeviceFromCache(pInfo, ptr->dbcc_name))
|
||||
{
|
||||
PA_DEBUG(("Device removed : %S\n", ptr->dbcc_name));
|
||||
Sleep(2000);
|
||||
PaUtil_DevicesChanged(2, ptr->dbcc_name);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "portaudio.h"
|
||||
|
||||
|
|
@ -33,9 +34,10 @@ int main(int argc, char* argv[])
|
|||
|
||||
for(;;){
|
||||
printDevices();
|
||||
|
||||
|
||||
printf( "press [enter] to update the device list. or q + [enter] to quit.\n" );
|
||||
if( getchar() == 'q' )
|
||||
char ch = getchar();
|
||||
if( ch == 'q' )
|
||||
break;
|
||||
|
||||
Pa_UpdateAvailableDeviceList();
|
||||
|
|
|
|||
Loading…
Reference in a new issue