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