Index: directx.c =================================================================== --- directx.c (revision 11090) +++ directx.c (working copy) @@ -143,7 +143,20 @@ } notification_thread_t; + /***************************************************************************** + * directSoundDevice: List of available audio devices + *****************************************************************************/ +struct directSoundDevice; +typedef struct directSoundDevice +{ + LPGUID p_guid; + char *psz_description; + char *psz_module; + struct directSoundDevice *p_next; +} directSoundDevice; + +/***************************************************************************** * aout_sys_t: directx audio output method descriptor ***************************************************************************** * This structure is part of the audio output thread descriptor. @@ -161,7 +174,7 @@ notification_thread_t *p_notif; /* DirectSoundThread id */ int b_playing; /* playing status */ - + int i_device_id; /* User defined device index */ int i_frame_size; /* Size in bytes of one frame */ vlc_bool_t b_chan_reorder; /* do we need channel reordering */ @@ -206,6 +219,10 @@ /***************************************************************************** * Module descriptor *****************************************************************************/ +#define FLOAT_TEXT N_("Output device") +#define FLOAT_LONGTEXT N_( \ + "DirectX device number: 0 default device, 1..N device by number" \ + "(Note that the default device appears as 0 AND another number)." ) vlc_module_begin(); set_description( _("DirectX audio output") ); set_shortname( "DirectX" ); @@ -213,6 +230,10 @@ set_category( CAT_AUDIO ); set_subcategory( SUBCAT_AUDIO_AOUT ); add_shortcut( "directx" ); + /* Add variable to VLC directx-device, default value 0, don't callback, + name the GUI field, GUI tooltip, display as advanced in preferences */ + add_integer( "directx-device", 0, NULL, FLOAT_TEXT, + FLOAT_LONGTEXT, VLC_TRUE ); set_callbacks( OpenAudio, CloseAudio ); vlc_module_end(); @@ -247,6 +268,13 @@ p_aout->output.pf_play = Play; aout_VolumeSoftInit( p_aout ); + + /* Retrieve output device id from config */ + var_Create( p_aout, "directx-device", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT); + var_Get( p_aout, "directx-device", &val ); + p_aout->output.p_sys->i_device_id = val.i_int; + + /* Initialise DirectSound */ if( InitDirectSound( p_aout ) ) { @@ -594,12 +622,72 @@ } /***************************************************************************** + * CallBackDirectSoundEnum: callback to enumerate available devices + *****************************************************************************/ +static int CALLBACK CallBackDirectSoundEnum (LPGUID p_guid, LPCSTR psz_desc, + LPCSTR psz_mod, LPVOID p_list) +{ + directSoundDevice *p_ad; + directSoundDevice *p_otherad = (directSoundDevice *)p_list; + p_ad = malloc( sizeof( directSoundDevice ) ); + + /* GUID == NULL is primary (default) device */ + if (p_guid == NULL) + { + p_ad->p_guid = NULL; + } + else + { + p_ad->p_guid = malloc( sizeof( GUID ) ); + memcpy( p_ad->p_guid, p_guid, sizeof( GUID ) ); + } + + /* Desc & mod not used, kept for next author to use if needed */ + p_ad->psz_description = malloc( sizeof(char) * (strlen(psz_desc) + 1) ); + strcpy(p_ad->psz_description, psz_desc); + p_ad->psz_module = malloc( sizeof(char) * (strlen(psz_mod) + 1) ); + strcpy(p_ad->psz_module, psz_mod); + + /* add to end of list */ + p_ad->p_next = NULL; + while( p_otherad->p_next != NULL ) + p_otherad = p_otherad->p_next; + p_otherad->p_next = p_ad; + return 1; +} +/***************************************************************************** + * DirectSoundEnumCleanup: free memory used when enumerating devices + *****************************************************************************/ +static void DirectSoundEnumCleanup(directSoundDevice *p_headDev) { + directSoundDevice *p_currDev; /* current device */ + directSoundDevice *p_delDev; /* useful pointer for deleting devices */ + /* clean up: delete the enumerated devices */ + p_currDev = p_headDev->p_next; + while (p_currDev->p_next != NULL) { + p_delDev = p_currDev; + p_currDev = p_currDev->p_next; + free(p_delDev->p_guid); + free(p_delDev); + } + free(p_currDev->p_guid); + free(p_currDev); + free(p_headDev); +} +/***************************************************************************** * InitDirectSound: handle all the gory details of DirectSound initialisation *****************************************************************************/ static int InitDirectSound( aout_instance_t *p_aout ) { HRESULT (WINAPI *OurDirectSoundCreate)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN); - + HRESULT (WINAPI *OurDirectSoundEnumerate)(LPDSENUMCALLBACK, LPVOID); + int i_selectedId; /* user defined index of device */ + directSoundDevice *p_headDev; /* head of device list */ + directSoundDevice *p_currDev; /* current device */ + + i_selectedId = p_aout->output.p_sys->i_device_id; /* get user selected id */ + p_headDev = malloc(sizeof(directSoundDevice)); + p_headDev->p_next = NULL; + p_aout->output.p_sys->hdsound_dll = LoadLibrary("DSOUND.DLL"); if( p_aout->output.p_sys->hdsound_dll == NULL ) { @@ -615,15 +703,55 @@ msg_Warn( p_aout, "GetProcAddress FAILED" ); goto error; } - - /* Create the direct sound object */ - if FAILED( OurDirectSoundCreate( NULL, &p_aout->output.p_sys->p_dsobject, + + /* Get DirectSoundEnumerate + (note getting ASCII call, not Unicode DirectSoundEnumerateW) */ + OurDirectSoundEnumerate = (void *)GetProcAddress( + p_aout->output.p_sys->hdsound_dll, + "DirectSoundEnumerateA" ); + + if( OurDirectSoundCreate == NULL ) + { + msg_Warn( p_aout, "GetProcAddress DirectSoundEnumerateA FAILED" ); + goto error; + } + + /* attempt enumeration */ + if (FAILED ( OurDirectSoundEnumerate( CallBackDirectSoundEnum, p_headDev))) + { + msg_Warn( p_aout, "Enumeration of DirectSound devices FAILED" ); + goto error; + } + else + { + /* ignore negative device id + (unnecessary, will default to first device) + ignore id past end of list + (default to last device) */ + + /* loop through to the selected device */ + p_currDev = p_headDev->p_next; + while (p_currDev->p_next != NULL && 0 < i_selectedId) + { + i_selectedId--; + p_currDev = p_currDev->p_next; + } + } + + /* Create the direct sound object */ + if FAILED( OurDirectSoundCreate( p_currDev->p_guid, + &p_aout->output.p_sys->p_dsobject, NULL ) ) { + /* clean up enumerated devices */ + DirectSoundEnumCleanup(p_headDev); msg_Warn( p_aout, "cannot create a direct sound device" ); goto error; } + /* clean up enumerated devices */ + DirectSoundEnumCleanup(p_headDev); + /* Set DirectSound Cooperative level, ie what control we want over Windows * sound device. In our case, DSSCL_EXCLUSIVE means that we can modify the * settings of the primary buffer, but also that only the sound of our