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