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