]> Repos - portaudio/commitdiff
Adds portaudio sources [adds hotplug support for pa_linux_alsa,
authorRoss Bencina <rossb@audiomulch.com>
Sat, 3 Sep 2016 12:29:58 +0000 (22:29 +1000)
committerRoss Bencina <rossb@audiomulch.com>
Sat, 3 Sep 2016 12:29:58 +0000 (22:29 +1000)
pa_mac_core, plus some other tweaks]
damencho committed on Mar 29, 2012
d2076b1 from https://github.com/jitsi/libsrc/commits/master/portaudio.zip

17 files changed:
Makefile.in
configure
configure.in
src/common/pa_front.c
src/hostapi/alsa/pa_linux_alsa.c
src/hostapi/asio/pa_asio.cpp
src/hostapi/coreaudio/pa_mac_core.c
src/hostapi/jack/pa_jack.c
src/hostapi/oss/pa_unix_oss.c
src/hostapi/skeleton/pa_hostapi_skeleton.c
src/hostapi/wasapi/pa_win_wasapi.c
src/hostapi/wdmks/pa_win_wdmks.c
src/os/mac_osx/pa_osx_hotplug.c [new file with mode: 0644]
src/os/unix/pa_linux_hotplug.c [new file with mode: 0644]
src/os/win/pa_win_hostapis.c
src/os/win/pa_win_hotplug.c
test/patest_update_available_device_list.c

index 3f3fb4a78a14f3ff610655c479c89291da2e7184..26273cd07c3b5f59e705953546b5a9b27a99bbb6 100644 (file)
@@ -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 =
index 0af577567b6424b3f8efec7d6dc6bce96a3d2844..18640d05ea068a1da5ed077f41a8db3cb2476ac8 100755 (executable)
Binary files a/configure and b/configure differ
index 0c2e67a514678fd1662cf01008e84e2a7d0c5328..0749eb053e3af68af3dc9bd46939da82bd63b4b0 100644 (file)
@@ -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
index 13dbebfd1362fe14cb59b068d850a58259e128e9..5c6aae04e5fb67853c645cbcb7ca9e92e7ee20ca 100644 (file)
@@ -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 */
index eee10d87b9dc2d304491c0fa0ccc0e6569e6e506..468065265ffdb257a93de91d88e56470e795d80d 100644 (file)
@@ -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;
+}
+
index d77c7e7391af57fe4124daa3e61a671baa1f1b56..ff8ea3e1ff26fe215871435fcc600c88e3908a87 100644 (file)
@@ -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;
index 01376b989330e6c5744af56aeb09f34098495c81..a71a74c433f55665a25c0aafe19ba312e0752e6d 100644 (file)
@@ -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;
+}
+
index 24a56d966a7d4e536b966be5b172fe2dd5b4ce2e..fd78e8b021bf5052be30a560b9fa7439602912da 100644 (file)
@@ -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;
index b523746af10964725a826d34949fd3051aa53b61..5da34c136a3b76427b13f2f0c1e4233c8afdf222 100644 (file)
@@ -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 ) );
 
index 84f73c712c1e3db9f332d9ba1940287d74aca30b..726c40768302be597aa4c8a6448b5cf97f35d814 100644 (file)
@@ -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,
index bd925870c115e23bd1be50235527d0d1d464ce64..0310151716f9d8859b35c5fc38120e00ff6823cc 100644 (file)
@@ -1386,6 +1386,9 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
         }\r
     }\r
 \r
+    (*hostApi)->ScanDeviceInfos = NULL;\r
+    (*hostApi)->CommitDeviceInfos = NULL;\r
+    (*hostApi)->DisposeDeviceInfos = NULL;\r
     (*hostApi)->Terminate = Terminate;\r
     (*hostApi)->OpenStream = OpenStream;\r
     (*hostApi)->IsFormatSupported = IsFormatSupported;\r
index 8070dbfeefef0e97752a13ce92a4a5e19635cf52..40297b7e0f3990806eb7905becfab2f7149c96d6 100644 (file)
@@ -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;
-}
\ No newline at end of file
+}
diff --git a/src/os/mac_osx/pa_osx_hotplug.c b/src/os/mac_osx/pa_osx_hotplug.c
new file mode 100644 (file)
index 0000000..22e7471
--- /dev/null
@@ -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()
+{
+}
+
diff --git a/src/os/unix/pa_linux_hotplug.c b/src/os/unix/pa_linux_hotplug.c
new file mode 100644 (file)
index 0000000..ba6eb19
--- /dev/null
@@ -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);
+}
+
index 7db5503c80ba7f496d3274c0bdd4d1fbe0209911..b1c6cbf15f007ad31df63aa469ea6a3f19784aaa 100644 (file)
@@ -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
index 044aaa1489ea76fd56cc6d6c59db83f23a336786..f2595832ace4c94de4f8c4f5949da8525351f2fe 100644 (file)
@@ -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);
                 }
             }
index ce6cdba90b84fdeefc0ff241338eb0c06d42828c..9e901e0263b43a478131b91d47d3c40178a83d5e 100644 (file)
@@ -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();