Various spelling fixes.
[vlc.git] / 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_aout.h>
34 #include <vlc_charset.h>
35
36 #include <windows.h>
37 #include <mmsystem.h>
38
39 #define FRAME_SIZE 4096              /* The size is in samples, not in bytes */
40 #define FRAMES_NUM 8
41
42 /*****************************************************************************
43  * Useful macros
44  *****************************************************************************/
45 #ifdef UNDER_CE
46 #   define DWORD_PTR DWORD
47 #   ifdef waveOutGetDevCaps
48 #       undef waveOutGetDevCaps
49         MMRESULT WINAPI waveOutGetDevCaps(UINT, LPWAVEOUTCAPS, UINT);
50 #   endif
51 #endif
52
53 #ifndef WAVE_FORMAT_IEEE_FLOAT
54 #   define WAVE_FORMAT_IEEE_FLOAT 0x0003
55 #endif
56
57 #ifndef WAVE_FORMAT_DOLBY_AC3_SPDIF
58 #   define WAVE_FORMAT_DOLBY_AC3_SPDIF 0x0092
59 #endif
60
61 #ifndef WAVE_FORMAT_EXTENSIBLE
62 #define  WAVE_FORMAT_EXTENSIBLE   0xFFFE
63 #endif
64
65 #ifndef SPEAKER_FRONT_LEFT
66 #   define SPEAKER_FRONT_LEFT             0x1
67 #   define SPEAKER_FRONT_RIGHT            0x2
68 #   define SPEAKER_FRONT_CENTER           0x4
69 #   define SPEAKER_LOW_FREQUENCY          0x8
70 #   define SPEAKER_BACK_LEFT              0x10
71 #   define SPEAKER_BACK_RIGHT             0x20
72 #   define SPEAKER_FRONT_LEFT_OF_CENTER   0x40
73 #   define SPEAKER_FRONT_RIGHT_OF_CENTER  0x80
74 #   define SPEAKER_BACK_CENTER            0x100
75 #   define SPEAKER_SIDE_LEFT              0x200
76 #   define SPEAKER_SIDE_RIGHT             0x400
77 #   define SPEAKER_TOP_CENTER             0x800
78 #   define SPEAKER_TOP_FRONT_LEFT         0x1000
79 #   define SPEAKER_TOP_FRONT_CENTER       0x2000
80 #   define SPEAKER_TOP_FRONT_RIGHT        0x4000
81 #   define SPEAKER_TOP_BACK_LEFT          0x8000
82 #   define SPEAKER_TOP_BACK_CENTER        0x10000
83 #   define SPEAKER_TOP_BACK_RIGHT         0x20000
84 #   define SPEAKER_RESERVED               0x80000000
85 #endif
86
87 #ifndef _WAVEFORMATEXTENSIBLE_
88 typedef struct {
89     WAVEFORMATEX    Format;
90     union {
91         WORD wValidBitsPerSample;       /* bits of precision  */
92         WORD wSamplesPerBlock;          /* valid if wBitsPerSample==0 */
93         WORD wReserved;                 /* If neither applies, set to zero. */
94     } Samples;
95     DWORD           dwChannelMask;      /* which channels are */
96                                         /* present in stream  */
97     GUID            SubFormat;
98 } WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE;
99 #endif
100
101 static const GUID __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = {WAVE_FORMAT_IEEE_FLOAT, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
102 static const GUID __KSDATAFORMAT_SUBTYPE_PCM = {WAVE_FORMAT_PCM, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
103 static const GUID __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF = {WAVE_FORMAT_DOLBY_AC3_SPDIF, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
104
105 /*****************************************************************************
106  * Local prototypes
107  *****************************************************************************/
108 static int  Open         ( vlc_object_t * );
109 static void Close        ( vlc_object_t * );
110 static void Play         ( aout_instance_t * );
111
112 /*****************************************************************************
113  * notification_thread_t: waveOut event thread
114  *****************************************************************************/
115 typedef struct notification_thread_t
116 {
117     VLC_COMMON_MEMBERS
118     aout_instance_t *p_aout;
119
120 } notification_thread_t;
121
122 /* local functions */
123 static void Probe        ( aout_instance_t * );
124 static int OpenWaveOut   ( aout_instance_t *, uint32_t,
125                            int, int, int, int, vlc_bool_t );
126 static int OpenWaveOutPCM( aout_instance_t *, uint32_t,
127                            int*, int, int, int, vlc_bool_t );
128 static int PlayWaveOut   ( aout_instance_t *, HWAVEOUT, WAVEHDR *,
129                            aout_buffer_t *, vlc_bool_t );
130
131 static void CALLBACK WaveOutCallback ( HWAVEOUT, UINT, DWORD, DWORD, DWORD );
132 static void WaveOutThread( notification_thread_t * );
133
134 static int VolumeInfos( aout_instance_t *, audio_volume_t * );
135 static int VolumeGet( aout_instance_t *, audio_volume_t * );
136 static int VolumeSet( aout_instance_t *, audio_volume_t );
137
138 static int WaveOutClearDoneBuffers(aout_sys_t *p_sys);
139
140 static int ReloadWaveoutDevices( vlc_object_t *, char const *,
141                                 vlc_value_t, vlc_value_t, void * );
142 static uint32_t findDeviceID(char *);
143
144 static const char psz_device_name_fmt[] = "%s ($%x,$%x)";
145
146 static const char *ppsz_adev[] = { "wavemapper", };
147 static const char *ppsz_adev_text[] = { N_("Microsoft Soundmapper") };
148
149
150
151 /*****************************************************************************
152  * Module descriptor
153  *****************************************************************************/
154 #define FLOAT_TEXT N_("Use float32 output")
155 #define FLOAT_LONGTEXT N_( \
156     "The option allows you to enable or disable the high-quality float32 " \
157     "audio output mode (which is not well supported by some soundcards)." )
158 #define DEVICE_TEXT N_("Select Audio Device")
159 #define DEVICE_LONG N_("Select special Audio device, or let windows "\
160                        "decide (default), change needs VLC restart "\
161                        "to apply.")
162 #define DEFAULT_AUDIO_DEVICE N_("Default Audio Device")
163
164 vlc_module_begin();
165     set_shortname( "WaveOut" );
166     set_description( _("Win32 waveOut extension output") );
167     set_capability( "audio output", 50 );
168     set_category( CAT_AUDIO );
169     set_subcategory( SUBCAT_AUDIO_AOUT );
170     add_bool( "waveout-float32", 1, 0, FLOAT_TEXT, FLOAT_LONGTEXT, VLC_TRUE );
171
172     add_string( "waveout-dev", "wavemapper", NULL,
173                  DEVICE_TEXT, DEVICE_LONG, VLC_FALSE );
174        change_string_list( ppsz_adev, ppsz_adev_text, ReloadWaveoutDevices );
175        change_need_restart();
176        change_action_add( ReloadWaveoutDevices, N_("Refresh list") );
177
178
179     set_callbacks( Open, Close );
180 vlc_module_end();
181
182 /*****************************************************************************
183  * aout_sys_t: waveOut audio output method descriptor
184  *****************************************************************************
185  * This structure is part of the audio output thread descriptor.
186  * It describes the waveOut specific properties of an audio device.
187  *****************************************************************************/
188 struct aout_sys_t
189 {
190     uint32_t i_wave_device_id;               /* ID of selected output device */
191
192     HWAVEOUT h_waveout;                        /* handle to waveout instance */
193
194     WAVEFORMATEXTENSIBLE waveformat;                         /* audio format */
195
196     WAVEHDR waveheader[FRAMES_NUM];
197
198     notification_thread_t *p_notif;                      /* WaveOutThread id */
199     HANDLE event;
200     HANDLE new_buffer_event;
201
202     // rental from alsa.c to synchronize startup of audiothread
203     int b_playing;                                         /* playing status */
204     mtime_t start_date;
205
206     int i_repeat_counter;
207
208     int i_buffer_size;
209
210     byte_t *p_silence_buffer;               /* buffer we use to play silence */
211
212     vlc_bool_t b_chan_reorder;              /* do we need channel reordering */
213     int pi_chan_table[AOUT_CHAN_MAX];
214 };
215
216 static const uint32_t pi_channels_src[] =
217     { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT,
218       AOUT_CHAN_MIDDLELEFT, AOUT_CHAN_MIDDLERIGHT,
219       AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT,
220       AOUT_CHAN_CENTER, AOUT_CHAN_LFE, 0 };
221 static const uint32_t pi_channels_in[] =
222     { SPEAKER_FRONT_LEFT, SPEAKER_FRONT_RIGHT,
223       SPEAKER_SIDE_LEFT, SPEAKER_SIDE_RIGHT,
224       SPEAKER_BACK_LEFT, SPEAKER_BACK_RIGHT,
225       SPEAKER_FRONT_CENTER, SPEAKER_LOW_FREQUENCY, 0 };
226 static const uint32_t pi_channels_out[] =
227     { SPEAKER_FRONT_LEFT, SPEAKER_FRONT_RIGHT,
228       SPEAKER_FRONT_CENTER, SPEAKER_LOW_FREQUENCY,
229       SPEAKER_BACK_LEFT, SPEAKER_BACK_RIGHT,
230       SPEAKER_SIDE_LEFT, SPEAKER_SIDE_RIGHT, 0 };
231
232 /*****************************************************************************
233  * Open: open the audio device
234  *****************************************************************************
235  * This function opens and setups Win32 waveOut
236  *****************************************************************************/
237 static int Open( vlc_object_t *p_this )
238 {
239     aout_instance_t *p_aout = (aout_instance_t *)p_this;
240     vlc_value_t val;
241     int i;
242
243     /* Allocate structure */
244     p_aout->output.p_sys = malloc( sizeof( aout_sys_t ) );
245
246     if( p_aout->output.p_sys == NULL )
247     {
248         msg_Err( p_aout, "out of memory" );
249         return VLC_EGENERIC;
250     }
251
252     p_aout->output.pf_play = Play;
253     p_aout->b_die = VLC_FALSE;
254
255
256     /*
257      initialize/update Device selection List
258     */
259     ReloadWaveoutDevices( p_this, "waveout-dev", val, val, NULL);
260
261
262     /*
263       check for configured audio device!
264     */
265     char *psz_waveout_dev = var_CreateGetString( p_aout, "waveout-dev");
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-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, VLC_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, VLC_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         msg_Err( p_aout, "out of memory" );
414         return 1;
415     }
416     p_aout->output.p_sys->i_repeat_counter = 0;
417
418
419     /* Zero the buffer. WinCE doesn't have calloc(). */
420     memset( p_aout->output.p_sys->p_silence_buffer, 0,
421             p_aout->output.p_sys->i_buffer_size );
422
423     /* Now we need to setup our waveOut play notification structure */
424     p_aout->output.p_sys->p_notif =
425         vlc_object_create( p_aout, sizeof(notification_thread_t) );
426     p_aout->output.p_sys->p_notif->p_aout = p_aout;
427     p_aout->output.p_sys->event = CreateEvent( NULL, FALSE, FALSE, NULL );
428     p_aout->output.p_sys->new_buffer_event = CreateEvent( NULL, FALSE, FALSE, NULL );
429
430     /* define startpoint of playback on first call to play()
431       like alsa does (instead of playing a blank sample) */
432     p_aout->output.p_sys->b_playing = 0;
433     p_aout->output.p_sys->start_date = 0;
434
435
436     /* Then launch the notification thread */
437     if( vlc_thread_create( p_aout->output.p_sys->p_notif,
438                            "waveOut Notification Thread", WaveOutThread,
439                            VLC_THREAD_PRIORITY_OUTPUT, VLC_FALSE ) )
440     {
441         msg_Err( p_aout, "cannot create WaveOutThread" );
442     }
443
444     /* We need to kick off the playback in order to have the callback properly
445      * working */
446     for( i = 0; i < FRAMES_NUM; i++ )
447     {
448         p_aout->output.p_sys->waveheader[i].dwFlags = WHDR_DONE;
449         p_aout->output.p_sys->waveheader[i].dwUser = 0;
450     }
451
452     return 0;
453 }
454
455 /*****************************************************************************
456  * Probe: probe the audio device for available formats and channels
457  *****************************************************************************/
458 static void Probe( aout_instance_t * p_aout )
459 {
460     vlc_value_t val, text;
461     int i_format;
462     unsigned int i_physical_channels;
463
464     var_Create( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
465     text.psz_string = _("Audio Device");
466     var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
467
468     /* Test for 5.1 support */
469     i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
470                           AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
471                           AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE;
472     if( p_aout->output.output.i_physical_channels == i_physical_channels )
473     {
474         if( OpenWaveOutPCM( p_aout,
475                             p_aout->output.p_sys->i_wave_device_id,
476                             &i_format,
477                             i_physical_channels, 6,
478                             p_aout->output.output.i_rate, VLC_TRUE )
479             == VLC_SUCCESS )
480         {
481             val.i_int = AOUT_VAR_5_1;
482             text.psz_string = (char *)N_("5.1");
483             var_Change( p_aout, "audio-device",
484                         VLC_VAR_ADDCHOICE, &val, &text );
485             msg_Dbg( p_aout, "device supports 5.1 channels" );
486         }
487     }
488
489     /* Test for 2 Front 2 Rear support */
490     i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
491                           AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
492     if( ( p_aout->output.output.i_physical_channels & i_physical_channels )
493         == i_physical_channels )
494     {
495         if( OpenWaveOutPCM( p_aout,
496                             p_aout->output.p_sys->i_wave_device_id,
497                             &i_format,
498                             i_physical_channels, 4,
499                             p_aout->output.output.i_rate, VLC_TRUE )
500             == VLC_SUCCESS )
501         {
502             val.i_int = AOUT_VAR_2F2R;
503             text.psz_string = (char *)N_("2 Front 2 Rear");
504             var_Change( p_aout, "audio-device",
505                         VLC_VAR_ADDCHOICE, &val, &text );
506             msg_Dbg( p_aout, "device supports 4 channels" );
507         }
508     }
509
510     /* Test for stereo support */
511     i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
512     if( OpenWaveOutPCM( p_aout,
513                         p_aout->output.p_sys->i_wave_device_id,
514                         &i_format,
515                         i_physical_channels, 2,
516                         p_aout->output.output.i_rate, VLC_TRUE )
517         == VLC_SUCCESS )
518     {
519         val.i_int = AOUT_VAR_STEREO;
520         text.psz_string = (char *)N_("Stereo");
521         var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
522         msg_Dbg( p_aout, "device supports 2 channels" );
523     }
524
525     /* Test for mono support */
526     i_physical_channels = AOUT_CHAN_CENTER;
527     if( OpenWaveOutPCM( p_aout,
528                         p_aout->output.p_sys->i_wave_device_id,
529                         &i_format,
530                         i_physical_channels, 1,
531                         p_aout->output.output.i_rate, VLC_TRUE )
532         == VLC_SUCCESS )
533     {
534         val.i_int = AOUT_VAR_MONO;
535         text.psz_string = (char *)N_("Mono");
536         var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
537         msg_Dbg( p_aout, "device supports 1 channel" );
538     }
539
540     /* Test for SPDIF support */
541     if ( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
542     {
543         if( OpenWaveOut( p_aout,
544                          p_aout->output.p_sys->i_wave_device_id,
545                          VLC_FOURCC('s','p','d','i'),
546                          p_aout->output.output.i_physical_channels,
547                          aout_FormatNbChannels( &p_aout->output.output ),
548                          p_aout->output.output.i_rate, VLC_TRUE )
549             == VLC_SUCCESS )
550         {
551             msg_Dbg( p_aout, "device supports A/52 over S/PDIF" );
552             val.i_int = AOUT_VAR_SPDIF;
553             text.psz_string = (char *)N_("A/52 over S/PDIF");
554             var_Change( p_aout, "audio-device",
555                         VLC_VAR_ADDCHOICE, &val, &text );
556             if( config_GetInt( p_aout, "spdif" ) )
557                 var_Set( p_aout, "audio-device", val );
558         }
559     }
560
561     var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
562     if( val.i_int <= 0 )
563     {
564         /* Probe() has failed. */
565         var_Destroy( p_aout, "audio-device" );
566         return;
567     }
568
569     var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
570
571     val.b_bool = VLC_TRUE;
572     var_Set( p_aout, "intf-change", val );
573 }
574
575 /*****************************************************************************
576  * Play: play a sound buffer
577  *****************************************************************************
578  * This doesn't actually play the buffer. This just stores the buffer so it
579  * can be played by the callback thread.
580  *****************************************************************************/
581 static void Play( aout_instance_t *_p_aout )
582 {
583     if( !_p_aout->output.p_sys->b_playing )
584     {
585         _p_aout->output.p_sys->b_playing = 1;
586
587         /* get the playing date of the first aout buffer */
588         _p_aout->output.p_sys->start_date =
589             aout_FifoFirstDate( _p_aout, &_p_aout->output.fifo );
590
591         msg_Dbg( _p_aout, "Wakeup sleeping output thread.");
592
593         /* wake up the audio output thread */
594         SetEvent( _p_aout->output.p_sys->event );
595     } else {
596         SetEvent( _p_aout->output.p_sys->new_buffer_event );
597     }
598 }
599
600 /*****************************************************************************
601  * Close: close the audio device
602  *****************************************************************************/
603 static void Close( vlc_object_t *p_this )
604 {
605     aout_instance_t *p_aout = (aout_instance_t *)p_this;
606     aout_sys_t *p_sys = p_aout->output.p_sys;
607
608     /* Before calling waveOutClose we must reset the device */
609     vlc_object_kill( p_aout );
610
611     /* wake up the audio thread, to recognize that p_aout died */
612     SetEvent( p_sys->event );
613     SetEvent( p_sys->new_buffer_event );
614
615     vlc_thread_join( p_sys->p_notif );
616     vlc_object_release( p_sys->p_notif );
617
618     /*
619       kill the real output then - when the feed thread
620       is surely terminated!
621       old code could be too early in case that "feeding"
622       was running on termination
623
624       at this point now its sure, that there will be no new
625       data send to the driver, and we can cancel the last
626       running playbuffers
627     */
628     MMRESULT result = waveOutReset( p_sys->h_waveout );
629     if(result != MMSYSERR_NOERROR)
630     {
631        msg_Err( p_aout, "waveOutReset failed 0x%x", result );
632        /*
633         now we must wait, that all buffers are played
634         because cancel doesn't work in this case...
635        */
636        if(result == MMSYSERR_NOTSUPPORTED)
637        {
638            /*
639              clear currently played (done) buffers,
640              if returnvalue > 0 (means some buffer still playing)
641              wait for the driver event callback that one buffer
642              is finished with playing, and check again
643              the timeout of 5000ms is just, an emergency exit
644              of this loop, to avoid deadlock in case of other
645              (currently not known bugs, problems, errors cases?)
646            */
647            while(
648                  (WaveOutClearDoneBuffers( p_sys ) > 0)
649                  &&
650                  (WaitForSingleObject( p_sys->event, 5000) == WAIT_OBJECT_0)
651                 )
652            {
653                  msg_Dbg( p_aout, "Wait for waveout device...");
654            }
655        }
656     } else {
657         WaveOutClearDoneBuffers( p_sys );
658     }
659
660     /* now we can Close the device */
661     if( waveOutClose( p_sys->h_waveout ) != MMSYSERR_NOERROR )
662     {
663         msg_Err( p_aout, "waveOutClose failed" );
664     }
665
666     /*
667       because so long, the waveout device is playing, the callback
668       could occur and need the events
669     */
670     CloseHandle( p_sys->event );
671     CloseHandle( p_sys->new_buffer_event);
672
673     free( p_sys->p_silence_buffer );
674     free( p_sys );
675 }
676
677 /*****************************************************************************
678  * OpenWaveOut: open the waveout sound device
679  ****************************************************************************/
680 static int OpenWaveOut( aout_instance_t *p_aout, uint32_t i_device_id, int i_format,
681                         int i_channels, int i_nb_channels, int i_rate,
682                         vlc_bool_t b_probe )
683 {
684     MMRESULT result;
685     unsigned int i;
686
687     /* Set sound format */
688
689 #define waveformat p_aout->output.p_sys->waveformat
690
691     waveformat.dwChannelMask = 0;
692     for( i = 0; i < sizeof(pi_channels_src)/sizeof(uint32_t); i++ )
693     {
694         if( i_channels & pi_channels_src[i] )
695             waveformat.dwChannelMask |= pi_channels_in[i];
696     }
697
698     switch( i_format )
699     {
700     case VLC_FOURCC('s','p','d','i'):
701         i_nb_channels = 2;
702         /* To prevent channel re-ordering */
703         waveformat.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
704         waveformat.Format.wBitsPerSample = 16;
705         waveformat.Samples.wValidBitsPerSample =
706             waveformat.Format.wBitsPerSample;
707         waveformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
708         waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF;
709         break;
710
711     case VLC_FOURCC('f','l','3','2'):
712         waveformat.Format.wBitsPerSample = sizeof(float) * 8;
713         waveformat.Samples.wValidBitsPerSample =
714             waveformat.Format.wBitsPerSample;
715         waveformat.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
716         waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
717         break;
718
719     case VLC_FOURCC('s','1','6','l'):
720         waveformat.Format.wBitsPerSample = 16;
721         waveformat.Samples.wValidBitsPerSample =
722             waveformat.Format.wBitsPerSample;
723         waveformat.Format.wFormatTag = WAVE_FORMAT_PCM;
724         waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_PCM;
725         break;
726     }
727
728     waveformat.Format.nChannels = i_nb_channels;
729     waveformat.Format.nSamplesPerSec = i_rate;
730     waveformat.Format.nBlockAlign =
731         waveformat.Format.wBitsPerSample / 8 * i_nb_channels;
732     waveformat.Format.nAvgBytesPerSec =
733         waveformat.Format.nSamplesPerSec * waveformat.Format.nBlockAlign;
734
735     /* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */
736     if( i_nb_channels <= 2 )
737     {
738         waveformat.Format.cbSize = 0;
739     }
740     else
741     {
742         waveformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
743         waveformat.Format.cbSize =
744             sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
745     }
746
747     if(!b_probe) {
748         msg_Dbg( p_aout, "OpenWaveDevice-ID: %u", i_device_id);
749         msg_Dbg( p_aout,"waveformat.Format.cbSize          = %d",
750                  waveformat.Format.cbSize);
751         msg_Dbg( p_aout,"waveformat.Format.wFormatTag      = %u",
752                  waveformat.Format.wFormatTag);
753         msg_Dbg( p_aout,"waveformat.Format.nChannels       = %u",
754                  waveformat.Format.nChannels);
755         msg_Dbg( p_aout,"waveformat.Format.nSamplesPerSec  = %d",
756                  (int)waveformat.Format.nSamplesPerSec);
757         msg_Dbg( p_aout,"waveformat.Format.nAvgBytesPerSec = %u",
758                  (int)waveformat.Format.nAvgBytesPerSec);
759         msg_Dbg( p_aout,"waveformat.Format.nBlockAlign     = %d",
760                  waveformat.Format.nBlockAlign);
761         msg_Dbg( p_aout,"waveformat.Format.wBitsPerSample  = %d",
762                  waveformat.Format.wBitsPerSample);
763         msg_Dbg( p_aout,"waveformat.Samples.wValidBitsPerSample = %d",
764                  waveformat.Samples.wValidBitsPerSample);
765         msg_Dbg( p_aout,"waveformat.Samples.wSamplesPerBlock = %d",
766                  waveformat.Samples.wSamplesPerBlock);
767         msg_Dbg( p_aout,"waveformat.dwChannelMask          = %lu",
768                  waveformat.dwChannelMask);
769     }
770
771     /* Open the device */
772     result = waveOutOpen( &p_aout->output.p_sys->h_waveout, i_device_id,
773                           (WAVEFORMATEX *)&waveformat,
774                           (DWORD_PTR)WaveOutCallback, (DWORD_PTR)p_aout,
775                           CALLBACK_FUNCTION | (b_probe?WAVE_FORMAT_QUERY:0) );
776     if( result == WAVERR_BADFORMAT )
777     {
778         msg_Warn( p_aout, "waveOutOpen failed WAVERR_BADFORMAT" );
779         return VLC_EGENERIC;
780     }
781     if( result == MMSYSERR_ALLOCATED )
782     {
783         msg_Warn( p_aout, "waveOutOpen failed WAVERR_ALLOCATED" );
784         return VLC_EGENERIC;
785     }
786     if( result != MMSYSERR_NOERROR )
787     {
788         msg_Warn( p_aout, "waveOutOpen failed" );
789         return VLC_EGENERIC;
790     }
791
792     p_aout->output.p_sys->b_chan_reorder =
793         aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
794                                   waveformat.dwChannelMask, i_nb_channels,
795                                   p_aout->output.p_sys->pi_chan_table );
796
797     if( p_aout->output.p_sys->b_chan_reorder )
798     {
799         msg_Dbg( p_aout, "channel reordering needed" );
800     }
801
802     return VLC_SUCCESS;
803
804 #undef waveformat
805
806 }
807
808 /*****************************************************************************
809  * OpenWaveOutPCM: open a PCM waveout sound device
810  ****************************************************************************/
811 static int OpenWaveOutPCM( aout_instance_t *p_aout, uint32_t i_device_id, int *i_format,
812                            int i_channels, int i_nb_channels, int i_rate,
813                            vlc_bool_t b_probe )
814 {
815     vlc_bool_t b_use_float32 = var_CreateGetBool( p_aout, "waveout-float32");
816
817     if( !b_use_float32 || OpenWaveOut( p_aout, i_device_id, VLC_FOURCC('f','l','3','2'),
818                                    i_channels, i_nb_channels, i_rate, b_probe )
819         != VLC_SUCCESS )
820     {
821         if ( OpenWaveOut( p_aout, i_device_id, VLC_FOURCC('s','1','6','l'),
822                           i_channels, i_nb_channels, i_rate, b_probe )
823              != VLC_SUCCESS )
824         {
825             return VLC_EGENERIC;
826         }
827         else
828         {
829             *i_format = VLC_FOURCC('s','1','6','l');
830             return VLC_SUCCESS;
831         }
832     }
833     else
834     {
835         *i_format = VLC_FOURCC('f','l','3','2');
836         return VLC_SUCCESS;
837     }
838 }
839
840 /*****************************************************************************
841  * PlayWaveOut: play a buffer through the WaveOut device
842  *****************************************************************************/
843 static int PlayWaveOut( aout_instance_t *p_aout, HWAVEOUT h_waveout,
844                         WAVEHDR *p_waveheader, aout_buffer_t *p_buffer,
845                         vlc_bool_t b_spdif)
846 {
847     MMRESULT result;
848
849     /* Prepare the buffer */
850     if( p_buffer != NULL )
851     {
852         p_waveheader->lpData = p_buffer->p_buffer;
853         /*
854           copy the buffer to the silence buffer :) so in case we don't
855           get the next buffer fast enough (I will repeat this one a time
856           for AC3 / DTS and SPDIF this will sound better instead of
857           a hickup)
858         */
859         if(b_spdif)
860         {
861            p_aout->p_libvlc->pf_memcpy( p_aout->output.p_sys->p_silence_buffer,
862                                      p_buffer->p_buffer,
863                                      p_aout->output.p_sys->i_buffer_size );
864            p_aout->output.p_sys->i_repeat_counter = 2;
865         }
866     } else {
867         /* Use silence buffer instead */
868         if(p_aout->output.p_sys->i_repeat_counter)
869         {
870            p_aout->output.p_sys->i_repeat_counter--;
871            if(!p_aout->output.p_sys->i_repeat_counter)
872            {
873                p_aout->p_libvlc->pf_memset( p_aout->output.p_sys->p_silence_buffer,
874                                             0x00,
875                                             p_aout->output.p_sys->i_buffer_size
876                                           );
877            }
878         }
879         p_waveheader->lpData = p_aout->output.p_sys->p_silence_buffer;
880     }
881
882     p_waveheader->dwUser = p_buffer ? (DWORD_PTR)p_buffer : (DWORD_PTR)1;
883     p_waveheader->dwBufferLength = p_aout->output.p_sys->i_buffer_size;
884     p_waveheader->dwFlags = 0;
885
886     result = waveOutPrepareHeader( h_waveout, p_waveheader, sizeof(WAVEHDR) );
887     if( result != MMSYSERR_NOERROR )
888     {
889         msg_Err( p_aout, "waveOutPrepareHeader failed" );
890         return VLC_EGENERIC;
891     }
892
893     /* Send the buffer to the waveOut queue */
894     result = waveOutWrite( h_waveout, p_waveheader, sizeof(WAVEHDR) );
895     if( result != MMSYSERR_NOERROR )
896     {
897         msg_Err( p_aout, "waveOutWrite failed" );
898         return VLC_EGENERIC;
899     }
900
901     return VLC_SUCCESS;
902 }
903
904 /*****************************************************************************
905  * WaveOutCallback: what to do once WaveOut has played its sound samples
906  *****************************************************************************/
907 static void CALLBACK WaveOutCallback( HWAVEOUT h_waveout, UINT uMsg,
908                                       DWORD _p_aout,
909                                       DWORD dwParam1, DWORD dwParam2 )
910 {
911     aout_instance_t *p_aout = (aout_instance_t *)_p_aout;
912     int i, i_queued_frames = 0;
913
914     if( uMsg != WOM_DONE ) return;
915
916     if( p_aout->b_die ) return;
917
918     /* Find out the current latency */
919     for( i = 0; i < FRAMES_NUM; i++ )
920     {
921         /* Check if frame buf is available */
922         if( !(p_aout->output.p_sys->waveheader[i].dwFlags & WHDR_DONE) )
923         {
924             i_queued_frames++;
925         }
926     }
927
928     /* Don't wake up the thread too much */
929     if( i_queued_frames <= FRAMES_NUM/2 )
930         SetEvent( p_aout->output.p_sys->event );
931 }
932
933
934 /****************************************************************************
935  * WaveOutClearDoneBuffers: Clear all done marked buffers, and free aout_bufer
936  ****************************************************************************
937  * return value is the number of still playing buffers in the queue
938  ****************************************************************************/
939 static int WaveOutClearDoneBuffers(aout_sys_t *p_sys)
940 {
941     WAVEHDR *p_waveheader = p_sys->waveheader;
942     int i_queued_frames = 0;
943
944     for( int i = 0; i < FRAMES_NUM; i++ )
945     {
946         if( (p_waveheader[i].dwFlags & WHDR_DONE) &&
947             p_waveheader[i].dwUser )
948         {
949             aout_buffer_t *p_buffer =
950                     (aout_buffer_t *)(p_waveheader[i].dwUser);
951             /* Unprepare and free the buffers which has just been played */
952             waveOutUnprepareHeader( p_sys->h_waveout, &p_waveheader[i],
953                                     sizeof(WAVEHDR) );
954
955             if( p_waveheader[i].dwUser != 1 )
956                 aout_BufferFree( p_buffer );
957
958             p_waveheader[i].dwUser = 0;
959         }
960
961         /* Check if frame buf is available */
962         if( !(p_waveheader[i].dwFlags & WHDR_DONE) )
963         {
964             i_queued_frames++;
965         }
966     }
967     return i_queued_frames;
968 }
969
970 /*****************************************************************************
971  * WaveOutThread: this thread will capture play notification events.
972  *****************************************************************************
973  * We use this thread to feed new audio samples to the sound card because
974  * we are not authorized to use waveOutWrite() directly in the waveout
975  * callback.
976  *****************************************************************************/
977 static void WaveOutThread( notification_thread_t *p_notif )
978 {
979     aout_instance_t *p_aout = p_notif->p_aout;
980     aout_sys_t *p_sys = p_aout->output.p_sys;
981     aout_buffer_t *p_buffer = NULL;
982     WAVEHDR *p_waveheader = p_sys->waveheader;
983     int i, i_queued_frames;
984     vlc_bool_t b_sleek;
985     mtime_t next_date;
986     uint32_t i_buffer_length = 64;
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 && !p_aout->b_die )
993            WaitForSingleObject( p_sys->event, INFINITE );
994     if( p_aout->b_die )
995         return;
996
997     msg_Dbg( p_aout, "will start to play in "I64Fd" 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( !p_aout->b_die )
1012     {
1013         /* Cleanup and find out the current latency */
1014         i_queued_frames = WaveOutClearDoneBuffers( p_sys );
1015
1016         if( p_aout->b_die ) return;
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( p_aout->b_die ) return;
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 }
1114
1115 static int VolumeInfos( aout_instance_t * p_aout, audio_volume_t * pi_soft )
1116 {
1117     *pi_soft = AOUT_VOLUME_MAX / 2;
1118     return 0;
1119 }
1120
1121 static int VolumeGet( aout_instance_t * p_aout, audio_volume_t * pi_volume )
1122 {
1123     DWORD i_waveout_vol;
1124
1125 #ifdef UNDER_CE
1126     waveOutGetVolume( 0, &i_waveout_vol );
1127 #else
1128     waveOutGetVolume( p_aout->output.p_sys->h_waveout, &i_waveout_vol );
1129 #endif
1130
1131     i_waveout_vol &= 0xFFFF;
1132     *pi_volume = p_aout->output.i_volume =
1133         (i_waveout_vol * AOUT_VOLUME_MAX + 0xFFFF /*rounding*/) / 2 / 0xFFFF;
1134     return 0;
1135 }
1136
1137 static int VolumeSet( aout_instance_t * p_aout, audio_volume_t i_volume )
1138 {
1139     unsigned long i_waveout_vol = i_volume * 0xFFFF * 2 / AOUT_VOLUME_MAX;
1140     i_waveout_vol |= (i_waveout_vol << 16);
1141
1142 #ifdef UNDER_CE
1143     waveOutSetVolume( 0, i_waveout_vol );
1144 #else
1145     waveOutSetVolume( p_aout->output.p_sys->h_waveout, i_waveout_vol );
1146 #endif
1147
1148     p_aout->output.i_volume = i_volume;
1149     return 0;
1150 }
1151
1152
1153 /*
1154   reload the configuration drop down list, of the Audio Devices
1155 */
1156 static int ReloadWaveoutDevices( vlc_object_t *p_this, char const *psz_name,
1157                                  vlc_value_t newval, vlc_value_t oldval, void *data )
1158 {
1159     int i;
1160
1161     module_config_t *p_item = config_FindConfig( p_this, psz_name );
1162     if( !p_item ) return VLC_SUCCESS;
1163
1164     /* Clear-up the current list */
1165     if( p_item->i_list )
1166     {
1167         /* Keep the first entry */
1168         for( i = 1; i < p_item->i_list; i++ )
1169         {
1170             free((char *)(p_item->ppsz_list[i]) );
1171             free((char *)(p_item->ppsz_list_text[i]) );
1172         }
1173         /* TODO: Remove when no more needed */
1174         p_item->ppsz_list[i] = NULL;
1175         p_item->ppsz_list_text[i] = NULL;
1176     }
1177     p_item->i_list = 1;
1178
1179     int wave_devices = waveOutGetNumDevs();
1180
1181     p_item->ppsz_list =
1182         (char **)realloc( p_item->ppsz_list,
1183                           (wave_devices+2) * sizeof(char *) );
1184     p_item->ppsz_list_text =
1185         (char **)realloc( p_item->ppsz_list_text,
1186                           (wave_devices+2) * sizeof(char *) );
1187
1188     WAVEOUTCAPS caps;
1189     char sz_dev_name[MAXPNAMELEN+32];
1190     int j=1;
1191     for(int i=0; i<wave_devices; i++)
1192     {
1193         if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
1194            == MMSYSERR_NOERROR)
1195         {
1196           sprintf( sz_dev_name, psz_device_name_fmt, caps.szPname,
1197                                                caps.wMid,
1198                                                caps.wPid
1199                                               );
1200           p_item->ppsz_list[j] = FromLocaleDup( sz_dev_name );
1201           p_item->ppsz_list_text[j] = FromLocaleDup( sz_dev_name );
1202           p_item->i_list++;
1203           j++;
1204         }
1205
1206     }
1207     p_item->ppsz_list[j] = NULL;
1208     p_item->ppsz_list_text[j] = NULL;
1209
1210     /* Signal change to the interface */
1211     p_item->b_dirty = VLC_TRUE;
1212
1213     return VLC_SUCCESS;
1214 }
1215
1216 /*
1217   convert devicename to device ID for output
1218   if device not found return WAVE_MAPPER, so let
1219   windows decide which preferred audio device
1220   should be used.
1221 */
1222 static uint32_t findDeviceID(char *psz_device_name)
1223 {
1224     if(!psz_device_name)
1225        return WAVE_MAPPER;
1226
1227     uint32_t wave_devices = waveOutGetNumDevs();
1228     WAVEOUTCAPS caps;
1229     char sz_dev_name[MAXPNAMELEN+32];
1230     for(uint32_t i=0; i<wave_devices; i++)
1231     {
1232         if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
1233            == MMSYSERR_NOERROR)
1234         {
1235             sprintf(sz_dev_name, psz_device_name_fmt, caps.szPname,
1236                                                caps.wMid,
1237                                                caps.wPid
1238                                               );
1239             char *psz_temp = FromLocaleDup(sz_dev_name);
1240
1241             if( !stricmp(psz_temp, psz_device_name) )
1242             {
1243                 LocaleFree( psz_temp );
1244                 return i;
1245             }
1246             LocaleFree( psz_temp );
1247         }
1248     }
1249
1250     return WAVE_MAPPER;
1251 }