]> git.sesse.net Git - vlc/blob - modules/audio_output/waveout.c
Plugins: push cancellation down
[vlc] / modules / audio_output / waveout.c
1 /*****************************************************************************
2  * waveout.c : Windows waveOut plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2001 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Gildas Bazin <gbazin@videolan.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
34 #include <vlc_aout.h>
35 #include <vlc_charset.h>
36
37 #include <windows.h>
38 #include <mmsystem.h>
39
40 #define FRAME_SIZE 4096              /* The size is in samples, not in bytes */
41 #define FRAMES_NUM 8
42
43 /*****************************************************************************
44  * Useful macros
45  *****************************************************************************/
46 #ifdef UNDER_CE
47 #   define DWORD_PTR DWORD
48 #   ifdef waveOutGetDevCaps
49 #       undef waveOutGetDevCaps
50         MMRESULT WINAPI waveOutGetDevCaps(UINT, LPWAVEOUTCAPS, UINT);
51 #   endif
52 #endif
53
54 #ifndef WAVE_FORMAT_IEEE_FLOAT
55 #   define WAVE_FORMAT_IEEE_FLOAT 0x0003
56 #endif
57
58 #ifndef WAVE_FORMAT_DOLBY_AC3_SPDIF
59 #   define WAVE_FORMAT_DOLBY_AC3_SPDIF 0x0092
60 #endif
61
62 #ifndef WAVE_FORMAT_EXTENSIBLE
63 #define  WAVE_FORMAT_EXTENSIBLE   0xFFFE
64 #endif
65
66 #ifndef SPEAKER_FRONT_LEFT
67 #   define SPEAKER_FRONT_LEFT             0x1
68 #   define SPEAKER_FRONT_RIGHT            0x2
69 #   define SPEAKER_FRONT_CENTER           0x4
70 #   define SPEAKER_LOW_FREQUENCY          0x8
71 #   define SPEAKER_BACK_LEFT              0x10
72 #   define SPEAKER_BACK_RIGHT             0x20
73 #   define SPEAKER_FRONT_LEFT_OF_CENTER   0x40
74 #   define SPEAKER_FRONT_RIGHT_OF_CENTER  0x80
75 #   define SPEAKER_BACK_CENTER            0x100
76 #   define SPEAKER_SIDE_LEFT              0x200
77 #   define SPEAKER_SIDE_RIGHT             0x400
78 #   define SPEAKER_TOP_CENTER             0x800
79 #   define SPEAKER_TOP_FRONT_LEFT         0x1000
80 #   define SPEAKER_TOP_FRONT_CENTER       0x2000
81 #   define SPEAKER_TOP_FRONT_RIGHT        0x4000
82 #   define SPEAKER_TOP_BACK_LEFT          0x8000
83 #   define SPEAKER_TOP_BACK_CENTER        0x10000
84 #   define SPEAKER_TOP_BACK_RIGHT         0x20000
85 #   define SPEAKER_RESERVED               0x80000000
86 #endif
87
88 #ifndef _WAVEFORMATEXTENSIBLE_
89 typedef struct {
90     WAVEFORMATEX    Format;
91     union {
92         WORD wValidBitsPerSample;       /* bits of precision  */
93         WORD wSamplesPerBlock;          /* valid if wBitsPerSample==0 */
94         WORD wReserved;                 /* If neither applies, set to zero. */
95     } Samples;
96     DWORD           dwChannelMask;      /* which channels are */
97                                         /* present in stream  */
98     GUID            SubFormat;
99 } WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE;
100 #endif
101
102 static const GUID __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = {WAVE_FORMAT_IEEE_FLOAT, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
103 static const GUID __KSDATAFORMAT_SUBTYPE_PCM = {WAVE_FORMAT_PCM, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
104 static const GUID __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF = {WAVE_FORMAT_DOLBY_AC3_SPDIF, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
105
106 /*****************************************************************************
107  * Local prototypes
108  *****************************************************************************/
109 static int  Open         ( vlc_object_t * );
110 static void Close        ( vlc_object_t * );
111 static void Play         ( aout_instance_t * );
112
113 /*****************************************************************************
114  * notification_thread_t: waveOut event thread
115  *****************************************************************************/
116 typedef struct notification_thread_t
117 {
118     VLC_COMMON_MEMBERS
119     aout_instance_t *p_aout;
120
121 } notification_thread_t;
122
123 /* local functions */
124 static void Probe        ( aout_instance_t * );
125 static int OpenWaveOut   ( aout_instance_t *, uint32_t,
126                            int, int, int, int, bool );
127 static int OpenWaveOutPCM( aout_instance_t *, uint32_t,
128                            int*, int, int, int, bool );
129 static int PlayWaveOut   ( aout_instance_t *, HWAVEOUT, WAVEHDR *,
130                            aout_buffer_t *, bool );
131
132 static void CALLBACK WaveOutCallback ( HWAVEOUT, UINT, DWORD, DWORD, DWORD );
133 static void* WaveOutThread( vlc_object_t * );
134
135 static int VolumeInfos( aout_instance_t *, audio_volume_t * );
136 static int VolumeGet( aout_instance_t *, audio_volume_t * );
137 static int VolumeSet( aout_instance_t *, audio_volume_t );
138
139 static int WaveOutClearDoneBuffers(aout_sys_t *p_sys);
140
141 static int ReloadWaveoutDevices( vlc_object_t *, char const *,
142                                 vlc_value_t, vlc_value_t, void * );
143 static uint32_t findDeviceID(char *);
144
145 static const char psz_device_name_fmt[] = "%s ($%x,$%x)";
146
147 static const char *const ppsz_adev[] = { "wavemapper", };
148 static const char *const ppsz_adev_text[] = { N_("Microsoft Soundmapper") };
149
150
151
152 /*****************************************************************************
153  * Module descriptor
154  *****************************************************************************/
155 #define FLOAT_TEXT N_("Use float32 output")
156 #define FLOAT_LONGTEXT N_( \
157     "The option allows you to enable or disable the high-quality float32 " \
158     "audio output mode (which is not well supported by some soundcards)." )
159 #define DEVICE_TEXT N_("Select Audio Device")
160 #define DEVICE_LONG N_("Select special Audio device, or let windows "\
161                        "decide (default), change needs VLC restart "\
162                        "to apply.")
163 #define DEFAULT_AUDIO_DEVICE N_("Default Audio Device")
164
165 vlc_module_begin();
166     set_shortname( "WaveOut" );
167     set_description( N_("Win32 waveOut extension output") );
168     set_capability( "audio output", 50 );
169     set_category( CAT_AUDIO );
170     set_subcategory( SUBCAT_AUDIO_AOUT );
171     add_bool( "waveout-float32", 1, 0, FLOAT_TEXT, FLOAT_LONGTEXT, true );
172
173     add_string( "waveout-dev", "wavemapper", NULL,
174                  DEVICE_TEXT, DEVICE_LONG, false );
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-dev", val, val, NULL);
259
260
261     /*
262       check for configured audio device!
263     */
264     char *psz_waveout_dev = var_CreateGetString( p_aout, "waveout-dev");
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-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_FOURCC('s','p','d','i');
316
317         if( OpenWaveOut( p_aout,
318                          p_aout->output.p_sys->i_wave_device_id,
319                          VLC_FOURCC('s','p','d','i'),
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         if( val.i_int == AOUT_VAR_5_1 )
344         {
345             p_aout->output.output.i_physical_channels
346                 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
347                    | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
348                    | AOUT_CHAN_LFE;
349         }
350         else if( val.i_int == AOUT_VAR_2F2R )
351         {
352             p_aout->output.output.i_physical_channels
353                 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
354                    | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
355         }
356         else if( val.i_int == AOUT_VAR_MONO )
357         {
358             p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
359         }
360         else
361         {
362             p_aout->output.output.i_physical_channels
363                 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
364         }
365
366         if( OpenWaveOutPCM( p_aout,
367                             p_aout->output.p_sys->i_wave_device_id,
368                             &p_aout->output.output.i_format,
369                             p_aout->output.output.i_physical_channels,
370                             aout_FormatNbChannels( &p_aout->output.output ),
371                             p_aout->output.output.i_rate, false )
372             != VLC_SUCCESS )
373         {
374             msg_Err( p_aout, "cannot open waveout audio device" );
375             free( p_aout->output.p_sys );
376             return VLC_EGENERIC;
377         }
378
379         /* Calculate the frame size in bytes */
380         p_aout->output.i_nb_samples = FRAME_SIZE;
381         aout_FormatPrepare( &p_aout->output.output );
382         p_aout->output.p_sys->i_buffer_size = FRAME_SIZE *
383             p_aout->output.output.i_bytes_per_frame;
384
385         aout_VolumeSoftInit( p_aout );
386
387         /* Check for hardware volume support */
388         if( waveOutGetDevCaps( (UINT_PTR)p_aout->output.p_sys->h_waveout,
389                                &wocaps, sizeof(wocaps) ) == MMSYSERR_NOERROR &&
390             wocaps.dwSupport & WAVECAPS_VOLUME )
391         {
392             DWORD i_dummy;
393             if( waveOutGetVolume( p_aout->output.p_sys->h_waveout, &i_dummy )
394                 == MMSYSERR_NOERROR )
395             {
396                 p_aout->output.pf_volume_infos = VolumeInfos;
397                 p_aout->output.pf_volume_get = VolumeGet;
398                 p_aout->output.pf_volume_set = VolumeSet;
399             }
400         }
401     }
402
403
404     waveOutReset( p_aout->output.p_sys->h_waveout );
405
406     /* Allocate silence buffer */
407     p_aout->output.p_sys->p_silence_buffer =
408         malloc( p_aout->output.p_sys->i_buffer_size );
409     if( p_aout->output.p_sys->p_silence_buffer == NULL )
410     {
411         free( p_aout->output.p_sys );
412         return 1;
413     }
414     p_aout->output.p_sys->i_repeat_counter = 0;
415
416
417     /* Zero the buffer. WinCE doesn't have calloc(). */
418     memset( p_aout->output.p_sys->p_silence_buffer, 0,
419             p_aout->output.p_sys->i_buffer_size );
420
421     /* Now we need to setup our waveOut play notification structure */
422     p_aout->output.p_sys->p_notif =
423         vlc_object_create( p_aout, sizeof(notification_thread_t) );
424     p_aout->output.p_sys->p_notif->p_aout = p_aout;
425     p_aout->output.p_sys->event = CreateEvent( NULL, FALSE, FALSE, NULL );
426     p_aout->output.p_sys->new_buffer_event = CreateEvent( NULL, FALSE, FALSE, NULL );
427
428     /* define startpoint of playback on first call to play()
429       like alsa does (instead of playing a blank sample) */
430     p_aout->output.p_sys->b_playing = 0;
431     p_aout->output.p_sys->start_date = 0;
432
433
434     /* Then launch the notification thread */
435     if( vlc_thread_create( p_aout->output.p_sys->p_notif,
436                            "waveOut Notification Thread", WaveOutThread,
437                            VLC_THREAD_PRIORITY_OUTPUT, false ) )
438     {
439         msg_Err( p_aout, "cannot create WaveOutThread" );
440     }
441
442     /* We need to kick off the playback in order to have the callback properly
443      * working */
444     for( i = 0; i < FRAMES_NUM; i++ )
445     {
446         p_aout->output.p_sys->waveheader[i].dwFlags = WHDR_DONE;
447         p_aout->output.p_sys->waveheader[i].dwUser = 0;
448     }
449
450     return 0;
451 }
452
453 /*****************************************************************************
454  * Probe: probe the audio device for available formats and channels
455  *****************************************************************************/
456 static void Probe( aout_instance_t * p_aout )
457 {
458     vlc_value_t val, text;
459     int i_format;
460     unsigned int i_physical_channels;
461
462     var_Create( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
463     text.psz_string = _("Audio Device");
464     var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
465
466     /* Test for 5.1 support */
467     i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
468                           AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
469                           AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE;
470     if( p_aout->output.output.i_physical_channels == i_physical_channels )
471     {
472         if( OpenWaveOutPCM( p_aout,
473                             p_aout->output.p_sys->i_wave_device_id,
474                             &i_format,
475                             i_physical_channels, 6,
476                             p_aout->output.output.i_rate, true )
477             == VLC_SUCCESS )
478         {
479             val.i_int = AOUT_VAR_5_1;
480             text.psz_string = (char *)N_("5.1");
481             var_Change( p_aout, "audio-device",
482                         VLC_VAR_ADDCHOICE, &val, &text );
483             msg_Dbg( p_aout, "device supports 5.1 channels" );
484         }
485     }
486
487     /* Test for 2 Front 2 Rear support */
488     i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
489                           AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
490     if( ( p_aout->output.output.i_physical_channels & i_physical_channels )
491         == i_physical_channels )
492     {
493         if( OpenWaveOutPCM( p_aout,
494                             p_aout->output.p_sys->i_wave_device_id,
495                             &i_format,
496                             i_physical_channels, 4,
497                             p_aout->output.output.i_rate, true )
498             == VLC_SUCCESS )
499         {
500             val.i_int = AOUT_VAR_2F2R;
501             text.psz_string = (char *)N_("2 Front 2 Rear");
502             var_Change( p_aout, "audio-device",
503                         VLC_VAR_ADDCHOICE, &val, &text );
504             msg_Dbg( p_aout, "device supports 4 channels" );
505         }
506     }
507
508     /* Test for stereo support */
509     i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
510     if( OpenWaveOutPCM( p_aout,
511                         p_aout->output.p_sys->i_wave_device_id,
512                         &i_format,
513                         i_physical_channels, 2,
514                         p_aout->output.output.i_rate, true )
515         == VLC_SUCCESS )
516     {
517         val.i_int = AOUT_VAR_STEREO;
518         text.psz_string = (char *)N_("Stereo");
519         var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
520         msg_Dbg( p_aout, "device supports 2 channels" );
521     }
522
523     /* Test for mono support */
524     i_physical_channels = AOUT_CHAN_CENTER;
525     if( OpenWaveOutPCM( p_aout,
526                         p_aout->output.p_sys->i_wave_device_id,
527                         &i_format,
528                         i_physical_channels, 1,
529                         p_aout->output.output.i_rate, true )
530         == VLC_SUCCESS )
531     {
532         val.i_int = AOUT_VAR_MONO;
533         text.psz_string = (char *)N_("Mono");
534         var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
535         msg_Dbg( p_aout, "device supports 1 channel" );
536     }
537
538     /* Test for SPDIF support */
539     if ( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
540     {
541         if( OpenWaveOut( p_aout,
542                          p_aout->output.p_sys->i_wave_device_id,
543                          VLC_FOURCC('s','p','d','i'),
544                          p_aout->output.output.i_physical_channels,
545                          aout_FormatNbChannels( &p_aout->output.output ),
546                          p_aout->output.output.i_rate, true )
547             == VLC_SUCCESS )
548         {
549             msg_Dbg( p_aout, "device supports A/52 over S/PDIF" );
550             val.i_int = AOUT_VAR_SPDIF;
551             text.psz_string = (char *)N_("A/52 over S/PDIF");
552             var_Change( p_aout, "audio-device",
553                         VLC_VAR_ADDCHOICE, &val, &text );
554             if( config_GetInt( p_aout, "spdif" ) )
555                 var_Set( p_aout, "audio-device", val );
556         }
557     }
558
559     var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
560     if( val.i_int <= 0 )
561     {
562         /* Probe() has failed. */
563         var_Destroy( p_aout, "audio-device" );
564         return;
565     }
566
567     var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
568
569     val.b_bool = true;
570     var_Set( p_aout, "intf-change", val );
571 }
572
573 /*****************************************************************************
574  * Play: play a sound buffer
575  *****************************************************************************
576  * This doesn't actually play the buffer. This just stores the buffer so it
577  * can be played by the callback thread.
578  *****************************************************************************/
579 static void Play( aout_instance_t *_p_aout )
580 {
581     if( !_p_aout->output.p_sys->b_playing )
582     {
583         _p_aout->output.p_sys->b_playing = 1;
584
585         /* get the playing date of the first aout buffer */
586         _p_aout->output.p_sys->start_date =
587             aout_FifoFirstDate( _p_aout, &_p_aout->output.fifo );
588
589         msg_Dbg( _p_aout, "Wakeup sleeping output thread.");
590
591         /* wake up the audio output thread */
592         SetEvent( _p_aout->output.p_sys->event );
593     } else {
594         SetEvent( _p_aout->output.p_sys->new_buffer_event );
595     }
596 }
597
598 /*****************************************************************************
599  * Close: close the audio device
600  *****************************************************************************/
601 static void Close( vlc_object_t *p_this )
602 {
603     aout_instance_t *p_aout = (aout_instance_t *)p_this;
604     aout_sys_t *p_sys = p_aout->output.p_sys;
605
606     /* Before calling waveOutClose we must reset the device */
607     vlc_object_kill( p_aout );
608
609     /* wake up the audio thread, to recognize that p_aout died */
610     SetEvent( p_sys->event );
611     SetEvent( p_sys->new_buffer_event );
612
613     vlc_thread_join( p_sys->p_notif );
614     vlc_object_release( p_sys->p_notif );
615
616     /*
617       kill the real output then - when the feed thread
618       is surely terminated!
619       old code could be too early in case that "feeding"
620       was running on termination
621
622       at this point now its sure, that there will be no new
623       data send to the driver, and we can cancel the last
624       running playbuffers
625     */
626     MMRESULT result = waveOutReset( p_sys->h_waveout );
627     if(result != MMSYSERR_NOERROR)
628     {
629        msg_Err( p_aout, "waveOutReset failed 0x%x", result );
630        /*
631         now we must wait, that all buffers are played
632         because cancel doesn't work in this case...
633        */
634        if(result == MMSYSERR_NOTSUPPORTED)
635        {
636            /*
637              clear currently played (done) buffers,
638              if returnvalue > 0 (means some buffer still playing)
639              wait for the driver event callback that one buffer
640              is finished with playing, and check again
641              the timeout of 5000ms is just, an emergency exit
642              of this loop, to avoid deadlock in case of other
643              (currently not known bugs, problems, errors cases?)
644            */
645            while(
646                  (WaveOutClearDoneBuffers( p_sys ) > 0)
647                  &&
648                  (WaitForSingleObject( p_sys->event, 5000) == WAIT_OBJECT_0)
649                 )
650            {
651                  msg_Dbg( p_aout, "Wait for waveout device...");
652            }
653        }
654     } else {
655         WaveOutClearDoneBuffers( p_sys );
656     }
657
658     /* now we can Close the device */
659     if( waveOutClose( p_sys->h_waveout ) != MMSYSERR_NOERROR )
660     {
661         msg_Err( p_aout, "waveOutClose failed" );
662     }
663
664     /*
665       because so long, the waveout device is playing, the callback
666       could occur and need the events
667     */
668     CloseHandle( p_sys->event );
669     CloseHandle( p_sys->new_buffer_event);
670
671     free( p_sys->p_silence_buffer );
672     free( p_sys );
673 }
674
675 /*****************************************************************************
676  * OpenWaveOut: open the waveout sound device
677  ****************************************************************************/
678 static int OpenWaveOut( aout_instance_t *p_aout, uint32_t i_device_id, int i_format,
679                         int i_channels, int i_nb_channels, int i_rate,
680                         bool b_probe )
681 {
682     MMRESULT result;
683     unsigned int i;
684
685     /* Set sound format */
686
687 #define waveformat p_aout->output.p_sys->waveformat
688
689     waveformat.dwChannelMask = 0;
690     for( i = 0; i < sizeof(pi_channels_src)/sizeof(uint32_t); i++ )
691     {
692         if( i_channels & pi_channels_src[i] )
693             waveformat.dwChannelMask |= pi_channels_in[i];
694     }
695
696     switch( i_format )
697     {
698     case VLC_FOURCC('s','p','d','i'):
699         i_nb_channels = 2;
700         /* To prevent channel re-ordering */
701         waveformat.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
702         waveformat.Format.wBitsPerSample = 16;
703         waveformat.Samples.wValidBitsPerSample =
704             waveformat.Format.wBitsPerSample;
705         waveformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
706         waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF;
707         break;
708
709     case VLC_FOURCC('f','l','3','2'):
710         waveformat.Format.wBitsPerSample = sizeof(float) * 8;
711         waveformat.Samples.wValidBitsPerSample =
712             waveformat.Format.wBitsPerSample;
713         waveformat.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
714         waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
715         break;
716
717     case VLC_FOURCC('s','1','6','l'):
718         waveformat.Format.wBitsPerSample = 16;
719         waveformat.Samples.wValidBitsPerSample =
720             waveformat.Format.wBitsPerSample;
721         waveformat.Format.wFormatTag = WAVE_FORMAT_PCM;
722         waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_PCM;
723         break;
724     }
725
726     waveformat.Format.nChannels = i_nb_channels;
727     waveformat.Format.nSamplesPerSec = i_rate;
728     waveformat.Format.nBlockAlign =
729         waveformat.Format.wBitsPerSample / 8 * i_nb_channels;
730     waveformat.Format.nAvgBytesPerSec =
731         waveformat.Format.nSamplesPerSec * waveformat.Format.nBlockAlign;
732
733     /* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */
734     if( i_nb_channels <= 2 )
735     {
736         waveformat.Format.cbSize = 0;
737     }
738     else
739     {
740         waveformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
741         waveformat.Format.cbSize =
742             sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
743     }
744
745     if(!b_probe) {
746         msg_Dbg( p_aout, "OpenWaveDevice-ID: %u", i_device_id);
747         msg_Dbg( p_aout,"waveformat.Format.cbSize          = %d",
748                  waveformat.Format.cbSize);
749         msg_Dbg( p_aout,"waveformat.Format.wFormatTag      = %u",
750                  waveformat.Format.wFormatTag);
751         msg_Dbg( p_aout,"waveformat.Format.nChannels       = %u",
752                  waveformat.Format.nChannels);
753         msg_Dbg( p_aout,"waveformat.Format.nSamplesPerSec  = %d",
754                  (int)waveformat.Format.nSamplesPerSec);
755         msg_Dbg( p_aout,"waveformat.Format.nAvgBytesPerSec = %u",
756                  (int)waveformat.Format.nAvgBytesPerSec);
757         msg_Dbg( p_aout,"waveformat.Format.nBlockAlign     = %d",
758                  waveformat.Format.nBlockAlign);
759         msg_Dbg( p_aout,"waveformat.Format.wBitsPerSample  = %d",
760                  waveformat.Format.wBitsPerSample);
761         msg_Dbg( p_aout,"waveformat.Samples.wValidBitsPerSample = %d",
762                  waveformat.Samples.wValidBitsPerSample);
763         msg_Dbg( p_aout,"waveformat.Samples.wSamplesPerBlock = %d",
764                  waveformat.Samples.wSamplesPerBlock);
765         msg_Dbg( p_aout,"waveformat.dwChannelMask          = %lu",
766                  waveformat.dwChannelMask);
767     }
768
769     /* Open the device */
770     result = waveOutOpen( &p_aout->output.p_sys->h_waveout, i_device_id,
771                           (WAVEFORMATEX *)&waveformat,
772                           (DWORD_PTR)WaveOutCallback, (DWORD_PTR)p_aout,
773                           CALLBACK_FUNCTION | (b_probe?WAVE_FORMAT_QUERY:0) );
774     if( result == WAVERR_BADFORMAT )
775     {
776         msg_Warn( p_aout, "waveOutOpen failed WAVERR_BADFORMAT" );
777         return VLC_EGENERIC;
778     }
779     if( result == MMSYSERR_ALLOCATED )
780     {
781         msg_Warn( p_aout, "waveOutOpen failed WAVERR_ALLOCATED" );
782         return VLC_EGENERIC;
783     }
784     if( result != MMSYSERR_NOERROR )
785     {
786         msg_Warn( p_aout, "waveOutOpen failed" );
787         return VLC_EGENERIC;
788     }
789
790     p_aout->output.p_sys->b_chan_reorder =
791         aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
792                                   waveformat.dwChannelMask, i_nb_channels,
793                                   p_aout->output.p_sys->pi_chan_table );
794
795     if( p_aout->output.p_sys->b_chan_reorder )
796     {
797         msg_Dbg( p_aout, "channel reordering needed" );
798     }
799
800     return VLC_SUCCESS;
801
802 #undef waveformat
803
804 }
805
806 /*****************************************************************************
807  * OpenWaveOutPCM: open a PCM waveout sound device
808  ****************************************************************************/
809 static int OpenWaveOutPCM( aout_instance_t *p_aout, uint32_t i_device_id, int *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_FOURCC('f','l','3','2'),
816                                    i_channels, i_nb_channels, i_rate, b_probe )
817         != VLC_SUCCESS )
818     {
819         if ( OpenWaveOut( p_aout, i_device_id, VLC_FOURCC('s','1','6','l'),
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_FOURCC('s','1','6','l');
828             return VLC_SUCCESS;
829         }
830     }
831     else
832     {
833         *i_format = VLC_FOURCC('f','l','3','2');
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_FOURCC('s','p','d','i');
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->end_date
1069                                              - p_buffer->start_date);
1070                     next_date = next_date + buffer_length;
1071                     i_buffer_length = buffer_length/1000;
1072                 }
1073
1074                 /* Do the channel reordering */
1075                 if( p_buffer && p_sys->b_chan_reorder )
1076                 {
1077                     aout_ChannelReorder( p_buffer->p_buffer,
1078                         p_buffer->i_nb_bytes,
1079                         p_sys->waveformat.Format.nChannels,
1080                         p_sys->pi_chan_table,
1081                         p_sys->waveformat.Format.wBitsPerSample );
1082                 }
1083
1084                 PlayWaveOut( p_aout, p_sys->h_waveout,
1085                              &p_waveheader[i], p_buffer, b_sleek );
1086
1087                 i_queued_frames++;
1088             }
1089         }
1090
1091         if( !vlc_object_alive (p_aout) ) return NULL;
1092
1093         /*
1094           deal with the case that the loop didn't fillup the buffer to the
1095           max - instead of waiting that half the buffer is played before
1096           fillup the waveout buffers, wait only for the next sample buffer
1097           to arrive at the play method...
1098
1099           this will also avoid, that the last buffer is play until the
1100           end, and then trying to get more data, so it will also
1101           work - if the next buffer will arrive some ms before the
1102           last buffer is finished.
1103         */
1104         if(i_queued_frames < FRAMES_NUM)
1105            WaitForSingleObject( p_sys->new_buffer_event, INFINITE );
1106         else
1107            WaitForSingleObject( p_sys->event, INFINITE );
1108
1109     }
1110
1111 #undef waveout_warn
1112     vlc_restorecancel (canc);
1113     return NULL;
1114 }
1115
1116 static int VolumeInfos( aout_instance_t * p_aout, audio_volume_t * pi_soft )
1117 {
1118     *pi_soft = AOUT_VOLUME_MAX / 2;
1119     return 0;
1120 }
1121
1122 static int VolumeGet( aout_instance_t * p_aout, audio_volume_t * pi_volume )
1123 {
1124     DWORD i_waveout_vol;
1125
1126 #ifdef UNDER_CE
1127     waveOutGetVolume( 0, &i_waveout_vol );
1128 #else
1129     waveOutGetVolume( p_aout->output.p_sys->h_waveout, &i_waveout_vol );
1130 #endif
1131
1132     i_waveout_vol &= 0xFFFF;
1133     *pi_volume = p_aout->output.i_volume =
1134         (i_waveout_vol * AOUT_VOLUME_MAX + 0xFFFF /*rounding*/) / 2 / 0xFFFF;
1135     return 0;
1136 }
1137
1138 static int VolumeSet( aout_instance_t * p_aout, audio_volume_t i_volume )
1139 {
1140     unsigned long i_waveout_vol = i_volume * 0xFFFF * 2 / AOUT_VOLUME_MAX;
1141     i_waveout_vol |= (i_waveout_vol << 16);
1142
1143 #ifdef UNDER_CE
1144     waveOutSetVolume( 0, i_waveout_vol );
1145 #else
1146     waveOutSetVolume( p_aout->output.p_sys->h_waveout, i_waveout_vol );
1147 #endif
1148
1149     p_aout->output.i_volume = i_volume;
1150     return 0;
1151 }
1152
1153
1154 /*
1155   reload the configuration drop down list, of the Audio Devices
1156 */
1157 static int ReloadWaveoutDevices( vlc_object_t *p_this, char const *psz_name,
1158                                  vlc_value_t newval, vlc_value_t oldval, void *data )
1159 {
1160     int i;
1161
1162     module_config_t *p_item = config_FindConfig( p_this, psz_name );
1163     if( !p_item ) return VLC_SUCCESS;
1164
1165     /* Clear-up the current list */
1166     if( p_item->i_list )
1167     {
1168         /* Keep the first entry */
1169         for( i = 1; i < p_item->i_list; i++ )
1170         {
1171             free((char *)(p_item->ppsz_list[i]) );
1172             free((char *)(p_item->ppsz_list_text[i]) );
1173         }
1174         /* TODO: Remove when no more needed */
1175         p_item->ppsz_list[i] = NULL;
1176         p_item->ppsz_list_text[i] = NULL;
1177     }
1178     p_item->i_list = 1;
1179
1180     int wave_devices = waveOutGetNumDevs();
1181
1182     p_item->ppsz_list =
1183         (char **)realloc( p_item->ppsz_list,
1184                           (wave_devices+2) * sizeof(char *) );
1185     p_item->ppsz_list_text =
1186         (char **)realloc( p_item->ppsz_list_text,
1187                           (wave_devices+2) * sizeof(char *) );
1188
1189     WAVEOUTCAPS caps;
1190     char sz_dev_name[MAXPNAMELEN+32];
1191     int j=1;
1192     for(int i=0; i<wave_devices; i++)
1193     {
1194         if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
1195            == MMSYSERR_NOERROR)
1196         {
1197           sprintf( sz_dev_name, psz_device_name_fmt, caps.szPname,
1198                                                caps.wMid,
1199                                                caps.wPid
1200                                               );
1201           p_item->ppsz_list[j] = FromLocaleDup( sz_dev_name );
1202           p_item->ppsz_list_text[j] = FromLocaleDup( sz_dev_name );
1203           p_item->i_list++;
1204           j++;
1205         }
1206
1207     }
1208     p_item->ppsz_list[j] = NULL;
1209     p_item->ppsz_list_text[j] = NULL;
1210
1211     /* Signal change to the interface */
1212     p_item->b_dirty = true;
1213
1214     return VLC_SUCCESS;
1215 }
1216
1217 /*
1218   convert devicename to device ID for output
1219   if device not found return WAVE_MAPPER, so let
1220   windows decide which preferred audio device
1221   should be used.
1222 */
1223 static uint32_t findDeviceID(char *psz_device_name)
1224 {
1225     if(!psz_device_name)
1226        return WAVE_MAPPER;
1227
1228     uint32_t wave_devices = waveOutGetNumDevs();
1229     WAVEOUTCAPS caps;
1230     char sz_dev_name[MAXPNAMELEN+32];
1231     for(uint32_t i=0; i<wave_devices; i++)
1232     {
1233         if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
1234            == MMSYSERR_NOERROR)
1235         {
1236             sprintf(sz_dev_name, psz_device_name_fmt, caps.szPname,
1237                                                caps.wMid,
1238                                                caps.wPid
1239                                               );
1240             char *psz_temp = FromLocaleDup(sz_dev_name);
1241
1242             if( !stricmp(psz_temp, psz_device_name) )
1243             {
1244                 LocaleFree( psz_temp );
1245                 return i;
1246             }
1247             LocaleFree( psz_temp );
1248         }
1249     }
1250
1251     return WAVE_MAPPER;
1252 }