DirectSound and CoreAudio draft version of Pa_RefreshDevices() from David Stuart (Sourced from Ross private email June 30, 2010). This is an early version before we implemented 2-phase commit/rollback for device list changes. Pushed so that Evan can look at the CoreAudio code.
diff --git a/include/portaudio.h b/include/portaudio.h
index b55eb0e..1e81e6a 100644
--- a/include/portaudio.h
+++ b/include/portaudio.h
@@ -397,6 +397,16 @@
 */
 PaDeviceIndex Pa_GetDefaultOutputDevice( void );
 
+/** Normally the list of devices is frozen after initialization, until the
+ next time port audio is re-initialized. This provides API stability but
+ has the side effect that hot-pluggable devices such as USB audio headsets
+ might not be up-to-date while the program is running. This method is used
+ to refresh the list of devices within port audio without closing open
+ streams.
+
+ @return an error code which indicates whether the device refresh was successful.
+ */
+PaError Pa_RefreshDevices( void );
 
 /** The type used to represent monotonic time in seconds that can be used
  for syncronisation. The type is used for the outTime argument to the
diff --git a/src/common/pa_front.c b/src/common/pa_front.c
index 22a7fda..c323be7 100644
--- a/src/common/pa_front.c
+++ b/src/common/pa_front.c
@@ -700,6 +700,54 @@
 }
 
 
+PaError Pa_RefreshDevices( void )
+{
+    int i, baseDeviceIndex;
+    PaError result = paNoError;
+
+    PA_LOGAPI_ENTER( "Pa_RefreshDeviceList" );
+    if( !PA_IS_INITIALISED_ )
+        return paNotInitialized;
+
+    baseDeviceIndex = 0;
+    deviceCount_ = 0;
+
+    for( i=0; i < hostApisCount_; ++i )
+    {
+        PaUtilHostApiRepresentation *hostApi = hostApis_[i];
+        if( hostApi->RefreshDevices == NULL )
+        {
+            /* RefreshDevices not yet implemented for this backend. Just
+               assume that the baseDeviceIndex and the deviceCount_ are
+               incremented according to the values in the info */
+            baseDeviceIndex += hostApi->info.deviceCount;
+            deviceCount_ += hostApi->info.deviceCount;
+            continue;
+        }
+
+        PA_DEBUG(( "refreshing device list for host api %d.\n",i));
+
+        if(( result = hostApi->RefreshDevices( hostApi, i )) != paNoError )
+           return result;
+
+        assert( hostApi->info.defaultInputDevice < hostApi->info.deviceCount );
+        assert( hostApi->info.defaultOutputDevice < hostApi->info.deviceCount );
+
+        hostApi->privatePaFrontInfo.baseDeviceIndex = baseDeviceIndex;
+
+        if( hostApi->info.defaultInputDevice != paNoDevice )
+            hostApi->info.defaultInputDevice += baseDeviceIndex;
+
+        if( hostApi->info.defaultOutputDevice != paNoDevice )
+            hostApi->info.defaultOutputDevice += baseDeviceIndex;
+
+        baseDeviceIndex += hostApi->info.deviceCount;
+        deviceCount_ += hostApi->info.deviceCount;
+    }
+
+    return result;
+}
+
 const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceIndex device )
 {
     int hostSpecificDeviceIndex;
diff --git a/src/common/pa_hostapi.h b/src/common/pa_hostapi.h
index 7746747..eee4def 100644
--- a/src/common/pa_hostapi.h
+++ b/src/common/pa_hostapi.h
@@ -218,6 +218,8 @@
                                   const PaStreamParameters *inputParameters,
                                   const PaStreamParameters *outputParameters,
                                   double sampleRate );
+
+    PaError (*RefreshDevices)( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index );
 } PaUtilHostApiRepresentation;
 
 
diff --git a/src/hostapi/coreaudio/pa_mac_core.c b/src/hostapi/coreaudio/pa_mac_core.c
index bd50973..18df1d4 100644
--- a/src/hostapi/coreaudio/pa_mac_core.c
+++ b/src/hostapi/coreaudio/pa_mac_core.c
@@ -242,6 +242,7 @@
                            PaStreamFlags streamFlags,
                            PaStreamCallback *streamCallback,
                            void *userData );
+static PaError RefreshDevices( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index );
 static PaError CloseStream( PaStream* stream );
 static PaError StartStream( PaStream *stream );
 static PaError StopStream( PaStream *stream );
@@ -636,6 +637,7 @@
     (*hostApi)->Terminate = Terminate;
     (*hostApi)->OpenStream = OpenStream;
     (*hostApi)->IsFormatSupported = IsFormatSupported;
+    (*hostApi)->RefreshDevices = RefreshDevices;
 
     PaUtil_InitializeStreamInterface( &auhalHostApi->callbackStreamInterface,
                                       CloseStream, StartStream,
@@ -1669,6 +1671,83 @@
     return result;
 }
 
+PaError RefreshDevices( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex hostApiIndex )
+{
+    PaMacAUHAL *auhalHostApi = (PaMacAUHAL*)hostApi;
+    PaError result = paNoError;
+    PaDeviceInfo *deviceInfoArray;
+    int i;
+
+    VVDBUG(("RefreshDevices(): hostApiIndex=%d\n", hostApiIndex));
+	
+    auhalHostApi->devIds = NULL;
+    auhalHostApi->devCount = 0;
+
+    /* get the info we need about the devices */
+    result = gatherDeviceInfo( auhalHostApi );
+    if( result != paNoError )
+       goto error;
+
+    hostApi->info.defaultInputDevice = paNoDevice;
+    hostApi->info.defaultOutputDevice = paNoDevice;
+    hostApi->info.deviceCount = 0;  
+
+    /* If the device infos already exist, free the old memory */
+    if( hostApi->deviceInfos != NULL )
+    {
+        PaUtil_GroupFreeMemory( auhalHostApi->allocations, hostApi->deviceInfos );
+        hostApi->deviceInfos = NULL;
+    }
+
+    if( auhalHostApi->devCount > 0 )
+    {
+        hostApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
+                auhalHostApi->allocations, sizeof(PaDeviceInfo*) * auhalHostApi->devCount);
+        if( !hostApi->deviceInfos )
+        {
+            result = paInsufficientMemory;
+            goto error;
+        }
+
+        /* 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;
+        }
+
+        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--;
+            }
+        }
+    }
+
+error:
+    return result;
+}
+
 PaTime GetStreamTime( PaStream *s )
 {
    /* FIXME: I am not at all sure this timing info stuff is right.
diff --git a/src/hostapi/dsound/pa_win_ds.c b/src/hostapi/dsound/pa_win_ds.c
index 5625810..31e69ca 100644
--- a/src/hostapi/dsound/pa_win_ds.c
+++ b/src/hostapi/dsound/pa_win_ds.c
@@ -167,6 +167,7 @@
                                   const PaStreamParameters *inputParameters,
                                   const PaStreamParameters *outputParameters,
                                   double sampleRate );
+static PaError RefreshDevices( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index );
 static PaError CloseStream( PaStream* stream );
 static PaError StartStream( PaStream *stream );
 static PaError StopStream( PaStream *stream );
@@ -1188,6 +1189,7 @@
     (*hostApi)->Terminate = Terminate;
     (*hostApi)->OpenStream = OpenStream;
     (*hostApi)->IsFormatSupported = IsFormatSupported;
+    (*hostApi)->RefreshDevices = RefreshDevices;
 
     PaUtil_InitializeStreamInterface( &winDsHostApi->callbackStreamInterface, CloseStream, StartStream,
                                       StopStream, AbortStream, IsStreamStopped, IsStreamActive,
@@ -1392,6 +1394,145 @@
     return paFormatIsSupported;
 }
 
+/***********************************************************************************/
+static PaError RefreshDevices( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex hostApiIndex )
+{
+    PaWinDsHostApiRepresentation *winDsHostApi = (PaWinDsHostApiRepresentation*)hostApi;
+    DSDeviceNamesAndGUIDs deviceNamesAndGUIDs;
+    PaWinDsDeviceInfo *deviceInfoArray;
+    int i = 0, deviceCount = 0;
+    char comWasInitialized = winDsHostApi->comWasInitialized;
+    PaError result = paNoError;
+
+    if( !comWasInitialized )
+       return paInternalError;
+
+    /* initialise guid vectors so they can be safely deleted on error */
+    deviceNamesAndGUIDs.winDsHostApi = NULL;
+    deviceNamesAndGUIDs.inputNamesAndGUIDs.items = NULL;
+    deviceNamesAndGUIDs.outputNamesAndGUIDs.items = NULL;
+
+    hostApi->info.deviceCount = 0;
+    hostApi->info.defaultInputDevice = paNoDevice;
+    hostApi->info.defaultOutputDevice = paNoDevice;
+
+    /* DSound - enumerate devices to count them and to gather their GUIDs */
+    result = InitializeDSDeviceNameAndGUIDVector( &deviceNamesAndGUIDs.inputNamesAndGUIDs, winDsHostApi->allocations );
+    if( result != paNoError )
+        goto error;
+
+    result = InitializeDSDeviceNameAndGUIDVector( &deviceNamesAndGUIDs.outputNamesAndGUIDs, winDsHostApi->allocations );
+    if( result != paNoError )
+        goto error;
+
+    paWinDsDSoundEntryPoints.DirectSoundCaptureEnumerateA( (LPDSENUMCALLBACK)CollectGUIDsProc, (void *)&deviceNamesAndGUIDs.inputNamesAndGUIDs );
+    paWinDsDSoundEntryPoints.DirectSoundEnumerateA( (LPDSENUMCALLBACK)CollectGUIDsProc, (void *)&deviceNamesAndGUIDs.outputNamesAndGUIDs );
+
+    if( deviceNamesAndGUIDs.inputNamesAndGUIDs.enumerationError != paNoError )
+    {
+        result = deviceNamesAndGUIDs.inputNamesAndGUIDs.enumerationError;
+        goto error;
+    }
+
+    if( deviceNamesAndGUIDs.outputNamesAndGUIDs.enumerationError != paNoError )
+    {
+        result = deviceNamesAndGUIDs.outputNamesAndGUIDs.enumerationError;
+        goto error;
+    }
+
+    /* Free any old memory which might be in the device info */
+    if( hostApi->deviceInfos )
+    {
+        PaUtil_GroupFreeMemory( winDsHostApi->allocations, hostApi->deviceInfos );
+        hostApi->deviceInfos = NULL;
+    }
+
+    deviceCount = deviceNamesAndGUIDs.inputNamesAndGUIDs.count + deviceNamesAndGUIDs.outputNamesAndGUIDs.count;
+
+#ifdef PAWIN_USE_WDMKS_DEVICE_INFO
+    if( deviceCount > 0 )
+    {
+        deviceNamesAndGUIDs.winDsHostApi = winDsHostApi;
+        FindDevicePnpInterfaces( &deviceNamesAndGUIDs );
+    }
+#endif /* PAWIN_USE_WDMKS_DEVICE_INFO */
+
+    if( deviceCount > 0 )
+    {
+        /* allocate array for pointers to PaDeviceInfo structs */
+        hostApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
+                winDsHostApi->allocations, sizeof(PaDeviceInfo*) * deviceCount );
+        if( !hostApi->deviceInfos )
+        {
+            result = paInsufficientMemory;
+            goto error;
+        }
+
+        /* allocate all PaDeviceInfo structs in a contiguous block */
+        deviceInfoArray = (PaWinDsDeviceInfo*)PaUtil_GroupAllocateMemory(
+                winDsHostApi->allocations, sizeof(PaWinDsDeviceInfo) * deviceCount );
+        if( !deviceInfoArray )
+        {
+            result = paInsufficientMemory;
+            goto error;
+        }
+
+        for( i=0; i < deviceCount; ++i )
+        {
+            PaDeviceInfo *deviceInfo = &deviceInfoArray[i].inheritedDeviceInfo;
+            deviceInfo->structVersion = 2;
+            deviceInfo->hostApi = hostApiIndex;
+            deviceInfo->name = 0;
+            hostApi->deviceInfos[i] = deviceInfo;
+        }
+
+        for( i=0; i < deviceNamesAndGUIDs.inputNamesAndGUIDs.count; ++i )
+        {
+            result = AddInputDeviceInfoFromDirectSoundCapture( winDsHostApi,
+                    deviceNamesAndGUIDs.inputNamesAndGUIDs.items[i].name,
+                    deviceNamesAndGUIDs.inputNamesAndGUIDs.items[i].lpGUID,
+                    deviceNamesAndGUIDs.inputNamesAndGUIDs.items[i].pnpInterface );
+            if( result != paNoError )
+                goto error;
+        }
+
+        for( i=0; i < deviceNamesAndGUIDs.outputNamesAndGUIDs.count; ++i )
+        {
+            result = AddOutputDeviceInfoFromDirectSound( winDsHostApi,
+                    deviceNamesAndGUIDs.outputNamesAndGUIDs.items[i].name,
+                    deviceNamesAndGUIDs.outputNamesAndGUIDs.items[i].lpGUID,
+                    deviceNamesAndGUIDs.outputNamesAndGUIDs.items[i].pnpInterface );
+            if( result != paNoError )
+                goto error;
+        }
+    }    
+
+    result = TerminateDSDeviceNameAndGUIDVector( &deviceNamesAndGUIDs.inputNamesAndGUIDs );
+    if( result != paNoError )
+        goto error;
+
+    result = TerminateDSDeviceNameAndGUIDVector( &deviceNamesAndGUIDs.outputNamesAndGUIDs );
+    if( result != paNoError )
+        goto error;
+
+    return result;
+
+error:
+    if( winDsHostApi )
+    {
+        if( winDsHostApi->allocations )
+        {
+            PaUtil_FreeAllAllocations( winDsHostApi->allocations );
+            PaUtil_DestroyAllocationGroup( winDsHostApi->allocations );
+        }
+    }
+
+    TerminateDSDeviceNameAndGUIDVector( &deviceNamesAndGUIDs.inputNamesAndGUIDs );
+    TerminateDSDeviceNameAndGUIDVector( &deviceNamesAndGUIDs.outputNamesAndGUIDs );
+
+
+    return result;
+}
 
 /*************************************************************************
 ** Determine minimum number of buffers required for this host based