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