Ticket #11: portaudio-deviceschanged.patch

File portaudio-deviceschanged.patch, 44.7 KB (added by rossb, 9 months ago)

Eric Bunce's Plug-and-play patch for portaudio, see http://techweb.rfa.org/pipermail/portaudio/2007-October/007719.html

  • test/patest2.c

     
     1/** @file patest2.c 
     2    @ingroup test_src 
     3    @brief Ring modulate the audio input with a sine wave for 20 seconds with 
     4    device change detection. 
     5    @author Ross Bencina <rossb@audiomulch.com>,  
     6            Phil Burk http://www.softsynth.com, 
     7            Erik Bunce <kde@bunce.us> 
     8*/ 
     9/* 
     10 * $Id$ 
     11 * 
     12 * This program uses the PortAudio Portable Audio Library. 
     13 * For more information see: http://www.portaudio.com 
     14 * Copyright (c) 1999-2000 Ross Bencina and Phil Burk 
     15 * 
     16 * Permission is hereby granted, free of charge, to any person obtaining 
     17 * a copy of this software and associated documentation files 
     18 * (the "Software"), to deal in the Software without restriction, 
     19 * including without limitation the rights to use, copy, modify, merge, 
     20 * publish, distribute, sublicense, and/or sell copies of the Software, 
     21 * and to permit persons to whom the Software is furnished to do so, 
     22 * subject to the following conditions: 
     23 * 
     24 * The above copyright notice and this permission notice shall be 
     25 * included in all copies or substantial portions of the Software. 
     26 * 
     27 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
     28 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
     29 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
     30 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 
     31 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 
     32 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
     33 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
     34 */ 
     35 
     36/* 
     37 * The text above constitutes the entire PortAudio license; however,  
     38 * the PortAudio community also makes the following non-binding requests: 
     39 * 
     40 * Any person wishing to distribute modifications to the Software is 
     41 * requested to send the modifications to the original developer so that 
     42 * they can be incorporated into the canonical version. It is also  
     43 * requested that these non-binding requests be included along with the  
     44 * license above. 
     45 */ 
     46 
     47#include <stdio.h> 
     48#include <math.h> 
     49#include "portaudio.h" 
     50 
     51#ifndef M_PI 
     52#define M_PI (3.14159265) 
     53#endif 
     54 
     55#define SAMPLE_RATE (44100) 
     56 
     57typedef struct 
     58{ 
     59    float sine[100]; 
     60    int phase; 
     61    int sampsToGo; 
     62} 
     63patest1data; 
     64 
     65static void patest1DevicesChangedCallback( PaDevicesChangedFlags flags,  
     66                                           void *userData ) 
     67{ 
     68    int     i, numDevices, defaultDisplayed; 
     69    const   PaDeviceInfo *deviceInfo; 
     70    printf( "========================================\n" ); 
     71    printf( "patest1DevicesChangedCallback(%04x, %p)\n", flags, userData ); 
     72    numDevices = Pa_GetDeviceCount(); 
     73 
     74    if( numDevices < 0 ) 
     75    { 
     76        printf( "ERROR: Pa_CountDevices returned 0x%x\n", numDevices ); 
     77        return; 
     78    } 
     79     
     80    if ( ( flags & paDefaultInputDeviceChanged ) ) 
     81    { 
     82        i = Pa_GetDefaultInputDevice(); 
     83 
     84        deviceInfo = Pa_GetDeviceInfo( i ); 
     85        if ( deviceInfo != NULL) 
     86            printf( "Default input device changed to %d: %s (%s)\n", i, deviceInfo->name, Pa_GetHostApiInfo( deviceInfo->hostApi )->name ); 
     87        else 
     88            printf( "Default input device changed to %d\n", i ); 
     89    } 
     90 
     91 
     92    if ( ( flags & paDefaultOutputDeviceChanged ) ) 
     93    { 
     94        i = Pa_GetDefaultOutputDevice(); 
     95 
     96        deviceInfo = Pa_GetDeviceInfo( i ); 
     97        if ( deviceInfo ) 
     98            printf( "Default output device changed to %d: %s (%s)\n", i, deviceInfo->name, Pa_GetHostApiInfo( deviceInfo->hostApi )->name ); 
     99        else 
     100            printf( "Default output device changed to %d\n", i ); 
     101    } 
     102 
     103    /* only display the new list if the list has already changed */ 
     104    if ( ( flags & paDevicesListChanged ) == 0 ) 
     105        return; 
     106 
     107    printf( "Hardware device list changed\n" ); 
     108         
     109    printf( "Number of devices = %d\n", numDevices ); 
     110    for( i=0; i<numDevices; i++ ) 
     111    { 
     112        deviceInfo = Pa_GetDeviceInfo( i ); 
     113        printf( "--------------------------------------- device #%d\n", i ); 
     114                 
     115    /* Mark global and API specific default devices */ 
     116        defaultDisplayed = 0; 
     117        if( i == Pa_GetDefaultInputDevice() ) 
     118        { 
     119            printf( "[ Default Input" ); 
     120            defaultDisplayed = 1; 
     121        } 
     122        else if( i == Pa_GetHostApiInfo( deviceInfo->hostApi )->defaultInputDevice ) 
     123        { 
     124            const PaHostApiInfo *hostInfo = Pa_GetHostApiInfo( deviceInfo->hostApi ); 
     125            printf( "[ Default %s Input", hostInfo->name ); 
     126            defaultDisplayed = 1; 
     127        } 
     128         
     129        if( i == Pa_GetDefaultOutputDevice() ) 
     130        { 
     131            printf( (defaultDisplayed ? "," : "[") ); 
     132            printf( " Default Output" ); 
     133            defaultDisplayed = 1; 
     134        } 
     135        else if( i == Pa_GetHostApiInfo( deviceInfo->hostApi )->defaultOutputDevice ) 
     136        { 
     137            const PaHostApiInfo *hostInfo = Pa_GetHostApiInfo( deviceInfo->hostApi ); 
     138            printf( (defaultDisplayed ? "," : "[") );                 
     139            printf( " Default %s Output", hostInfo->name ); 
     140            defaultDisplayed = 1; 
     141        } 
     142 
     143        if( defaultDisplayed ) 
     144            printf( " ]\n" ); 
     145 
     146    /* print device info fields */ 
     147        printf( "Name                        = %s\n", deviceInfo->name ); 
     148        printf( "Host API                    = %s\n",  Pa_GetHostApiInfo( deviceInfo->hostApi )->name ); 
     149        printf( "Max inputs = %d", deviceInfo->maxInputChannels  ); 
     150        printf( ", Max outputs = %d\n", deviceInfo->maxOutputChannels  ); 
     151 
     152        printf( "Default low input latency   = %8.3f\n", deviceInfo->defaultLowInputLatency  ); 
     153        printf( "Default low output latency  = %8.3f\n", deviceInfo->defaultLowOutputLatency  ); 
     154        printf( "Default high input latency  = %8.3f\n", deviceInfo->defaultHighInputLatency  ); 
     155        printf( "Default high output latency = %8.3f\n", deviceInfo->defaultHighOutputLatency  ); 
     156    } 
     157} 
     158 
     159static int patest1Callback( const void *inputBuffer, void *outputBuffer, 
     160                            unsigned long framesPerBuffer, 
     161                            const PaStreamCallbackTimeInfo* timeInfo, 
     162                            PaStreamCallbackFlags statusFlags, 
     163                            void *userData ) 
     164{ 
     165    patest1data *data = (patest1data*)userData; 
     166    float *in = (float*)inputBuffer; 
     167    float *out = (float*)outputBuffer; 
     168    int framesToCalc = framesPerBuffer; 
     169    unsigned long i = 0; 
     170    int finished; 
     171 
     172    if( data->sampsToGo < framesPerBuffer ) 
     173    { 
     174        framesToCalc = data->sampsToGo; 
     175        finished = paComplete; 
     176    } 
     177    else 
     178    { 
     179        finished = paContinue; 
     180    } 
     181 
     182    for( ; i<framesToCalc; i++ ) 
     183    { 
     184        *out++ = *in++ * data->sine[data->phase];  /* left */ 
     185        *out++ = *in++ * data->sine[data->phase++];  /* right */ 
     186        if( data->phase >= 100 ) 
     187            data->phase = 0; 
     188    } 
     189 
     190    data->sampsToGo -= framesToCalc; 
     191 
     192    /* zero remainder of final buffer if not already done */ 
     193    for( ; i<framesPerBuffer; i++ ) 
     194    { 
     195        *out++ = 0; /* left */ 
     196        *out++ = 0; /* right */ 
     197    } 
     198     
     199    return finished; 
     200} 
     201 
     202int main(int argc, char* argv[]); 
     203int main(int argc, char* argv[]) 
     204{ 
     205    PaStream                *stream; 
     206    PaError                 err; 
     207    patest1data             data; 
     208    int                     i; 
     209    PaStreamParameters      inputParameters, outputParameters; 
     210    const PaHostErrorInfo*  herr; 
     211 
     212    printf("patest1.c\n"); fflush(stdout); 
     213    printf("Ring modulate input for 20 seconds.\n"); fflush(stdout); 
     214     
     215    /* initialise sinusoidal wavetable */ 
     216    for( i=0; i<100; i++ ) 
     217        data.sine[i] = sin( ((double)i/100.) * M_PI * 2. ); 
     218    data.phase = 0; 
     219    data.sampsToGo = SAMPLE_RATE * 20;        /* 20 seconds. */ 
     220 
     221    /* initialise portaudio subsytem */ 
     222    err = Pa_Initialize(); 
     223 
     224    err = Pa_AddDevicesChangedCallback(patest1DevicesChangedCallback, NULL); 
     225 
     226    inputParameters.device = Pa_GetDefaultInputDevice();    /* default input device */ 
     227    inputParameters.channelCount = 2;                       /* stereo input */ 
     228    inputParameters.sampleFormat = paFloat32;               /* 32 bit floating point input */ 
     229    inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency; 
     230    inputParameters.hostApiSpecificStreamInfo = NULL; 
     231 
     232    outputParameters.device = Pa_GetDefaultOutputDevice();  /* default output device */ 
     233    outputParameters.channelCount = 2;                      /* stereo output */ 
     234    outputParameters.sampleFormat = paFloat32;              /* 32 bit floating point output */ 
     235    outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency; 
     236    outputParameters.hostApiSpecificStreamInfo = NULL; 
     237 
     238    err = Pa_OpenStream( 
     239                        &stream, 
     240                        &inputParameters, 
     241                        &outputParameters, 
     242                        (double)SAMPLE_RATE, /* Samplerate in Hertz. */ 
     243                        512,                 /* Small buffers */ 
     244                        paClipOff,           /* We won't output out of range samples so don't bother clipping them. */ 
     245                        patest1Callback, 
     246                        &data ); 
     247    if( err != paNoError ) goto done; 
     248 
     249    err = Pa_StartStream( stream ); 
     250    if( err != paNoError ) goto done; 
     251     
     252    printf( "Press any key to end.\n" ); fflush(stdout); 
     253          
     254    getc( stdin ); /* wait for input before exiting */ 
     255 
     256    err = Pa_AbortStream( stream ); 
     257    if( err != paNoError ) goto done; 
     258     
     259    printf( "Waiting for stream to complete...\n" ); 
     260 
     261    /* sleep until playback has finished */ 
     262    while( ( err = Pa_IsStreamActive( stream ) ) == 1 ) Pa_Sleep(1000); 
     263    if( err < 0 ) goto done; 
     264 
     265    err = Pa_CloseStream( stream ); 
     266    if( err != paNoError ) goto done; 
     267 
     268done: 
     269    err = Pa_RemoveDevicesChangedCallback(patest1DevicesChangedCallback, NULL); 
     270 
     271    Pa_Terminate(); 
     272 
     273    if( err != paNoError ) 
     274    { 
     275        fprintf( stderr, "An error occured while using portaudio\n" ); 
     276        if( err == paUnanticipatedHostError ) 
     277        { 
     278            fprintf( stderr, " unanticipated host error.\n"); 
     279            herr = Pa_GetLastHostErrorInfo(); 
     280            if (herr) 
     281            { 
     282                fprintf( stderr, " Error number: %ld\n", herr->errorCode ); 
     283                if (herr->errorText) 
     284                    fprintf( stderr, " Error text: %s\n", herr->errorText ); 
     285            } 
     286            else 
     287                fprintf( stderr, " Pa_GetLastHostErrorInfo() failed!\n" ); 
     288        } 
     289        else 
     290        { 
     291            fprintf( stderr, " Error number: %d\n", err ); 
     292            fprintf( stderr, " Error text: %s\n", Pa_GetErrorText( err ) ); 
     293        } 
     294 
     295        err = 1;          /* Always return 0 or 1, but no other return codes. */ 
     296    } 
     297 
     298    printf( "bye\n" ); 
     299 
     300    return err; 
     301} 
  • Makefile.in

    Property changes on: test/patest2.c
    ___________________________________________________________________
    Name: svn:mime-type
       + text/plain
    Name: svn:keywords
       + author id date revision
    Name: svn:eol-style
       + native
    
     
    5959        bin/paqa_devs \ 
    6060        bin/paqa_errs \ 
    6161        bin/patest1 \ 
     62        bin/patest2 \ 
    6263        bin/patest_buffer \ 
    6364        bin/patest_callbackstop \ 
    6465        bin/patest_clip \ 
  • include/portaudio.h

     
    356356*/ 
    357357const PaHostErrorInfo* Pa_GetLastHostErrorInfo( void ); 
    358358 
     359/* Device enumeration and capabilities */ 
    359360 
     361/** Flags used to indicate which device states have changed. 
     362  
     363    @see paDevicesListAboutToBeChanged, paDevicesListChanged, 
     364    paDefaultInputDeviceChanged, paDefaultOutputDeviceChanged 
     365*/ 
     366typedef unsigned long PaDevicesChangedFlags; 
    360367 
    361 /* Device enumeration and capabilities */ 
     368/** Indicates that the list of devices is about to be changed. 
    362369 
     370 This is sent before the list of devices is changed.  All PaDeviceInfo  
     371 structures retrieved prior to this notification are about to be freed. 
     372 
     373 @see PaDevicesChangedFlags 
     374*/ 
     375#define paDevicesListAboutToBeChanged   ((PaDevicesChangedFlags) 0x00000001) 
     376 
     377/** Indicates that the list of devices has changed. 
     378 
     379 This is sent after the PortAudio list of devices has changed. 
     380 All PaDeviceInfo structures retrieved prior to this notification are now  
     381 invalid. 
     382 
     383 @see PaDevicesChangedFlags 
     384*/ 
     385#define paDevicesListChanged            ((PaDevicesChangedFlags) 0x00000002) 
     386 
     387/** Indicates that the systems default input device has changed. 
     388 
     389 @see PaDevicesChangedFlags 
     390*/ 
     391#define paDefaultInputDeviceChanged     ((PaDevicesChangedFlags) 0x00000004) 
     392 
     393/** Indicates that the systems default output device has changed. 
     394 
     395 @see PaDevicesChangedFlags 
     396*/ 
     397#define paDefaultOutputDeviceChanged    ((PaDevicesChangedFlags) 0x00000008) 
     398 
     399/** Functions of type PaDevicesChangedCallback are implemented by PortAudio 
     400 clients. They can be registered using the Pa_SetDevicesChangedCallback 
     401 function. Once registered they are called when the state of installed devices 
     402 changes. 
     403 
     404 @param flags The flags indicate what aspects of the known devices has 
     405 changed. 
     406 @param userData The userData parameter supplied t Pa_SetDevicesChangedCallback(). 
     407 
     408 @see Pa_AddDevicesChangedCallback, Pa_RemoveDevicesChangedCallback,  
     409 PaDevicesChangedFlags 
     410 */ 
     411typedef void PaDevicesChangedCallback( PaDevicesChangedFlags flags,  
     412                                       void *userData ); 
     413 
     414/** Add a devices changed callback function which will be called when the  
     415 the state of installed devices changes. 
     416 
     417 @note If no callback is registered the traditional behavior of ignoring devices 
     418 changes is maintained. However, if a callback is registered then PortAudio  
     419 will automatically rescan the set of available devices when a change is detected. 
     420 This is done in an attempt to maintain backwards compatibility for older  
     421 clients. 
     422 
     423 @param userData A client supplied pointer which is passed to the stream callback 
     424 function. It could for example, contain a pointer to instance data necessary for 
     425 processing device change notifications. 
     426*/ 
     427PaError Pa_AddDevicesChangedCallback( PaDevicesChangedCallback* devicesCallback, 
     428                                      void *userData ); 
     429 
     430/** Remove a devices changed callback function which will be called when the  
     431 the state of installed devices changes. 
     432 
     433 @param userData A client supplied pointer which is passed to the stream callback 
     434 function. It could for example, contain a pointer to instance data necessary for 
     435 processing device change notifications. 
     436*/ 
     437PaError Pa_RemoveDevicesChangedCallback( PaDevicesChangedCallback* devicesCallback, 
     438                                      void *userData ); 
     439 
     440/** Rescans the system in order to detect new devices. 
     441 
     442 It will call the registered PaDevicesChangedCallback with paDevicesListChanged 
     443 when it is done. 
     444 
     445 @note This will free all PaDeviceInfo structures that may have been returned 
     446 previously. 
     447*/ 
     448PaError Pa_RescanDevices( void ); 
     449 
    363450/** Retrieve the number of available devices. The number of available devices 
    364451 may be zero. 
    365452 
     
    470557 
    471558 @note PortAudio manages the memory referenced by the returned pointer, 
    472559 the client must not manipulate or free the memory. The pointer is only 
    473  guaranteed to be valid between calls to Pa_Initialize() and Pa_Terminate(). 
     560 guaranteed to be valid between calls to Pa_Initialize(), Pa_RescanDevices(), 
     561 and Pa_Terminate(). 
    474562 
    475563 @see PaDeviceInfo, PaDeviceIndex 
    476564*/ 
  • src/hostapi/alsa/pa_linux_alsa.c

     
    254254    (*hostApi)->info.name = "ALSA"; 
    255255 
    256256    (*hostApi)->Terminate = Terminate; 
     257    (*hostApi)->RescanDevices = NULL; 
    257258    (*hostApi)->OpenStream = OpenStream; 
    258259    (*hostApi)->IsFormatSupported = IsFormatSupported; 
    259260 
  • src/hostapi/oss/pa_unix_oss.c

     
    250250    (*hostApi)->info.type = paOSS; 
    251251    (*hostApi)->info.name = "OSS"; 
    252252    (*hostApi)->Terminate = Terminate; 
     253    (*hostApi)->RescanDevices = NULL; 
    253254    (*hostApi)->OpenStream = OpenStream; 
    254255    (*hostApi)->IsFormatSupported = IsFormatSupported; 
    255256 
  • src/hostapi/wasapi/pa_win_wasapi.cpp

     
    635635    spEndpoints->Release(); 
    636636 
    637637    (*hostApi)->Terminate = Terminate; 
     638    (*hostApi)->RescanDevices = NULL; 
    638639    (*hostApi)->OpenStream = OpenStream; 
    639640    (*hostApi)->IsFormatSupported = IsFormatSupported; 
    640641 
     
    19081909                                stream->outVol->SetMute(FALSE, NULL); 
    19091910                                bFirst = false; 
    19101911                        } 
    1911 #endif 
    1912  No newline at end of file 
     1912#endif 
  • src/hostapi/wdmks/pa_win_wdmks.c

     
    18761876    (*hostApi)->info.deviceCount = deviceCount; 
    18771877 
    18781878    (*hostApi)->Terminate = Terminate; 
     1879    (*hostApi)->RescanDevices = NULL; 
    18791880    (*hostApi)->OpenStream = OpenStream; 
    18801881    (*hostApi)->IsFormatSupported = IsFormatSupported; 
    18811882 
     
    32803281    /* IMPLEMENT ME, see portaudio.h for required behavior*/ 
    32813282    PA_LOGL_; 
    32823283    return 0; 
    3283 } 
    3284  No newline at end of file 
     3284} 
  • src/hostapi/wmme/pa_win_wmme.c

     
    10401040    InitializeDefaultDeviceIdsFromEnv( winMmeHostApi ); 
    10411041 
    10421042    (*hostApi)->Terminate = Terminate; 
     1043    (*hostApi)->RescanDevices = NULL; 
    10431044    (*hostApi)->OpenStream = OpenStream; 
    10441045    (*hostApi)->IsFormatSupported = IsFormatSupported; 
    10451046 
  • src/hostapi/jack/pa_jack.c

     
    746746    /* Register functions */ 
    747747 
    748748    (*hostApi)->Terminate = Terminate; 
     749    (*hostApi)->RescanDevices = NULL; 
    749750    (*hostApi)->OpenStream = OpenStream; 
    750751    (*hostApi)->IsFormatSupported = IsFormatSupported; 
    751752 
  • src/hostapi/coreaudio/pa_mac_core.c

     
    7070#include "pa_mac_core.h" 
    7171#include "pa_mac_core_utilities.h" 
    7272#include "pa_mac_core_blocking.h" 
     73#include "pa_debugprint.h" 
    7374 
    7475 
    7576#ifdef __cplusplus 
     
    227228#define RING_BUFFER_ADVANCE_DENOMINATOR (4) 
    228229 
    229230static void Terminate( struct PaUtilHostApiRepresentation *hostApi ); 
     231static PaError RescanDevices( struct PaUtilHostApiRepresentation *hostApi ); 
    230232static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, 
    231233                                  const PaStreamParameters *inputParameters, 
    232234                                  const PaStreamParameters *outputParameters, 
     
    324326      sfc( stream->streamRepresentation.userData ); 
    325327} 
    326328 
    327  
    328 /*currently, this is only used in initialization, but it might be modified 
    329   to be used when the list of devices changes.*/ 
    330 static PaError gatherDeviceInfo(PaMacAUHAL *auhalHostApi) 
     329/* This is used during initialization, rescan, and default device changes to  
     330 gather information about the current default input device. */ 
     331static void gatherDefaultInputDevice(PaMacAUHAL *auhalHostApi) 
    331332{ 
    332     UInt32 size; 
    333     UInt32 propsize; 
    334     VVDBUG(("gatherDeviceInfo()\n")); 
    335     /* -- free any previous allocations -- */ 
    336     if( auhalHostApi->devIds ) 
    337         PaUtil_GroupFreeMemory(auhalHostApi->allocations, auhalHostApi->devIds); 
    338     auhalHostApi->devIds = NULL; 
    339  
    340     /* -- figure out how many devices there are -- */ 
    341     AudioHardwareGetPropertyInfo( kAudioHardwarePropertyDevices, 
    342                                   &propsize, 
    343                                   NULL ); 
    344     auhalHostApi->devCount = propsize / sizeof( AudioDeviceID ); 
    345  
    346     VDBUG( ( "Found %ld device(s).\n", auhalHostApi->devCount ) ); 
    347  
    348     /* -- copy the device IDs -- */ 
    349     auhalHostApi->devIds = (AudioDeviceID *)PaUtil_GroupAllocateMemory( 
    350                              auhalHostApi->allocations, 
    351                              propsize ); 
    352     if( !auhalHostApi->devIds ) 
    353         return paInsufficientMemory; 
    354     AudioHardwareGetProperty( kAudioHardwarePropertyDevices, 
    355                                   &propsize, 
    356                                   auhalHostApi->devIds ); 
    357 #ifdef MAC_CORE_VERBOSE_DEBUG 
    358     { 
    359        int i; 
    360        for( i=0; i<auhalHostApi->devCount; ++i ) 
    361           printf( "Device %d\t: %ld\n", i, auhalHostApi->devIds[i] ); 
    362     } 
    363 #endif 
    364  
    365     size = sizeof(AudioDeviceID); 
     333    UInt32 size = sizeof(AudioDeviceID); 
     334    VVDBUG(("gatherDefaultInputDevice()\n")); 
    366335    auhalHostApi->defaultIn  = kAudioDeviceUnknown; 
    367     auhalHostApi->defaultOut = kAudioDeviceUnknown; 
    368336 
    369337    /* determine the default device. */ 
    370338    /* I am not sure how these calls to AudioHardwareGetProperty() 
     
    385353                auhalHostApi->defaultIn = auhalHostApi->devIds[i]; 
    386354                break; 
    387355             } 
    388        } 
     356      } 
    389357    }    
     358    VDBUG( ( "Default in : %ld\n", auhalHostApi->defaultIn  ) ); 
     359} 
     360 
     361/* This is used during initialization, rescan, and default device changes to  
     362 gather information about the current default output device. */ 
     363static void gatherDefaultOutputDevice(PaMacAUHAL *auhalHostApi) 
     364{ 
     365    UInt32 size = sizeof(AudioDeviceID); 
     366    VVDBUG(("gatherDefaultOutputDevice()\n")); 
     367    auhalHostApi->defaultOut = kAudioDeviceUnknown; 
     368 
    390369    if( 0 != AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, 
    391370                     &size, 
    392371                     &auhalHostApi->defaultOut) ) { 
     
    404383             } 
    405384       } 
    406385    }    
    407  
    408     VDBUG( ( "Default in : %ld\n", auhalHostApi->defaultIn  ) ); 
    409386    VDBUG( ( "Default out: %ld\n", auhalHostApi->defaultOut ) ); 
     387} 
    410388 
     389/* This is used during initialization and rescan to gather information about  
     390 devices. */ 
     391static PaError gatherDeviceInfo(PaMacAUHAL *auhalHostApi) 
     392{ 
     393    UInt32 size; 
     394    UInt32 propsize; 
     395    VVDBUG(("gatherDeviceInfo()\n")); 
     396    /* -- free any previous allocations -- */ 
     397    if( auhalHostApi->devIds ) 
     398        PaUtil_GroupFreeMemory(auhalHostApi->allocations, auhalHostApi->devIds); 
     399    auhalHostApi->devIds = NULL; 
     400 
     401    /* -- figure out how many devices there are -- */ 
     402    AudioHardwareGetPropertyInfo( kAudioHardwarePropertyDevices, 
     403                                  &propsize, 
     404                                  NULL ); 
     405    auhalHostApi->devCount = propsize / sizeof( AudioDeviceID ); 
     406 
     407    VDBUG( ( "Found %ld device(s).\n", auhalHostApi->devCount ) ); 
     408 
     409    /* -- copy the device IDs -- */ 
     410    auhalHostApi->devIds = (AudioDeviceID *)PaUtil_GroupAllocateMemory( 
     411                             auhalHostApi->allocations, 
     412                             propsize ); 
     413    if( !auhalHostApi->devIds ) 
     414        return paInsufficientMemory; 
     415    AudioHardwareGetProperty( kAudioHardwarePropertyDevices, 
     416                                  &propsize, 
     417                                  auhalHostApi->devIds ); 
     418#ifdef MAC_CORE_VERBOSE_DEBUG 
     419    { 
     420       int i; 
     421       for( i=0; i<auhalHostApi->devCount; ++i ) 
     422          printf( "Device %d\t: %ld\n", i, auhalHostApi->devIds[i] ); 
     423    } 
     424#endif 
     425 
     426    gatherDefaultInputDevice(auhalHostApi); 
     427    gatherDefaultOutputDevice(auhalHostApi); 
     428 
    411429    return paNoError; 
    412430} 
    413431 
     432/* Callback for audio hardware property changes. */ 
     433static OSStatus audioPropertyCallback(AudioHardwarePropertyID inPropertyID,  
     434                                      void *refCon) 
     435{ 
     436    struct PaUtilHostApiRepresentation *hostApi =  
     437        (struct PaUtilHostApiRepresentation *)refCon; 
     438    PaMacAUHAL *auhalHostApi = (PaMacAUHAL*)hostApi; 
     439    int i; 
     440    switch (inPropertyID) 
     441    { 
     442        /* 
     443         * These are the other types of notifications we might receive, however, they are beyond 
     444         * the scope of this sample and we ignore them. 
     445         **/ 
     446    case kAudioHardwarePropertyDefaultInputDevice: 
     447        PA_DEBUG(("audioPropertyCallback: default input device changed\n")); 
     448 
     449        /* default to no device, in case we don't find it in the devIds. */ 
     450        hostApi->info.defaultInputDevice = paNoDevice; 
     451         
     452        gatherDefaultInputDevice(auhalHostApi); 
     453         
     454        /* attempt to find the device amongst the known devIds. */ 
     455        for( i=0; i < auhalHostApi->devCount; ++i ) 
     456        { 
     457            if (auhalHostApi->devIds[i] == auhalHostApi->defaultIn) 
     458                hostApi->info.defaultInputDevice = i; 
     459        } 
     460 
     461        PaUtil_DevicesChanged( paDefaultInputDeviceChanged ); 
     462        break; 
     463         
     464    case kAudioHardwarePropertyDefaultOutputDevice: 
     465        PA_DEBUG(("audioPropertyCallback: default output device changed\n")); 
     466 
     467        /* default to no device, in case we don't find it in the devIds. */ 
     468        hostApi->info.defaultOutputDevice = paNoDevice; 
     469 
     470        gatherDefaultOutputDevice(auhalHostApi); 
     471 
     472        /* attempt to find the device amongst the known devIds. */ 
     473        for( i=0; i < auhalHostApi->devCount; ++i ) 
     474        { 
     475            if (auhalHostApi->devIds[i] == auhalHostApi->defaultOut) 
     476                hostApi->info.defaultOutputDevice = i; 
     477        } 
     478 
     479        PaUtil_DevicesChanged( paDefaultOutputDeviceChanged ); 
     480        break; 
     481         
     482    case kAudioHardwarePropertyDefaultSystemOutputDevice: 
     483        PA_DEBUG(("audioPropertyCallback: default system output device changed\n")); 
     484        break; 
     485         
     486    case kAudioHardwarePropertyDevices: 
     487        PA_DEBUG(("audioPropertyCallback: device list changed\n")); 
     488        PaUtil_DevicesChanged( paUtilHardwareDevicesChanged ); 
     489        break; 
     490         
     491    default: 
     492        PA_DEBUG(("audioPropertyCallback: unknown message id=%08lx\n", inPropertyID)); 
     493        break; 
     494    } 
     495     
     496    return noErr; 
     497} 
     498 
    414499static PaError GetChannelInfo( PaMacAUHAL *auhalHostApi, 
    415500                               PaDeviceInfo *deviceInfo, 
    416501                               AudioDeviceID macCoreDeviceId, 
     
    626711    } 
    627712 
    628713    (*hostApi)->Terminate = Terminate; 
     714    (*hostApi)->RescanDevices = RescanDevices; 
    629715    (*hostApi)->OpenStream = OpenStream; 
    630716    (*hostApi)->IsFormatSupported = IsFormatSupported; 
    631717 
     
    647733                                      GetStreamReadAvailable, 
    648734                                      GetStreamWriteAvailable ); 
    649735 
     736    /* register the audio hardware change listener */ 
     737    AudioHardwareAddPropertyListener(kAudioHardwarePropertyDevices,  
     738                                     audioPropertyCallback, *hostApi); 
     739    AudioHardwareAddPropertyListener(kAudioHardwarePropertyDefaultInputDevice,  
     740                                     audioPropertyCallback, *hostApi); 
     741    AudioHardwareAddPropertyListener(kAudioHardwarePropertyDefaultOutputDevice,  
     742                                     audioPropertyCallback, *hostApi); 
     743     
    650744    return result; 
    651745 
    652746error: 
     
    676770