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