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