]> git.sesse.net Git - vlc/blob - modules/audio_output/waveout.c
4f1c28f01f3a93e0bf15f09b05c7cbd196182c43
[vlc] / modules / audio_output / waveout.c
1 /*****************************************************************************
2  * waveout.c : Windows waveOut plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2001 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Gildas Bazin <gbazin@videolan.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <vlc/vlc.h>
33 #include <vlc_plugin.h>
34 #include <vlc_aout.h>
35 #include <vlc_charset.h>
36
37 #include <windows.h>
38 #include <mmsystem.h>
39
40 #define FRAME_SIZE 4096              /* The size is in samples, not in bytes */
41 #define FRAMES_NUM 8
42
43 /*****************************************************************************
44  * Useful macros
45  *****************************************************************************/
46 #ifdef UNDER_CE
47 #   define DWORD_PTR DWORD
48 #   ifdef waveOutGetDevCaps
49 #       undef waveOutGetDevCaps
50         MMRESULT WINAPI waveOutGetDevCaps(UINT, LPWAVEOUTCAPS, UINT);
51 #   endif
52 #endif
53
54 #ifndef WAVE_FORMAT_IEEE_FLOAT
55 #   define WAVE_FORMAT_IEEE_FLOAT 0x0003
56 #endif
57
58 #ifndef WAVE_FORMAT_DOLBY_AC3_SPDIF
59 #   define WAVE_FORMAT_DOLBY_AC3_SPDIF 0x0092
60 #endif
61
62 #ifndef WAVE_FORMAT_EXTENSIBLE
63 #define  WAVE_FORMAT_EXTENSIBLE   0xFFFE
64 #endif
65
66 #ifndef SPEAKER_FRONT_LEFT
67 #   define SPEAKER_FRONT_LEFT             0x1
68 #   define SPEAKER_FRONT_RIGHT            0x2
69 #   define SPEAKER_FRONT_CENTER           0x4
70 #   define SPEAKER_LOW_FREQUENCY          0x8
71 #   define SPEAKER_BACK_LEFT              0x10
72 #   define SPEAKER_BACK_RIGHT             0x20
73 #   define SPEAKER_FRONT_LEFT_OF_CENTER   0x40
74 #   define SPEAKER_FRONT_RIGHT_OF_CENTER  0x80
75 #   define SPEAKER_BACK_CENTER            0x100
76 #   define SPEAKER_SIDE_LEFT              0x200
77 #   define SPEAKER_SIDE_RIGHT             0x400
78 #   define SPEAKER_TOP_CENTER             0x800
79 #   define SPEAKER_TOP_FRONT_LEFT         0x1000
80 #   define SPEAKER_TOP_FRONT_CENTER       0x2000
81 #   define SPEAKER_TOP_FRONT_RIGHT        0x4000
82 #   define SPEAKER_TOP_BACK_LEFT          0x8000
83 #   define SPEAKER_TOP_BACK_CENTER        0x10000
84 #   define SPEAKER_TOP_BACK_RIGHT         0x20000
85 #   define SPEAKER_RESERVED               0x80000000
86 #endif
87
88 #ifndef _WAVEFORMATEXTENSIBLE_
89 typedef struct {
90     WAVEFORMATEX    Format;
91     union {
92         WORD wValidBitsPerSample;       /* bits of precision  */
93         WORD wSamplesPerBlock;          /* valid if wBitsPerSample==0 */
94         WORD wReserved;                 /* If neither applies, set to zero. */
95     } Samples;
96     DWORD           dwChannelMask;      /* which channels are */
97                                         /* present in stream  */
98     GUID            SubFormat;
99 } WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE;
100 #endif
101
102 static const GUID __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = {WAVE_FORMAT_IEEE_FLOAT, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
103 static const GUID __KSDATAFORMAT_SUBTYPE_PCM = {WAVE_FORMAT_PCM, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
104 static const GUID __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF = {WAVE_FORMAT_DOLBY_AC3_SPDIF, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
105
106 /*****************************************************************************
107  * Local prototypes
108  *****************************************************************************/
109 static int  Open         ( vlc_object_t * );
110 static void Close        ( vlc_object_t * );
111 static void Play         ( aout_instance_t * );
112
113 /*****************************************************************************
114  * notification_thread_t: waveOut event thread
115  *****************************************************************************/
116 typedef struct notification_thread_t
117 {
118     VLC_COMMON_MEMBERS
119     aout_instance_t *p_aout;
120
121 } notification_thread_t;
122
123 /* local functions */
124 static void Probe        ( aout_instance_t * );
125 static int OpenWaveOut   ( aout_instance_t *, uint32_t,
126                            int, int, int, int, bool );
127 static int OpenWaveOutPCM( aout_instance_t *, uint32_t,
128                            int*, int, int, int, bool );
129 static int PlayWaveOut   ( aout_instance_t *, HWAVEOUT, WAVEHDR *,
130                            aout_buffer_t *, bool );
131
132 static void CALLBACK WaveOutCallback ( HWAVEOUT, UINT, DWORD, DWORD, DWORD );
133 static void WaveOutThread( notification_thread_t * );
134
135 static int VolumeInfos( aout_instance_t *, audio_volume_t * );
136 static int VolumeGet( aout_instance_t *, audio_volume_t * );
137 static int VolumeSet( aout_instance_t *, audio_volume_t );
138
139 static int WaveOutClearDoneBuffers(aout_sys_t *p_sys);
140
141 static int ReloadWaveoutDevices( vlc_object_t *, char const *,
142                                 vlc_value_t, vlc_value_t, void * );
143 static uint32_t findDeviceID(char *);
144
145 static const char psz_device_name_fmt[] = "%s ($%x,$%x)";
146
147 static const char *ppsz_adev[] = { "wavemapper", };
148 static const char *ppsz_adev_text[] = { N_("Microsoft Soundmapper") };
149
150
151
152 /*****************************************************************************
153  * Module descriptor
154  *****************************************************************************/
155 #define FLOAT_TEXT N_("Use float32 output")
156 #define FLOAT_LONGTEXT N_( \
157     "The option allows you to enable or disable the high-quality float32 " \
158     "audio output mode (which is not well supported by some soundcards)." )
159 #define DEVICE_TEXT N_("Select Audio Device")
160 #define DEVICE_LONG N_("Select special Audio device, or let windows "\
161                        "decide (default), change needs VLC restart "\
162                        "to apply.")
163 #define DEFAULT_AUDIO_DEVICE N_("Default Audio Device")
164
165 vlc_module_begin();
166     set_shortname( "WaveOut" );
167     set_description( N_("Win32 waveOut extension output") );
168     set_capability( "audio output", 50 );
169     set_category( CAT_AUDIO );
170     set_subcategory( SUBCAT_AUDIO_AOUT );
171     add_bool( "waveout-float32", 1, 0, FLOAT_TEXT, FLOAT_LONGTEXT, true );
172
173     add_string( "waveout-dev", "wavemapper", NULL,
174                  DEVICE_TEXT, DEVICE_LONG, false );
175        change_string_list( ppsz_adev, ppsz_adev_text, ReloadWaveoutDevices );
176        change_need_restart();
177        change_action_add( ReloadWaveoutDevices, N_("Refresh list") );
178
179
180     set_callbacks( Open, Close );
181 vlc_module_end();
182
183 /*****************************************************************************
184  * aout_sys_t: waveOut audio output method descriptor
185  *****************************************************************************
186  * This structure is part of the audio output thread descriptor.
187  * It describes the waveOut specific properties of an audio device.
188  *****************************************************************************/
189 struct aout_sys_t
190 {
191     uint32_t i_wave_device_id;               /* ID of selected output device */
192
193     HWAVEOUT h_waveout;                        /* handle to waveout instance */
194
195     WAVEFORMATEXTENSIBLE waveformat;                         /* audio format */
196
197     WAVEHDR waveheader[FRAMES_NUM];
198
199     notification_thread_t *p_notif;                      /* WaveOutThread id */
200     HANDLE event;
201     HANDLE new_buffer_event;
202
203     // rental from alsa.c to synchronize startup of audiothread
204     int b_playing;                                         /* playing status */
205     mtime_t start_date;
206
207     int i_repeat_counter;
208
209     int i_buffer_size;
210
211     uint8_t *p_silence_buffer;              /* buffer we use to play silence */
212
213     bool b_chan_reorder;              /* do we need channel reordering */
214     int pi_chan_table[AOUT_CHAN_MAX];
215 };
216
217 static const uint32_t pi_channels_src[] =
218     { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT,
219       AOUT_CHAN_MIDDLELEFT, AOUT_CHAN_MIDDLERIGHT,
220       AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT,
221       AOUT_CHAN_CENTER, AOUT_CHAN_LFE, 0 };
222 static const uint32_t pi_channels_in[] =
223     { SPEAKER_FRONT_LEFT, SPEAKER_FRONT_RIGHT,
224       SPEAKER_SIDE_LEFT, SPEAKER_SIDE_RIGHT,
225       SPEAKER_BACK_LEFT, SPEAKER_BACK_RIGHT,
226       SPEAKER_FRONT_CENTER, SPEAKER_LOW_FREQUENCY, 0 };
227 static const uint32_t pi_channels_out[] =
228     { SPEAKER_FRONT_LEFT, SPEAKER_FRONT_RIGHT,
229       SPEAKER_FRONT_CENTER, SPEAKER_LOW_FREQUENCY,
230       SPEAKER_BACK_LEFT, SPEAKER_BACK_RIGHT,
231       SPEAKER_SIDE_LEFT, SPEAKER_SIDE_RIGHT, 0 };
232
233 /*****************************************************************************
234  * Open: open the audio device
235  *****************************************************************************
236  * This function opens and setups Win32 waveOut
237  *****************************************************************************/
238 static int Open( vlc_object_t *p_this )
239 {
240     aout_instance_t *p_aout = (aout_instance_t *)p_this;
241     vlc_value_t val;
242     int i;
243
244     /* Allocate structure */
245     p_aout->output.p_sys = malloc( sizeof( aout_sys_t ) );
246
247     if( p_aout->output.p_sys == NULL )
248     {
249         msg_Err( p_aout, "out of memory" );
250         return VLC_EGENERIC;
251     }
252
253     p_aout->output.pf_play = Play;
254     p_aout->b_die = false;
255
256
257     /*
258      initialize/update Device selection List
259     */
260     ReloadWaveoutDevices( p_this, "waveout-dev", val, val, NULL);
261
262
263     /*
264       check for configured audio device!
265     */
266     char *psz_waveout_dev = var_CreateGetString( p_aout, "waveout-dev");
267
268     p_aout->output.p_sys->i_wave_device_id =
269          findDeviceID( psz_waveout_dev );
270
271     if(p_aout->output.p_sys->i_wave_device_id == WAVE_MAPPER)
272     {
273        if(psz_waveout_dev &&
274           stricmp(psz_waveout_dev,"wavemapper"))
275        {
276            msg_Warn( p_aout, "configured audio device '%s' not available, "\
277                          "use default instead", psz_waveout_dev );
278        }
279     }
280     free( psz_waveout_dev );
281
282
283     WAVEOUTCAPS waveoutcaps;
284     if(waveOutGetDevCaps( p_aout->output.p_sys->i_wave_device_id,
285                           &waveoutcaps,
286                           sizeof(WAVEOUTCAPS)) == MMSYSERR_NOERROR)
287     {
288       /* log debug some infos about driver, to know who to blame
289          if it doesn't work */
290         msg_Dbg( p_aout, "Drivername: %s", waveoutcaps.szPname);
291         msg_Dbg( p_aout, "Driver Version: %d.%d",
292                           (waveoutcaps.vDriverVersion>>8)&255,
293                           waveoutcaps.vDriverVersion & 255);
294         msg_Dbg( p_aout, "Manufacturer identifier: 0x%x", waveoutcaps.wMid );
295         msg_Dbg( p_aout, "Product identifier: 0x%x", waveoutcaps.wPid );
296     }
297
298
299
300     if( var_Type( p_aout, "audio-device" ) == 0 )
301     {
302         Probe( p_aout );
303     }
304
305     if( var_Get( p_aout, "audio-device", &val ) < 0 )
306     {
307         /* Probe() has failed. */
308         var_Destroy( p_aout, "waveout-device");
309         free( p_aout->output.p_sys );
310         return VLC_EGENERIC;
311     }
312
313
314     /* Open the device */
315     if( val.i_int == AOUT_VAR_SPDIF )
316     {
317         p_aout->output.output.i_format = VLC_FOURCC('s','p','d','i');
318
319         if( OpenWaveOut( p_aout,
320                          p_aout->output.p_sys->i_wave_device_id,
321                          VLC_FOURCC('s','p','d','i'),
322                          p_aout->output.output.i_physical_channels,
323                          aout_FormatNbChannels( &p_aout->output.output ),
324                          p_aout->output.output.i_rate, false )
325             != VLC_SUCCESS )
326         {
327             msg_Err( p_aout, "cannot open waveout audio device" );
328             free( p_aout->output.p_sys );
329             return VLC_EGENERIC;
330         }
331
332         /* Calculate the frame size in bytes */
333         p_aout->output.i_nb_samples = A52_FRAME_NB;
334         p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
335         p_aout->output.output.i_frame_length = A52_FRAME_NB;
336         p_aout->output.p_sys->i_buffer_size =
337             p_aout->output.output.i_bytes_per_frame;
338
339         aout_VolumeNoneInit( p_aout );
340     }
341     else
342     {
343         WAVEOUTCAPS wocaps;
344
345         if( val.i_int == AOUT_VAR_5_1 )
346         {
347             p_aout->output.output.i_physical_channels
348                 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
349                    | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
350                    | AOUT_CHAN_LFE;
351         }
352         else if( val.i_int == AOUT_VAR_2F2R )
353         {
354             p_aout->output.output.i_physical_channels
355                 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
356                    | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
357         }
358         else if( val.i_int == AOUT_VAR_MONO )
359         {
360             p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
361         }
362         else
363         {
364             p_aout->output.output.i_physical_channels
365                 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
366         }
367
368         if( OpenWaveOutPCM( p_aout,
369                             p_aout->output.p_sys->i_wave_device_id,
370                             &p_aout->output.output.i_format,
371                             p_aout->output.output.i_physical_channels,
372                             aout_FormatNbChannels( &p_aout->output.output ),
373                             p_aout->output.output.i_rate, false )
374             != VLC_SUCCESS )
375         {
376             msg_Err( p_aout, "cannot open waveout audio device" );
377             free( p_aout->output.p_sys );
378             return VLC_EGENERIC;
379         }
380
381         /* Calculate the frame size in bytes */
382         p_aout->output.i_nb_samples = FRAME_SIZE;
383         aout_FormatPrepare( &p_aout->output.output );
384         p_aout->output.p_sys->i_buffer_size = FRAME_SIZE *
385             p_aout->output.output.i_bytes_per_frame;
386
387         aout_VolumeSoftInit( p_aout );
388
389         /* Check for hardware volume support */
390         if( waveOutGetDevCaps( (UINT_PTR)p_aout->output.p_sys->h_waveout,
391                                &wocaps, sizeof(wocaps) ) == MMSYSERR_NOERROR &&
392             wocaps.dwSupport & WAVECAPS_VOLUME )
393         {
394             DWORD i_dummy;
395             if( waveOutGetVolume( p_aout->output.p_sys->h_waveout, &i_dummy )
396                 == MMSYSERR_NOERROR )
397             {
398                 p_aout->output.pf_volume_infos = VolumeInfos;
399                 p_aout->output.pf_volume_get = VolumeGet;
400                 p_aout->output.pf_volume_set = VolumeSet;
401             }
402         }
403     }
404
405
406     waveOutReset( p_aout->output.p_sys->h_waveout );
407
408     /* Allocate silence buffer */
409     p_aout->output.p_sys->p_silence_buffer =
410         malloc( p_aout->output.p_sys->i_buffer_size );
411     if( p_aout->output.p_sys->p_silence_buffer == NULL )
412     {
413         free( p_aout->output.p_sys );
414         msg_Err( p_aout, "out of memory" );
415         return 1;
416     }
417     p_aout->output.p_sys->i_repeat_counter = 0;
418
419
420     /* Zero the buffer. WinCE doesn't have calloc(). */
421     memset( p_aout->output.p_sys->p_silence_buffer, 0,
422             p_aout->output.p_sys->i_buffer_size );
423
424     /* Now we need to setup our waveOut play notification structure */
425     p_aout->output.p_sys->p_notif =
426         vlc_object_create( p_aout, sizeof(notification_thread_t) );
427     p_aout->output.p_sys->p_notif->p_aout = p_aout;
428     p_aout->output.p_sys->event = CreateEvent( NULL, FALSE, FALSE, NULL );
429     p_aout->output.p_sys->new_buffer_event = CreateEvent( NULL, FALSE, FALSE, NULL );
430
431     /* define startpoint of playback on first call to play()
432       like alsa does (instead of playing a blank sample) */
433     p_aout->output.p_sys->b_playing = 0;
434     p_aout->output.p_sys->start_date = 0;
435
436
437     /* Then launch the notification thread */
438     if( vlc_thread_create( p_aout->output.p_sys->p_notif,
439                            "waveOut Notification Thread", WaveOutThread,
440                            VLC_THREAD_PRIORITY_OUTPUT, false ) )
441     {
442         msg_Err( p_aout, "cannot create WaveOutThread" );
443     }
444
445     /* We need to kick off the playback in order to have the callback properly
446      * working */
447     for( i = 0; i < FRAMES_NUM; i++ )
448     {
449         p_aout->output.p_sys->waveheader[i].dwFlags = WHDR_DONE;
450         p_aout->output.p_sys->waveheader[i].dwUser = 0;
451     }
452
453     return 0;
454 }
455
456 /*****************************************************************************
457  * Probe: probe the audio device for available formats and channels
458  *****************************************************************************/
459 static void Probe( aout_instance_t * p_aout )
460 {
461     vlc_value_t val, text;
462     int i_format;
463     unsigned int i_physical_channels;
464
465     var_Create( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
466     text.psz_string = _("Audio Device");
467     var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
468
469     /* Test for 5.1 support */
470     i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
471                           AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
472                           AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE;
473     if( p_aout->output.output.i_physical_channels == i_physical_channels )
474     {
475         if( OpenWaveOutPCM( p_aout,
476                             p_aout->output.p_sys->i_wave_device_id,
477                             &i_format,
478                             i_physical_channels, 6,
479                             p_aout->output.output.i_rate, true )
480             == VLC_SUCCESS )
481         {
482             val.i_int = AOUT_VAR_5_1;
483             text.psz_string = (char *)N_("5.1");
484             var_Change( p_aout, "audio-device",
485                         VLC_VAR_ADDCHOICE, &val, &text );
486             msg_Dbg( p_aout, "device supports 5.1 channels" );
487         }
488     }
489
490     /* Test for 2 Front 2 Rear support */
491     i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
492                           AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
493     if( ( p_aout->output.output.i_physical_channels & i_physical_channels )
494         == i_physical_channels )
495     {
496         if( OpenWaveOutPCM( p_aout,
497                             p_aout->output.p_sys->i_wave_device_id,
498                             &i_format,
499                             i_physical_channels, 4,
500                             p_aout->output.output.i_rate, true )
501             == VLC_SUCCESS )
502         {
503             val.i_int = AOUT_VAR_2F2R;
504             text.psz_string = (char *)N_("2 Front 2 Rear");
505             var_Change( p_aout, "audio-device",
506                         VLC_VAR_ADDCHOICE, &val, &text );
507             msg_Dbg( p_aout, "device supports 4 channels" );
508         }
509     }
510
511     /* Test for stereo support */
512     i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
513     if( OpenWaveOutPCM( p_aout,
514                         p_aout->output.p_sys->i_wave_device_id,
515                         &i_format,
516                         i_physical_channels, 2,
517                         p_aout->output.output.i_rate, true )
518         == VLC_SUCCESS )
519     {
520         val.i_int = AOUT_VAR_STEREO;
521         text.psz_string = (char *)N_("Stereo");
522         var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
523         msg_Dbg( p_aout, "device supports 2 channels" );
524     }
525
526     /* Test for mono support */
527     i_physical_channels = AOUT_CHAN_CENTER;
528     if( OpenWaveOutPCM( p_aout,
529                         p_aout->output.p_sys->i_wave_device_id,
530                         &i_format,
531                         i_physical_channels, 1,
532                         p_aout->output.output.i_rate, true )
533         == VLC_SUCCESS )
534     {
535         val.i_int = AOUT_VAR_MONO;
536         text.psz_string = (char *)N_("Mono");
537         var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
538         msg_Dbg( p_aout, "device supports 1 channel" );
539     }
540
541     /* Test for SPDIF support */
542     if ( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
543     {
544         if( OpenWaveOut( p_aout,
545                          p_aout->output.p_sys->i_wave_device_id,
546                          VLC_FOURCC('s','p','d','i'),
547                          p_aout->output.output.i_physical_channels,
548                          aout_FormatNbChannels( &p_aout->output.output ),
549                          p_aout->output.output.i_rate, true )
550             == VLC_SUCCESS )
551         {
552             msg_Dbg( p_aout, "device supports A/52 over S/PDIF" );
553             val.i_int = AOUT_VAR_SPDIF;
554             text.psz_string = (char *)N_("A/52 over S/PDIF");
555             var_Change( p_aout, "audio-device",
556                         VLC_VAR_ADDCHOICE, &val, &text );
557             if( config_GetInt( p_aout, "spdif" ) )
558                 var_Set( p_aout, "audio-device", val );
559         }
560     }
561
562     var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
563     if( val.i_int <= 0 )
564     {
565         /* Probe() has failed. */
566         var_Destroy( p_aout, "audio-device" );
567         return;
568     }
569
570     var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
571
572     val.b_bool = true;
573     var_Set( p_aout, "intf-change", val );
574 }
575
576 /*****************************************************************************
577  * Play: play a sound buffer
578  *****************************************************************************
579  * This doesn't actually play the buffer. This just stores the buffer so it
580  * can be played by the callback thread.
581  *****************************************************************************/
582 static void Play( aout_instance_t *_p_aout )
583 {
584     if( !_p_aout->output.p_sys->b_playing )
585     {
586         _p_aout->output.p_sys->b_playing = 1;
587
588         /* get the playing date of the first aout buffer */
589         _p_aout->output.p_sys->start_date =
590             aout_FifoFirstDate( _p_aout, &_p_aout->output.fifo );
591
592         msg_Dbg( _p_aout, "Wakeup sleeping output thread.");
593
594         /* wake up the audio output thread */
595         SetEvent( _p_aout->output.p_sys->event );
596     } else {
597         SetEvent( _p_aout->output.p_sys->new_buffer_event );
598     }
599 }
600
601 /*****************************************************************************
602  * Close: close the audio device
603  *****************************************************************************/
604 static void Close( vlc_object_t *p_this )
605 {
606     aout_instance_t *p_aout = (aout_instance_t *)p_this;
607     aout_sys_t *p_sys = p_aout->output.p_sys;
608
609     /* Before calling waveOutClose we must reset the device */
610     vlc_object_kill( p_aout );
611
612     /* wake up the audio thread, to recognize that p_aout died */
613     SetEvent( p_sys->event );
614     SetEvent( p_sys->new_buffer_event );
615
616     vlc_thread_join( p_sys->p_notif );
617     vlc_object_release( p_sys->p_notif );
618
619     /*
620       kill the real output then - when the feed thread
621       is surely terminated!
622       old code could be too early in case that "feeding"
623       was running on termination
624
625       at this point now its sure, that there will be no new
626       data send to the driver, and we can cancel the last
627       running playbuffers
628     */
629     MMRESULT result = waveOutReset( p_sys->h_waveout );
630     if(result != MMSYSERR_NOERROR)
631     {
632        msg_Err( p_aout, "waveOutReset failed 0x%x", result );
633        /*
634         now we must wait, that all buffers are played
635         because cancel doesn't work in this case...
636        */
637        if(result == MMSYSERR_NOTSUPPORTED)
638        {
639            /*
640              clear currently played (done) buffers,
641              if returnvalue > 0 (means some buffer still playing)
642              wait for the driver event callback that one buffer
643              is finished with playing, and check again
644              the timeout of 5000ms is just, an emergency exit
645              of this loop, to avoid deadlock in case of other
646              (currently not known bugs, problems, errors cases?)
647            */
648            while(
649                  (WaveOutClearDoneBuffers( p_sys ) > 0)
650                  &&
651                  (WaitForSingleObject( p_sys->event, 5000) == WAIT_OBJECT_0)
652                 )
653            {
654                  msg_Dbg( p_aout, "Wait for waveout device...");
655            }
656        }
657     } else {
658         WaveOutClearDoneBuffers( p_sys );
659     }
660
661     /* now we can Close the device */
662     if( waveOutClose( p_sys->h_waveout ) != MMSYSERR_NOERROR )
663     {
664         msg_Err( p_aout, "waveOutClose failed" );
665     }
666
667     /*
668       because so long, the waveout device is playing, the callback
669       could occur and need the events
670     */
671     CloseHandle( p_sys->event );
672     CloseHandle( p_sys->new_buffer_event);
673
674     free( p_sys->p_silence_buffer );
675     free( p_sys );
676 }
677
678 /*****************************************************************************
679  * OpenWaveOut: open the waveout sound device
680  ****************************************************************************/
681 static int OpenWaveOut( aout_instance_t *p_aout, uint32_t i_device_id, int i_format,
682                         int i_channels, int i_nb_channels, int i_rate,
683                         bool b_probe )
684 {
685     MMRESULT result;
686     unsigned int i;
687
688     /* Set sound format */
689
690 #define waveformat p_aout->output.p_sys->waveformat
691
692     waveformat.dwChannelMask = 0;
693     for( i = 0; i < sizeof(pi_channels_src)/sizeof(uint32_t); i++ )
694     {
695         if( i_channels & pi_channels_src[i] )
696             waveformat.dwChannelMask |= pi_channels_in[i];
697     }
698
699     switch( i_format )
700     {
701     case VLC_FOURCC('s','p','d','i'):
702         i_nb_channels = 2;
703         /* To prevent channel re-ordering */
704         waveformat.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
705         waveformat.Format.wBitsPerSample = 16;
706         waveformat.Samples.wValidBitsPerSample =
707             waveformat.Format.wBitsPerSample;
708         waveformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
709         waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF;
710         break;
711
712     case VLC_FOURCC('f','l','3','2'):
713         waveformat.Format.wBitsPerSample = sizeof(float) * 8;
714         waveformat.Samples.wValidBitsPerSample =
715             waveformat.Format.wBitsPerSample;
716         waveformat.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
717         waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
718         break;
719
720     case VLC_FOURCC('s','1','6','l'):
721         waveformat.Format.wBitsPerSample = 16;
722         waveformat.Samples.wValidBitsPerSample =
723             waveformat.Format.wBitsPerSample;
724         waveformat.Format.wFormatTag = WAVE_FORMAT_PCM;
725         waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_PCM;
726         break;
727     }
728
729     waveformat.Format.nChannels = i_nb_channels;
730     waveformat.Format.nSamplesPerSec = i_rate;
731     waveformat.Format.nBlockAlign =
732         waveformat.Format.wBitsPerSample / 8 * i_nb_channels;
733     waveformat.Format.nAvgBytesPerSec =
734         waveformat.Format.nSamplesPerSec * waveformat.Format.nBlockAlign;
735
736     /* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */
737     if( i_nb_channels <= 2 )
738     {
739         waveformat.Format.cbSize = 0;
740     }
741     else
742     {
743         waveformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
744         waveformat.Format.cbSize =
745             sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
746     }
747
748     if(!b_probe) {
749         msg_Dbg( p_aout, "OpenWaveDevice-ID: %u", i_device_id);
750         msg_Dbg( p_aout,"waveformat.Format.cbSize          = %d",
751                  waveformat.Format.cbSize);
752         msg_Dbg( p_aout,"waveformat.Format.wFormatTag      = %u",
753                  waveformat.Format.wFormatTag);
754         msg_Dbg( p_aout,"waveformat.Format.nChannels       = %u",
755                  waveformat.Format.nChannels);
756         msg_Dbg( p_aout,"waveformat.Format.nSamplesPerSec  = %d",
757                  (int)waveformat.Format.nSamplesPerSec);
758         msg_Dbg( p_aout,"waveformat.Format.nAvgBytesPerSec = %u",
759                  (int)waveformat.Format.nAvgBytesPerSec);
760         msg_Dbg( p_aout,"waveformat.Format.nBlockAlign     = %d",
761                  waveformat.Format.nBlockAlign);
762         msg_Dbg( p_aout,"waveformat.Format.wBitsPerSample  = %d",
763                  waveformat.Format.wBitsPerSample);
764         msg_Dbg( p_aout,"waveformat.Samples.wValidBitsPerSample = %d",
765                  waveformat.Samples.wValidBitsPerSample);
766         msg_Dbg( p_aout,"waveformat.Samples.wSamplesPerBlock = %d",
767                  waveformat.Samples.wSamplesPerBlock);
768         msg_Dbg( p_aout,"waveformat.dwChannelMask          = %lu",
769                  waveformat.dwChannelMask);
770     }
771
772     /* Open the device */
773     result = waveOutOpen( &p_aout->output.p_sys->h_waveout, i_device_id,
774                           (WAVEFORMATEX *)&waveformat,
775                           (DWORD_PTR)WaveOutCallback, (DWORD_PTR)p_aout,
776                           CALLBACK_FUNCTION | (b_probe?WAVE_FORMAT_QUERY:0) );
777     if( result == WAVERR_BADFORMAT )
778     {
779         msg_Warn( p_aout, "waveOutOpen failed WAVERR_BADFORMAT" );
780         return VLC_EGENERIC;
781     }
782     if( result == MMSYSERR_ALLOCATED )
783     {
784         msg_Warn( p_aout, "waveOutOpen failed WAVERR_ALLOCATED" );
785         return VLC_EGENERIC;
786     }
787     if( result != MMSYSERR_NOERROR )
788     {
789         msg_Warn( p_aout, "waveOutOpen failed" );
790         return VLC_EGENERIC;
791     }
792
793     p_aout->output.p_sys->b_chan_reorder =
794         aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
795                                   waveformat.dwChannelMask, i_nb_channels,
796                                   p_aout->output.p_sys->pi_chan_table );
797
798     if( p_aout->output.p_sys->b_chan_reorder )
799     {
800         msg_Dbg( p_aout, "channel reordering needed" );
801     }
802
803     return VLC_SUCCESS;
804
805 #undef waveformat
806
807 }
808
809 /*****************************************************************************
810  * OpenWaveOutPCM: open a PCM waveout sound device
811  ****************************************************************************/
812 static int OpenWaveOutPCM( aout_instance_t *p_aout, uint32_t i_device_id, int *i_format,
813                            int i_channels, int i_nb_channels, int i_rate,
814                            bool b_probe )
815 {
816     bool b_use_float32 = var_CreateGetBool( p_aout, "waveout-float32");
817
818     if( !b_use_float32 || OpenWaveOut( p_aout, i_device_id, VLC_FOURCC('f','l','3','2'),
819                                    i_channels, i_nb_channels, i_rate, b_probe )
820         != VLC_SUCCESS )
821     {
822         if ( OpenWaveOut( p_aout, i_device_id, VLC_FOURCC('s','1','6','l'),
823                           i_channels, i_nb_channels, i_rate, b_probe )
824              != VLC_SUCCESS )
825         {
826             return VLC_EGENERIC;
827         }
828         else
829         {
830             *i_format = VLC_FOURCC('s','1','6','l');
831             return VLC_SUCCESS;
832         }
833     }
834     else
835     {
836         *i_format = VLC_FOURCC('f','l','3','2');
837         return VLC_SUCCESS;
838     }
839 }
840
841 /*****************************************************************************
842  * PlayWaveOut: play a buffer through the WaveOut device
843  *****************************************************************************/
844 static int PlayWaveOut( aout_instance_t *p_aout, HWAVEOUT h_waveout,
845                         WAVEHDR *p_waveheader, aout_buffer_t *p_buffer,
846                         bool b_spdif)
847 {
848     MMRESULT result;
849
850     /* Prepare the buffer */
851     if( p_buffer != NULL )
852     {
853         p_waveheader->lpData = p_buffer->p_buffer;
854         /*
855           copy the buffer to the silence buffer :) so in case we don't
856           get the next buffer fast enough (I will repeat this one a time
857           for AC3 / DTS and SPDIF this will sound better instead of
858           a hickup)
859         */
860         if(b_spdif)
861         {
862            vlc_memcpy( p_aout->output.p_sys->p_silence_buffer,
863                        p_buffer->p_buffer,
864                        p_aout->output.p_sys->i_buffer_size );
865            p_aout->output.p_sys->i_repeat_counter = 2;
866         }
867     } else {
868         /* Use silence buffer instead */
869         if(p_aout->output.p_sys->i_repeat_counter)
870         {
871            p_aout->output.p_sys->i_repeat_counter--;
872            if(!p_aout->output.p_sys->i_repeat_counter)
873            {
874                vlc_memset( p_aout->output.p_sys->p_silence_buffer,
875                            0x00, p_aout->output.p_sys->i_buffer_size );
876            }
877         }
878         p_waveheader->lpData = p_aout->output.p_sys->p_silence_buffer;
879     }
880
881     p_waveheader->dwUser = p_buffer ? (DWORD_PTR)p_buffer : (DWORD_PTR)1;
882     p_waveheader->dwBufferLength = p_aout->output.p_sys->i_buffer_size;
883     p_waveheader->dwFlags = 0;
884
885     result = waveOutPrepareHeader( h_waveout, p_waveheader, sizeof(WAVEHDR) );
886     if( result != MMSYSERR_NOERROR )
887     {
888         msg_Err( p_aout, "waveOutPrepareHeader failed" );
889         return VLC_EGENERIC;
890     }
891
892     /* Send the buffer to the waveOut queue */
893     result = waveOutWrite( h_waveout, p_waveheader, sizeof(WAVEHDR) );
894     if( result != MMSYSERR_NOERROR )
895     {
896         msg_Err( p_aout, "waveOutWrite failed" );
897         return VLC_EGENERIC;
898     }
899
900     return VLC_SUCCESS;
901 }
902
903 /*****************************************************************************
904  * WaveOutCallback: what to do once WaveOut has played its sound samples
905  *****************************************************************************/
906 static void CALLBACK WaveOutCallback( HWAVEOUT h_waveout, UINT uMsg,
907                                       DWORD _p_aout,
908                                       DWORD dwParam1, DWORD dwParam2 )
909 {
910     aout_instance_t *p_aout = (aout_instance_t *)_p_aout;
911     int i, i_queued_frames = 0;
912
913     if( uMsg != WOM_DONE ) return;
914
915     if( p_aout->b_die ) return;
916
917     /* Find out the current latency */
918     for( i = 0; i < FRAMES_NUM; i++ )
919     {
920         /* Check if frame buf is available */
921         if( !(p_aout->output.p_sys->waveheader[i].dwFlags & WHDR_DONE) )
922         {
923             i_queued_frames++;
924         }
925     }
926
927     /* Don't wake up the thread too much */
928     if( i_queued_frames <= FRAMES_NUM/2 )
929         SetEvent( p_aout->output.p_sys->event );
930 }
931
932
933 /****************************************************************************
934  * WaveOutClearDoneBuffers: Clear all done marked buffers, and free aout_bufer
935  ****************************************************************************
936  * return value is the number of still playing buffers in the queue
937  ****************************************************************************/
938 static int WaveOutClearDoneBuffers(aout_sys_t *p_sys)
939 {
940     WAVEHDR *p_waveheader = p_sys->waveheader;
941     int i_queued_frames = 0;
942
943     for( int i = 0; i < FRAMES_NUM; i++ )
944     {
945         if( (p_waveheader[i].dwFlags & WHDR_DONE) &&
946             p_waveheader[i].dwUser )
947         {
948             aout_buffer_t *p_buffer =
949                     (aout_buffer_t *)(p_waveheader[i].dwUser);
950             /* Unprepare and free the buffers which has just been played */
951             waveOutUnprepareHeader( p_sys->h_waveout, &p_waveheader[i],
952                                     sizeof(WAVEHDR) );
953
954             if( p_waveheader[i].dwUser != 1 )
955                 aout_BufferFree( p_buffer );
956
957             p_waveheader[i].dwUser = 0;
958         }
959
960         /* Check if frame buf is available */
961         if( !(p_waveheader[i].dwFlags & WHDR_DONE) )
962         {
963             i_queued_frames++;
964         }
965     }
966     return i_queued_frames;
967 }
968
969 /*****************************************************************************
970  * WaveOutThread: this thread will capture play notification events.
971  *****************************************************************************
972  * We use this thread to feed new audio samples to the sound card because
973  * we are not authorized to use waveOutWrite() directly in the waveout
974  * callback.
975  *****************************************************************************/
976 static void WaveOutThread( notification_thread_t *p_notif )
977 {
978     aout_instance_t *p_aout = p_notif->p_aout;
979     aout_sys_t *p_sys = p_aout->output.p_sys;
980     aout_buffer_t *p_buffer = NULL;
981     WAVEHDR *p_waveheader = p_sys->waveheader;
982     int i, i_queued_frames;
983     bool b_sleek;
984     mtime_t next_date;
985     uint32_t i_buffer_length = 64;
986
987     /* We don't want any resampling when using S/PDIF */
988     b_sleek = p_aout->output.output.i_format == VLC_FOURCC('s','p','d','i');
989
990     // wait for first call to "play()"
991     while( !p_sys->start_date && !p_aout->b_die )
992            WaitForSingleObject( p_sys->event, INFINITE );
993     if( p_aout->b_die )
994         return;
995
996     msg_Dbg( p_aout, "will start to play in %"PRId64" us",
997              (p_sys->start_date - AOUT_PTS_TOLERANCE/4)-mdate());
998
999     // than wait a short time... before grabbing first frames
1000     mwait( p_sys->start_date - AOUT_PTS_TOLERANCE/4 );
1001
1002 #define waveout_warn(msg) msg_Warn( p_aout, "aout_OutputNextBuffer no buffer "\
1003                            "got next_date=%d ms, "\
1004                            "%d frames to play, "\
1005                            "starving? %d, %s",(int)(next_date/(mtime_t)1000), \
1006                            i_queued_frames, \
1007                            p_aout->output.b_starving, msg);
1008     next_date = mdate();
1009
1010     while( !p_aout->b_die )
1011     {
1012         /* Cleanup and find out the current latency */
1013         i_queued_frames = WaveOutClearDoneBuffers( p_sys );
1014
1015         if( p_aout->b_die ) return;
1016
1017         /* Try to fill in as many frame buffers as possible */
1018         for( i = 0; i < FRAMES_NUM; i++ )
1019         {
1020             /* Check if frame buf is available */
1021             if( p_waveheader[i].dwFlags & WHDR_DONE )
1022             {
1023                 // next_date = mdate() + 1000000 * i_queued_frames /
1024                 //  p_aout->output.output.i_rate * p_aout->output.i_nb_samples;
1025
1026                 // the realtime has got our back-site:) to come in sync
1027                 if(next_date < mdate())
1028                    next_date = mdate();
1029
1030
1031                 /* Take into account the latency */
1032                 p_buffer = aout_OutputNextBuffer( p_aout,
1033                     next_date,
1034                     b_sleek );
1035
1036                 if(!p_buffer)
1037                 {
1038 #if 0
1039                     msg_Dbg( p_aout, "aout_OutputNextBuffer no buffer "\
1040                                       "got next_date=%d ms, "\
1041                                       "%d frames to play, "\
1042                                       "starving? %d",(int)(next_date/(mtime_t)1000),
1043                                                      i_queued_frames,
1044                                                      p_aout->output.b_starving);
1045 #endif
1046                     if(p_aout->output.b_starving)
1047                     {
1048                         // means we are too early to request a new buffer?
1049                         waveout_warn("waiting...")
1050                         next_date = aout_FifoFirstDate( p_aout, &p_aout->output.fifo );
1051                         mwait( next_date - AOUT_PTS_TOLERANCE/4 );
1052                         next_date = mdate();
1053                         p_buffer = aout_OutputNextBuffer( p_aout,
1054                                      next_date,
1055                                      b_sleek
1056                                    );
1057                     }
1058                 }
1059
1060                 if( !p_buffer && i_queued_frames )
1061                 {
1062                     /* We aren't late so no need to play a blank sample */
1063                     break;
1064                 }
1065
1066                 if( p_buffer )
1067                 {
1068                     mtime_t buffer_length = (p_buffer->end_date
1069                                              - p_buffer->start_date);
1070                     next_date = next_date + buffer_length;
1071                     i_buffer_length = buffer_length/1000;
1072                 }
1073
1074                 /* Do the channel reordering */
1075                 if( p_buffer && p_sys->b_chan_reorder )
1076                 {
1077                     aout_ChannelReorder( p_buffer->p_buffer,
1078                         p_buffer->i_nb_bytes,
1079                         p_sys->waveformat.Format.nChannels,
1080                         p_sys->pi_chan_table,
1081                         p_sys->waveformat.Format.wBitsPerSample );
1082                 }
1083
1084                 PlayWaveOut( p_aout, p_sys->h_waveout,
1085                              &p_waveheader[i], p_buffer, b_sleek );
1086
1087                 i_queued_frames++;
1088             }
1089         }
1090
1091         if( p_aout->b_die ) return;
1092
1093         /*
1094           deal with the case that the loop didn't fillup the buffer to the
1095           max - instead of waiting that half the buffer is played before
1096           fillup the waveout buffers, wait only for the next sample buffer
1097           to arrive at the play method...
1098
1099           this will also avoid, that the last buffer is play until the
1100           end, and then trying to get more data, so it will also
1101           work - if the next buffer will arrive some ms before the
1102           last buffer is finished.
1103         */
1104         if(i_queued_frames < FRAMES_NUM)
1105            WaitForSingleObject( p_sys->new_buffer_event, INFINITE );
1106         else
1107            WaitForSingleObject( p_sys->event, INFINITE );
1108
1109     }
1110
1111 #undef waveout_warn
1112 }
1113
1114 static int VolumeInfos( aout_instance_t * p_aout, audio_volume_t * pi_soft )
1115 {
1116     *pi_soft = AOUT_VOLUME_MAX / 2;
1117     return 0;
1118 }
1119
1120 static int VolumeGet( aout_instance_t * p_aout, audio_volume_t * pi_volume )
1121 {
1122     DWORD i_waveout_vol;
1123
1124 #ifdef UNDER_CE
1125     waveOutGetVolume( 0, &i_waveout_vol );
1126 #else
1127     waveOutGetVolume( p_aout->output.p_sys->h_waveout, &i_waveout_vol );
1128 #endif
1129
1130     i_waveout_vol &= 0xFFFF;
1131     *pi_volume = p_aout->output.i_volume =
1132         (i_waveout_vol * AOUT_VOLUME_MAX + 0xFFFF /*rounding*/) / 2 / 0xFFFF;
1133     return 0;
1134 }
1135
1136 static int VolumeSet( aout_instance_t * p_aout, audio_volume_t i_volume )
1137 {
1138     unsigned long i_waveout_vol = i_volume * 0xFFFF * 2 / AOUT_VOLUME_MAX;
1139     i_waveout_vol |= (i_waveout_vol << 16);
1140
1141 #ifdef UNDER_CE
1142     waveOutSetVolume( 0, i_waveout_vol );
1143 #else
1144     waveOutSetVolume( p_aout->output.p_sys->h_waveout, i_waveout_vol );
1145 #endif
1146
1147     p_aout->output.i_volume = i_volume;
1148     return 0;
1149 }
1150
1151
1152 /*
1153   reload the configuration drop down list, of the Audio Devices
1154 */
1155 static int ReloadWaveoutDevices( vlc_object_t *p_this, char const *psz_name,
1156                                  vlc_value_t newval, vlc_value_t oldval, void *data )
1157 {
1158     int i;
1159
1160     module_config_t *p_item = config_FindConfig( p_this, psz_name );
1161     if( !p_item ) return VLC_SUCCESS;
1162
1163     /* Clear-up the current list */
1164     if( p_item->i_list )
1165     {
1166         /* Keep the first entry */
1167         for( i = 1; i < p_item->i_list; i++ )
1168         {
1169             free((char *)(p_item->ppsz_list[i]) );
1170             free((char *)(p_item->ppsz_list_text[i]) );
1171         }
1172         /* TODO: Remove when no more needed */
1173         p_item->ppsz_list[i] = NULL;
1174         p_item->ppsz_list_text[i] = NULL;
1175     }
1176     p_item->i_list = 1;
1177
1178     int wave_devices = waveOutGetNumDevs();
1179
1180     p_item->ppsz_list =
1181         (char **)realloc( p_item->ppsz_list,
1182                           (wave_devices+2) * sizeof(char *) );
1183     p_item->ppsz_list_text =
1184         (char **)realloc( p_item->ppsz_list_text,
1185                           (wave_devices+2) * sizeof(char *) );
1186
1187     WAVEOUTCAPS caps;
1188     char sz_dev_name[MAXPNAMELEN+32];
1189     int j=1;
1190     for(int i=0; i<wave_devices; i++)
1191     {
1192         if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
1193            == MMSYSERR_NOERROR)
1194         {
1195           sprintf( sz_dev_name, psz_device_name_fmt, caps.szPname,
1196                                                caps.wMid,
1197                                                caps.wPid
1198                                               );
1199           p_item->ppsz_list[j] = FromLocaleDup( sz_dev_name );
1200           p_item->ppsz_list_text[j] = FromLocaleDup( sz_dev_name );
1201           p_item->i_list++;
1202           j++;
1203         }
1204
1205     }
1206     p_item->ppsz_list[j] = NULL;
1207     p_item->ppsz_list_text[j] = NULL;
1208
1209     /* Signal change to the interface */
1210     p_item->b_dirty = true;
1211
1212     return VLC_SUCCESS;
1213 }
1214
1215 /*
1216   convert devicename to device ID for output
1217   if device not found return WAVE_MAPPER, so let
1218   windows decide which preferred audio device
1219   should be used.
1220 */
1221 static uint32_t findDeviceID(char *psz_device_name)
1222 {
1223     if(!psz_device_name)
1224        return WAVE_MAPPER;
1225
1226     uint32_t wave_devices = waveOutGetNumDevs();
1227     WAVEOUTCAPS caps;
1228     char sz_dev_name[MAXPNAMELEN+32];
1229     for(uint32_t i=0; i<wave_devices; i++)
1230     {
1231         if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
1232            == MMSYSERR_NOERROR)
1233         {
1234             sprintf(sz_dev_name, psz_device_name_fmt, caps.szPname,
1235                                                caps.wMid,
1236                                                caps.wPid
1237                                               );
1238             char *psz_temp = FromLocaleDup(sz_dev_name);
1239
1240             if( !stricmp(psz_temp, psz_device_name) )
1241             {
1242                 LocaleFree( psz_temp );
1243                 return i;
1244             }
1245             LocaleFree( psz_temp );
1246         }
1247     }
1248
1249     return WAVE_MAPPER;
1250 }