]> git.sesse.net Git - vlc/blob - modules/audio_output/waveout.c
auhal: fix cf0fafe6
[vlc] / modules / audio_output / waveout.c
1 /*****************************************************************************
2  * waveout.c : Windows waveOut plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2001-2009 VLC authors and VideoLAN
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 it
11  * under the terms of the GNU Lesser General Public License as published by
12  * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * along with this program; if not, write to the Free Software Foundation,
22  * 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 <stdio.h>
34 #include <math.h>
35 #include <wchar.h>
36
37 #define UNICODE
38 #include <vlc_common.h>
39 #include <vlc_plugin.h>
40 #include <vlc_aout.h>
41 #include <vlc_charset.h> /* FromWide() */
42 #include <vlc_atomic.h>
43
44 #include "windows_audio_common.h"
45
46 #define FRAME_SIZE 4096              /* The size is in samples, not in bytes */
47
48 /*****************************************************************************
49  * Local prototypes
50  *****************************************************************************/
51 static int  Open         ( vlc_object_t * );
52 static void Close        ( vlc_object_t * );
53 static void Play         ( audio_output_t *, block_t * );
54
55 /*****************************************************************************
56  * notification_thread_t: waveOut event thread
57  *****************************************************************************/
58 struct lkwavehdr
59 {
60     WAVEHDR hdr;
61     struct lkwavehdr * p_next;
62 };
63
64 /* local functions */
65 static int OpenWaveOut   ( audio_output_t *, uint32_t,
66                            int, int, int, int, bool );
67 static int OpenWaveOutPCM( audio_output_t *, uint32_t,
68                            vlc_fourcc_t*, int, int, int, bool );
69 static int PlayWaveOut   ( audio_output_t *, HWAVEOUT, struct lkwavehdr *,
70                            block_t *, bool );
71
72 static void CALLBACK WaveOutCallback ( HWAVEOUT, UINT, DWORD_PTR, DWORD_PTR, DWORD_PTR );
73
74 static void WaveOutClean( aout_sys_t * p_sys );
75
76 static void WaveOutClearBuffer( HWAVEOUT, WAVEHDR *);
77
78 static int ReloadWaveoutDevices( vlc_object_t *, const char *,
79                                  char ***, char *** );
80 static uint32_t findDeviceID(char *);
81 static int WaveOutTimeGet(audio_output_t * , mtime_t *);
82 static void WaveOutFlush( audio_output_t *, bool);
83 static void WaveOutPause( audio_output_t *, bool, mtime_t);
84 static int WaveoutVolumeSet(audio_output_t * p_aout, float volume);
85 static int WaveoutMuteSet(audio_output_t * p_aout, bool mute);
86
87 static void WaveoutPollVolume( void * );
88
89 static const wchar_t device_name_fmt[] = L"%ls ($%x,$%x)";
90
91 /*****************************************************************************
92  * aout_sys_t: waveOut audio output method descriptor
93  *****************************************************************************
94  * This structure is part of the audio output thread descriptor.
95  * It describes the waveOut specific properties of an audio device.
96  *****************************************************************************/
97
98 struct aout_sys_t
99 {
100     uint32_t i_wave_device_id;               /* ID of selected output device */
101
102     HWAVEOUT h_waveout;                        /* handle to waveout instance */
103
104     WAVEFORMATEXTENSIBLE waveformat;                         /* audio format */
105
106     size_t i_frames;
107
108     int i_repeat_counter;
109
110     int i_buffer_size;
111
112     int i_rate;
113
114     uint8_t *p_silence_buffer;              /* buffer we use to play silence */
115
116     float f_volume;
117
118     bool b_spdif;
119     bool b_mute;
120     bool b_soft;                            /* Use software gain */
121     uint8_t chans_to_reorder;              /* do we need channel reordering */
122
123     uint8_t chan_table[AOUT_CHAN_MAX];
124     vlc_fourcc_t format;
125
126     mtime_t i_played_length;
127
128     struct lkwavehdr * p_free_list;
129
130     vlc_mutex_t lock;
131     vlc_cond_t cond;
132     vlc_timer_t volume_poll_timer;
133 };
134
135 /*****************************************************************************
136  * Module descriptor
137  *****************************************************************************/
138 #define DEVICE_TEXT N_("Select Audio Device")
139 #define DEVICE_LONG N_("Select special Audio device, or let windows "\
140                        "decide (default), change needs VLC restart "\
141                        "to apply.")
142 #define DEFAULT_AUDIO_DEVICE N_("Default Audio Device")
143
144 #define AUDIO_CHAN_TEXT N_("Audio output channels")
145 #define AUDIO_CHAN_LONGTEXT N_("Channels available for audio output. " \
146     "If the input has more channels than the output, it will be down-mixed. " \
147     "This parameter is ignored when digital pass-through is active.")
148
149 #define VOLUME_TEXT N_("Audio volume")
150
151 vlc_module_begin ()
152     set_shortname( "WaveOut" )
153     set_description( N_("Win32 waveOut extension output") )
154     set_capability( "audio output", 50 )
155     set_category( CAT_AUDIO )
156     set_subcategory( SUBCAT_AUDIO_AOUT )
157     add_string( "waveout-audio-device", "wavemapper",
158                  DEVICE_TEXT, DEVICE_LONG, false )
159        change_string_cb( ReloadWaveoutDevices )
160     add_float( "waveout-volume", 1.0f, VOLUME_TEXT, NULL, true )
161          change_float_range(0.0f, 2.0f)
162     add_bool( "waveout-float32", true, FLOAT_TEXT, FLOAT_LONGTEXT, true )
163     add_integer ("waveout-audio-channels", 6, AUDIO_CHAN_TEXT,
164                  AUDIO_CHAN_LONGTEXT, false)
165         change_integer_range(1,6)
166     set_callbacks( Open, Close )
167 vlc_module_end ()
168
169 /*****************************************************************************
170  * Opens the audio device
171  *****************************************************************************
172  * This function opens and setups Win32 waveOut
173  *****************************************************************************/
174 static int Start( audio_output_t *p_aout, audio_sample_format_t *restrict fmt )
175 {
176     vlc_value_t val;
177
178     p_aout->time_get = WaveOutTimeGet;
179     p_aout->play = Play;
180     p_aout->pause = WaveOutPause;
181     p_aout->flush = WaveOutFlush;
182
183     /* Default behaviour is to use software gain */
184     p_aout->sys->b_soft = true;
185
186     /*
187       check for configured audio device!
188     */
189     fmt->i_format = var_InheritBool( p_aout, "waveout-float32" )?
190         VLC_CODEC_FL32: VLC_CODEC_S16N;
191
192     char *psz_waveout_dev = var_CreateGetString( p_aout, "waveout-audio-device");
193
194     p_aout->sys->i_wave_device_id =
195          findDeviceID( psz_waveout_dev );
196
197     if(p_aout->sys->i_wave_device_id == WAVE_MAPPER)
198     {
199        if(psz_waveout_dev &&
200           stricmp(psz_waveout_dev,"wavemapper"))
201        {
202            msg_Warn( p_aout, "configured audio device '%s' not available, "\
203                          "use default instead", psz_waveout_dev );
204        }
205     }
206     free( psz_waveout_dev );
207
208
209     WAVEOUTCAPS waveoutcaps;
210     if(waveOutGetDevCaps( p_aout->sys->i_wave_device_id,
211                           &waveoutcaps,
212                           sizeof(WAVEOUTCAPS)) == MMSYSERR_NOERROR)
213     {
214       /* log debug some infos about driver, to know who to blame
215          if it doesn't work */
216         msg_Dbg( p_aout, "Drivername: %ls", waveoutcaps.szPname);
217         msg_Dbg( p_aout, "Driver Version: %d.%d",
218                           (waveoutcaps.vDriverVersion>>8)&255,
219                           waveoutcaps.vDriverVersion & 255);
220         msg_Dbg( p_aout, "Manufacturer identifier: 0x%x", waveoutcaps.wMid );
221         msg_Dbg( p_aout, "Product identifier: 0x%x", waveoutcaps.wPid );
222     }
223
224
225
226     /* Open the device */
227     if( AOUT_FMT_SPDIF(fmt) && var_InheritBool (p_aout, "spdif") )
228     {
229
230         if( OpenWaveOut( p_aout, p_aout->sys->i_wave_device_id,
231                          VLC_CODEC_SPDIFL, fmt->i_physical_channels,
232                          aout_FormatNbChannels( fmt ), fmt->i_rate, false )
233             == VLC_SUCCESS )
234         {
235             fmt->i_format = VLC_CODEC_SPDIFL;
236
237             /* Calculate the frame size in bytes */
238             fmt->i_bytes_per_frame = AOUT_SPDIF_SIZE;
239             fmt->i_frame_length = A52_FRAME_NB;
240             p_aout->sys->i_buffer_size = fmt->i_bytes_per_frame;
241             p_aout->sys->b_spdif = true;
242
243         }
244         else
245             msg_Err( p_aout,
246                      "cannot open waveout audio device for spdif fallback to PCM" );
247     }
248
249     if( fmt->i_format != VLC_CODEC_SPDIFL )
250     {
251         int max_chan = var_InheritInteger( p_aout, "waveout-audio-channels");
252         int i_channels = aout_FormatNbChannels(fmt);
253         i_channels = ( i_channels < max_chan )? i_channels: max_chan;
254         do
255         {
256             switch(i_channels)
257             {
258                 case 6:
259                     fmt->i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
260                         | AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT
261                         | AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE;
262                     break;
263                 case 5:
264                     fmt->i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
265                         | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
266                         | AOUT_CHAN_LFE;
267                     break;
268                 case 4:
269                     fmt->i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
270                         | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
271                     break;
272                 case 3:
273                     fmt->i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
274                         | AOUT_CHAN_LFE;
275                     break;
276                 case 2:
277                     fmt->i_physical_channels = AOUT_CHANS_STEREO;
278                     break;
279                 case 1:
280                 default:
281                     fmt->i_physical_channels = AOUT_CHAN_CENTER;
282             }
283             msg_Dbg( p_aout, "Trying %d channels", i_channels );
284         }
285         while( ( OpenWaveOutPCM( p_aout, p_aout->sys->i_wave_device_id,
286                                  &fmt->i_format, fmt->i_physical_channels,
287                                  i_channels, fmt->i_rate, false ) != VLC_SUCCESS ) &&
288                --i_channels );
289
290         if( !i_channels )
291         {
292             msg_Err(p_aout, "Waveout couldn't find appropriate channel mapping");
293             return VLC_EGENERIC;
294         }
295
296         /* Calculate the frame size in bytes */
297         aout_FormatPrepare( fmt );
298         p_aout->sys->i_buffer_size = FRAME_SIZE * fmt->i_bytes_per_frame;
299
300         if( waveoutcaps.dwSupport & WAVECAPS_VOLUME )
301         {
302             aout_GainRequest( p_aout, 1.0f );
303             p_aout->sys->b_soft = false;
304         }
305
306         WaveoutMuteSet( p_aout, p_aout->sys->b_mute );
307
308         p_aout->sys->b_spdif = false;
309     }
310
311     p_aout->sys->i_rate = fmt->i_rate;
312
313     waveOutReset( p_aout->sys->h_waveout );
314
315     /* Allocate silence buffer */
316     p_aout->sys->p_silence_buffer =
317         malloc( p_aout->sys->i_buffer_size );
318     if( p_aout->sys->p_silence_buffer == NULL )
319     {
320         msg_Err( p_aout, "Couldn't alloc silence buffer... aborting");
321         return VLC_ENOMEM;
322     }
323     p_aout->sys->i_repeat_counter = 0;
324
325
326     /* Zero the buffer. WinCE doesn't have calloc(). */
327     memset( p_aout->sys->p_silence_buffer, 0,
328             p_aout->sys->i_buffer_size );
329
330     /* Now we need to setup our waveOut play notification structure */
331     p_aout->sys->i_frames = 0;
332     p_aout->sys->i_played_length = 0;
333     p_aout->sys->p_free_list = NULL;
334
335     return VLC_SUCCESS;
336 }
337
338 /*****************************************************************************
339  * Play: play a sound buffer
340  *****************************************************************************
341  * This doesn't actually play the buffer. This just stores the buffer so it
342  * can be played by the callback thread.
343  *****************************************************************************/
344 static void Play( audio_output_t *p_aout, block_t *block )
345 {
346     struct lkwavehdr * p_waveheader =
347         (struct lkwavehdr *) malloc(sizeof(struct lkwavehdr));
348     if(!p_waveheader)
349     {
350         msg_Err(p_aout, "Couldn't alloc WAVEHDR");
351         if( block )
352             block_Release( block );
353         return;
354     }
355
356     p_waveheader->p_next = NULL;
357
358     if( block && p_aout->sys->chans_to_reorder )
359     {
360         aout_ChannelReorder( block->p_buffer, block->i_buffer,
361                              p_aout->sys->waveformat.Format.nChannels,
362                              p_aout->sys->chan_table, p_aout->sys->format );
363     }
364     while( PlayWaveOut( p_aout, p_aout->sys->h_waveout, p_waveheader, block,
365                         p_aout->sys->b_spdif ) != VLC_SUCCESS )
366
367     {
368         msg_Warn( p_aout, "Couln't write frame... sleeping");
369         msleep( block->i_length );
370     }
371
372     WaveOutClean( p_aout->sys );
373     WaveoutPollVolume( p_aout );
374
375     vlc_mutex_lock( &p_aout->sys->lock );
376     p_aout->sys->i_frames++;
377     p_aout->sys->i_played_length += block->i_length;
378     vlc_mutex_unlock( &p_aout->sys->lock );
379 }
380
381 /*****************************************************************************
382  * Close: close the audio device
383  *****************************************************************************/
384 static void Stop( audio_output_t *p_aout )
385 {
386     aout_sys_t *p_sys = p_aout->sys;
387
388     /* Before calling waveOutClose we must reset the device */
389     MMRESULT result = waveOutReset( p_sys->h_waveout );
390     if(result != MMSYSERR_NOERROR)
391     {
392        msg_Err( p_aout, "waveOutReset failed 0x%x", result );
393        /*
394         now we must wait, that all buffers are played
395         because cancel doesn't work in this case...
396        */
397        if(result == MMSYSERR_NOTSUPPORTED)
398        {
399            /*
400              clear currently played (done) buffers,
401              if returnvalue > 0 (means some buffer still playing)
402              wait for the driver event callback that one buffer
403              is finished with playing, and check again
404              the timeout of 5000ms is just, an emergency exit
405              of this loop, to avoid deadlock in case of other
406              (currently not known bugs, problems, errors cases?)
407            */
408             WaveOutFlush( p_aout, true );
409        }
410     }
411
412     /* wait for the frames to be queued in cleaning list */
413     WaveOutFlush( p_aout, true );
414     WaveOutClean( p_aout->sys );
415
416     /* now we can Close the device */
417     if( waveOutClose( p_sys->h_waveout ) != MMSYSERR_NOERROR )
418     {
419         msg_Err( p_aout, "waveOutClose failed" );
420     }
421
422     free( p_sys->p_silence_buffer );
423     p_aout->sys->i_played_length = 0;
424     p_sys->b_soft = true;
425 }
426
427 /*****************************************************************************
428  * OpenWaveOut: open the waveout sound device
429  ****************************************************************************/
430 static int OpenWaveOut( audio_output_t *p_aout, uint32_t i_device_id, int i_format,
431                         int i_channels, int i_nb_channels, int i_rate,
432                         bool b_probe )
433 {
434     MMRESULT result;
435
436     /* Set sound format */
437
438 #define waveformat p_aout->sys->waveformat
439
440     waveformat.dwChannelMask = 0;
441     for( unsigned i = 0; pi_vlc_chan_order_wg4[i]; i++ )
442         if( i_channels & pi_vlc_chan_order_wg4[i] )
443             waveformat.dwChannelMask |= pi_channels_in[i];
444
445     switch( i_format )
446     {
447     case VLC_CODEC_SPDIFL:
448         i_nb_channels = 2;
449         /* To prevent channel re-ordering */
450         waveformat.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
451         waveformat.Format.wBitsPerSample = 16;
452         waveformat.Samples.wValidBitsPerSample =
453             waveformat.Format.wBitsPerSample;
454         waveformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
455         waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF;
456         break;
457
458     case VLC_CODEC_FL32:
459         waveformat.Format.wBitsPerSample = sizeof(float) * 8;
460         waveformat.Samples.wValidBitsPerSample =
461             waveformat.Format.wBitsPerSample;
462         waveformat.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
463         waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
464         break;
465
466     case VLC_CODEC_S16N:
467         waveformat.Format.wBitsPerSample = 16;
468         waveformat.Samples.wValidBitsPerSample =
469             waveformat.Format.wBitsPerSample;
470         waveformat.Format.wFormatTag = WAVE_FORMAT_PCM;
471         waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_PCM;
472         break;
473     }
474
475     waveformat.Format.nChannels = i_nb_channels;
476     waveformat.Format.nSamplesPerSec = i_rate;
477     waveformat.Format.nBlockAlign =
478         waveformat.Format.wBitsPerSample / 8 * i_nb_channels;
479     waveformat.Format.nAvgBytesPerSec =
480         waveformat.Format.nSamplesPerSec * waveformat.Format.nBlockAlign;
481
482     /* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */
483     if( i_nb_channels <= 2 )
484     {
485         waveformat.Format.cbSize = 0;
486     }
487     else
488     {
489         waveformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
490         waveformat.Format.cbSize =
491             sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
492     }
493
494     if(!b_probe) {
495         msg_Dbg( p_aout, "OpenWaveDevice-ID: %u", i_device_id);
496         msg_Dbg( p_aout,"waveformat.Format.cbSize          = %d",
497                  waveformat.Format.cbSize);
498         msg_Dbg( p_aout,"waveformat.Format.wFormatTag      = %u",
499                  waveformat.Format.wFormatTag);
500         msg_Dbg( p_aout,"waveformat.Format.nChannels       = %u",
501                  waveformat.Format.nChannels);
502         msg_Dbg( p_aout,"waveformat.Format.nSamplesPerSec  = %d",
503                  (int)waveformat.Format.nSamplesPerSec);
504         msg_Dbg( p_aout,"waveformat.Format.nAvgBytesPerSec = %u",
505                  (int)waveformat.Format.nAvgBytesPerSec);
506         msg_Dbg( p_aout,"waveformat.Format.nBlockAlign     = %d",
507                  waveformat.Format.nBlockAlign);
508         msg_Dbg( p_aout,"waveformat.Format.wBitsPerSample  = %d",
509                  waveformat.Format.wBitsPerSample);
510         msg_Dbg( p_aout,"waveformat.Samples.wValidBitsPerSample = %d",
511                  waveformat.Samples.wValidBitsPerSample);
512         msg_Dbg( p_aout,"waveformat.Samples.wSamplesPerBlock = %d",
513                  waveformat.Samples.wSamplesPerBlock);
514         msg_Dbg( p_aout,"waveformat.dwChannelMask          = %lx",
515                  waveformat.dwChannelMask);
516     }
517
518     /* Open the device */
519     result = waveOutOpen( &p_aout->sys->h_waveout, i_device_id,
520                           (WAVEFORMATEX *)&waveformat,
521                           (DWORD_PTR)WaveOutCallback, (DWORD_PTR)p_aout,
522                           CALLBACK_FUNCTION | (b_probe?WAVE_FORMAT_QUERY:0) );
523     if( result == WAVERR_BADFORMAT )
524     {
525         msg_Warn( p_aout, "waveOutOpen failed WAVERR_BADFORMAT" );
526         return VLC_EGENERIC;
527     }
528     if( result == MMSYSERR_ALLOCATED )
529     {
530         msg_Warn( p_aout, "waveOutOpen failed WAVERR_ALLOCATED" );
531         return VLC_EGENERIC;
532     }
533     if( result != MMSYSERR_NOERROR )
534     {
535         msg_Warn( p_aout, "waveOutOpen failed" );
536         return VLC_EGENERIC;
537     }
538
539     p_aout->sys->chans_to_reorder =
540         aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
541                                   waveformat.dwChannelMask,
542                                   p_aout->sys->chan_table );
543     if( p_aout->sys->chans_to_reorder )
544         msg_Dbg( p_aout, "channel reordering needed" );
545     p_aout->sys->format = i_format;
546
547     return VLC_SUCCESS;
548
549 #undef waveformat
550
551 }
552
553 /*****************************************************************************
554  * OpenWaveOutPCM: open a PCM waveout sound device
555  ****************************************************************************/
556 static int OpenWaveOutPCM( audio_output_t *p_aout, uint32_t i_device_id,
557                            vlc_fourcc_t *i_format,
558                            int i_channels, int i_nb_channels, int i_rate,
559                            bool b_probe )
560 {
561     bool b_use_float32 = var_CreateGetBool( p_aout, "waveout-float32");
562
563     if( !b_use_float32 || OpenWaveOut( p_aout, i_device_id, VLC_CODEC_FL32,
564                                    i_channels, i_nb_channels, i_rate, b_probe )
565         != VLC_SUCCESS )
566     {
567         if ( OpenWaveOut( p_aout, i_device_id, VLC_CODEC_S16N,
568                           i_channels, i_nb_channels, i_rate, b_probe )
569              != VLC_SUCCESS )
570         {
571             return VLC_EGENERIC;
572         }
573         else
574         {
575             *i_format = VLC_CODEC_S16N;
576             return VLC_SUCCESS;
577         }
578     }
579     else
580     {
581         *i_format = VLC_CODEC_FL32;
582         return VLC_SUCCESS;
583     }
584 }
585
586 /*****************************************************************************
587  * PlayWaveOut: play a buffer through the WaveOut device
588  *****************************************************************************/
589 static int PlayWaveOut( audio_output_t *p_aout, HWAVEOUT h_waveout,
590                         struct lkwavehdr *p_waveheader, block_t *p_buffer, bool b_spdif)
591 {
592     MMRESULT result;
593
594     /* Prepare the buffer */
595     if( p_buffer != NULL )
596     {
597         p_waveheader->hdr.lpData = (LPSTR)p_buffer->p_buffer;
598         p_waveheader->hdr.dwBufferLength = p_buffer->i_buffer;
599         /*
600           copy the buffer to the silence buffer :) so in case we don't
601           get the next buffer fast enough (I will repeat this one a time
602           for AC3 / DTS and SPDIF this will sound better instead of
603           a hickup)
604         */
605         if(b_spdif)
606         {
607            memcpy( p_aout->sys->p_silence_buffer,
608                        p_buffer->p_buffer,
609                        p_aout->sys->i_buffer_size );
610            p_aout->sys->i_repeat_counter = 2;
611         }
612     } else {
613         /* Use silence buffer instead */
614         if(p_aout->sys->i_repeat_counter)
615         {
616            p_aout->sys->i_repeat_counter--;
617            if(!p_aout->sys->i_repeat_counter)
618            {
619                memset( p_aout->sys->p_silence_buffer,
620                            0x00, p_aout->sys->i_buffer_size );
621            }
622         }
623         p_waveheader->hdr.lpData = (LPSTR)p_aout->sys->p_silence_buffer;
624         p_waveheader->hdr.dwBufferLength = p_aout->sys->i_buffer_size;
625     }
626
627     p_waveheader->hdr.dwUser = p_buffer ? (DWORD_PTR)p_buffer : (DWORD_PTR)1;
628     p_waveheader->hdr.dwFlags = 0;
629
630     result = waveOutPrepareHeader( h_waveout, &p_waveheader->hdr, sizeof(WAVEHDR) );
631     if( result != MMSYSERR_NOERROR )
632     {
633         msg_Err( p_aout, "waveOutPrepareHeader failed" );
634         return VLC_EGENERIC;
635     }
636
637     /* Send the buffer to the waveOut queue */
638     result = waveOutWrite( h_waveout, &p_waveheader->hdr, sizeof(WAVEHDR) );
639     if( result != MMSYSERR_NOERROR )
640     {
641         msg_Err( p_aout, "waveOutWrite failed" );
642         return VLC_EGENERIC;
643     }
644
645     return VLC_SUCCESS;
646 }
647
648 /*****************************************************************************
649  * WaveOutCallback: what to do once WaveOut has played its sound samples
650  *****************************************************************************/
651 static void CALLBACK WaveOutCallback( HWAVEOUT h_waveout, UINT uMsg,
652                                       DWORD_PTR _p_aout,
653                                       DWORD_PTR dwParam1, DWORD_PTR dwParam2 )
654 {
655     (void) h_waveout;
656     (void) dwParam2;
657     audio_output_t *p_aout = (audio_output_t *)_p_aout;
658     struct lkwavehdr * p_waveheader =  (struct lkwavehdr *) dwParam1;
659
660     if( uMsg != WOM_DONE ) return;
661
662     vlc_mutex_lock( &p_aout->sys->lock );
663     p_waveheader->p_next = p_aout->sys->p_free_list;
664     p_aout->sys->p_free_list = p_waveheader;
665     p_aout->sys->i_frames--;
666     vlc_cond_broadcast( &p_aout->sys->cond );
667     vlc_mutex_unlock( &p_aout->sys->lock );
668 }
669
670 static void WaveOutClean( aout_sys_t * p_sys )
671 {
672     struct lkwavehdr *p_whdr, *p_list;
673
674     vlc_mutex_lock(&p_sys->lock);
675     p_list =  p_sys->p_free_list;
676     p_sys->p_free_list = NULL;
677     vlc_mutex_unlock(&p_sys->lock);
678
679     while( p_list )
680     {
681         p_whdr = p_list;
682         p_list = p_list->p_next;
683         WaveOutClearBuffer( p_sys->h_waveout, &p_whdr->hdr );
684         free(p_whdr);
685     }
686 }
687
688 static void WaveOutClearBuffer( HWAVEOUT h_waveout, WAVEHDR *p_waveheader )
689 {
690     block_t *p_buffer = (block_t *)(p_waveheader->dwUser);
691     /* Unprepare and free the buffers which has just been played */
692     waveOutUnprepareHeader( h_waveout, p_waveheader, sizeof(WAVEHDR) );
693
694     if( p_waveheader->dwUser != 1 )
695         block_Release( p_buffer );
696 }
697
698 /*
699   reload the configuration drop down list, of the Audio Devices
700 */
701 static int ReloadWaveoutDevices( vlc_object_t *p_this, char const *psz_name,
702                                  char ***values, char ***descs )
703 {
704     int n = 0, nb_devices = waveOutGetNumDevs();
705
706     VLC_UNUSED( p_this); VLC_UNUSED( psz_name );
707
708     *values = xmalloc( (nb_devices + 1) * sizeof(char *) );
709     *descs = xmalloc( (nb_devices + 1) * sizeof(char *) );
710
711     (*values)[n] = strdup( "wavemapper" );
712     (*descs)[n] = strdup( _("Microsoft Soundmapper") );
713     n++;
714
715     for(int i = 0; i < nb_devices; i++)
716     {
717         WAVEOUTCAPS caps;
718         wchar_t dev_name[MAXPNAMELEN+32];
719
720         if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
721                                                            != MMSYSERR_NOERROR)
722             continue;
723
724         _snwprintf(dev_name, MAXPNAMELEN + 32, device_name_fmt,
725                    caps.szPname, caps.wMid, caps.wPid);
726         (*values)[n] = FromWide( dev_name );
727         (*descs)[n] = strdup( (*values)[n] );
728         n++;
729     }
730
731     return n;
732 }
733
734 /*
735   convert devicename to device ID for output
736   if device not found return WAVE_MAPPER, so let
737   windows decide which preferred audio device
738   should be used.
739 */
740 static uint32_t findDeviceID(char *psz_device_name)
741 {
742     if( !psz_device_name )
743        return WAVE_MAPPER;
744
745     uint32_t wave_devices = waveOutGetNumDevs();
746
747     for( uint32_t i = 0; i < wave_devices; i++ )
748     {
749         WAVEOUTCAPS caps;
750         wchar_t dev_name[MAXPNAMELEN+32];
751
752         if( waveOutGetDevCaps( i, &caps, sizeof(WAVEOUTCAPS) )
753                                                           != MMSYSERR_NOERROR )
754             continue;
755
756         _snwprintf( dev_name, MAXPNAMELEN + 32, device_name_fmt,
757                   caps.szPname, caps.wMid, caps.wPid );
758         char *u8 = FromWide(dev_name);
759         if( !stricmp(u8, psz_device_name) )
760         {
761             free( u8 );
762             return i;
763         }
764         free( u8 );
765     }
766
767     return WAVE_MAPPER;
768 }
769
770 static int Open(vlc_object_t *obj)
771 {
772     audio_output_t *aout = (audio_output_t *)obj;
773     aout_sys_t *sys = malloc(sizeof (*sys));
774
775     if (unlikely(sys == NULL))
776         return VLC_ENOMEM;
777     aout->sys = sys;
778     aout->start = Start;
779     aout->stop = Stop;
780     aout->volume_set = WaveoutVolumeSet;
781     aout->mute_set = WaveoutMuteSet;
782
783     sys->f_volume = var_InheritFloat(aout, "waveout-volume");
784     sys->b_mute = var_InheritBool(aout, "mute");
785
786     aout_MuteReport(aout, sys->b_mute);
787     aout_VolumeReport(aout, sys->f_volume );
788
789     if( vlc_timer_create( &sys->volume_poll_timer,
790                           WaveoutPollVolume, aout ) )
791     {
792         msg_Err( aout, "Couldn't create volume polling timer" );
793         free( sys );
794         return VLC_ENOMEM;
795     }
796
797     vlc_mutex_init( &sys->lock );
798     vlc_cond_init( &sys->cond );
799
800     return VLC_SUCCESS;
801 }
802
803 static void Close(vlc_object_t *obj)
804 {
805     audio_output_t *aout = (audio_output_t *)obj;
806     aout_sys_t *sys = aout->sys;
807
808     vlc_timer_destroy( sys->volume_poll_timer );
809
810     vlc_cond_destroy( &sys->cond );
811     vlc_mutex_destroy( &sys->lock );
812
813     free(sys);
814 }
815
816 static int WaveOutTimeGet(audio_output_t * p_aout, mtime_t *delay)
817 {
818     MMTIME mmtime;
819     mmtime.wType = TIME_SAMPLES;
820
821     if( !p_aout->sys->i_frames )
822         return -1;
823
824     if( waveOutGetPosition( p_aout->sys->h_waveout, &mmtime, sizeof(MMTIME) )
825             != MMSYSERR_NOERROR )
826     {
827         msg_Err( p_aout, "waveOutGetPosition failed");
828         return -1;
829     }
830
831     mtime_t i_pos = (mtime_t) mmtime.u.sample * CLOCK_FREQ / p_aout->sys->i_rate;
832     *delay = p_aout->sys->i_played_length - i_pos;
833     return 0;
834 }
835
836 static void WaveOutFlush( audio_output_t *p_aout, bool wait)
837 {
838     MMRESULT res;
839     if( !wait )
840     {
841         res  = waveOutReset( p_aout->sys->h_waveout );
842         p_aout->sys->i_played_length = 0;
843         if( res != MMSYSERR_NOERROR )
844             msg_Err( p_aout, "waveOutReset failed");
845     }
846     else
847     {
848         vlc_mutex_lock( &p_aout->sys->lock );
849         while( p_aout->sys->i_frames )
850         {
851             vlc_cond_wait( &p_aout->sys->cond, &p_aout->sys-> lock );
852         }
853         vlc_mutex_unlock( &p_aout->sys->lock );
854     }
855 }
856
857 static void WaveOutPause( audio_output_t * p_aout, bool pause, mtime_t date)
858 {
859     MMRESULT res;
860     (void) date;
861     if(pause)
862     {
863         vlc_timer_schedule( p_aout->sys->volume_poll_timer, false, 1, 200000 );
864         res = waveOutPause( p_aout->sys->h_waveout );
865         if( res != MMSYSERR_NOERROR )
866         {
867             msg_Err( p_aout, "waveOutPause failed (0x%x)", res);
868             return;
869         }
870     }
871     else
872     {
873         vlc_timer_schedule( p_aout->sys->volume_poll_timer, false, 0, 0 );
874         res = waveOutRestart( p_aout->sys->h_waveout );
875         if( res != MMSYSERR_NOERROR )
876         {
877             msg_Err( p_aout, "waveOutRestart failed (0x%x)", res);
878             return;
879         }
880     }
881 }
882
883 static int WaveoutVolumeSet( audio_output_t *p_aout, float volume )
884 {
885     aout_sys_t *sys = p_aout->sys;
886
887     if( sys->b_soft )
888     {
889         float gain = volume * volume * volume;
890         if ( !sys->b_mute && aout_GainRequest( p_aout, gain ) )
891             return -1;
892     }
893     else
894     {
895         const HWAVEOUT hwo = sys->h_waveout;
896
897         uint32_t vol = lroundf( volume * 0x7fff.fp0 );
898
899         if( !sys->b_mute )
900         {
901             if( vol > 0xffff )
902             {
903                 vol = 0xffff;
904                 volume = 2.0f;
905             }
906
907             MMRESULT r = waveOutSetVolume( hwo, vol | ( vol << 16 ) );
908             if( r != MMSYSERR_NOERROR )
909             {
910                 msg_Err( p_aout, "waveOutSetVolume failed (%u)", r );
911                 return -1;
912             }
913         }
914     }
915
916     vlc_mutex_lock(&p_aout->sys->lock);
917     sys->f_volume = volume;
918
919     if( var_InheritBool( p_aout, "volume-save" ) )
920         config_PutFloat( p_aout, "waveout-volume", volume );
921
922     aout_VolumeReport( p_aout, volume );
923     vlc_mutex_unlock(&p_aout->sys->lock);
924
925     return 0;
926 }
927
928 static int WaveoutMuteSet( audio_output_t * p_aout, bool mute )
929 {
930     aout_sys_t *sys = p_aout->sys;
931
932     if( sys->b_soft )
933     {
934         float gain = sys->f_volume * sys->f_volume * sys->f_volume;
935         if ( aout_GainRequest( p_aout, mute ? 0.f : gain ) )
936             return -1;
937     }
938     else
939     {
940
941         const HWAVEOUT hwo = sys->h_waveout;
942         uint32_t vol = mute ? 0 : lroundf( sys->f_volume * 0x7fff.fp0 );
943
944         if( vol > 0xffff )
945             vol = 0xffff;
946
947         MMRESULT r = waveOutSetVolume( hwo, vol | ( vol << 16 ) );
948         if( r != MMSYSERR_NOERROR )
949         {
950             msg_Err( p_aout, "waveOutSetVolume failed (%u)", r );
951             return -1;
952         }
953     }
954
955     vlc_mutex_lock(&p_aout->sys->lock);
956     sys->b_mute = mute;
957     aout_MuteReport( p_aout, mute );
958     vlc_mutex_unlock(&p_aout->sys->lock);
959
960     return 0;
961 }
962
963 static void WaveoutPollVolume( void * aout )
964 {
965     audio_output_t * p_aout = (audio_output_t *) aout;
966     uint32_t vol;
967
968     MMRESULT r = waveOutGetVolume( p_aout->sys->h_waveout, (LPDWORD) &vol );
969
970     if( r != MMSYSERR_NOERROR )
971     {
972         msg_Err( p_aout, "waveOutGetVolume failed (%u)", r );
973         return;
974     }
975
976     float volume = (float) ( vol & UINT32_C( 0xffff ) );
977     volume /= 0x7fff.fp0;
978
979     vlc_mutex_lock(&p_aout->sys->lock);
980     if( !p_aout->sys->b_mute && volume != p_aout->sys->f_volume )
981     {
982         p_aout->sys->f_volume = volume;
983
984         if( var_InheritBool( p_aout, "volume-save" ) )
985             config_PutFloat( p_aout, "waveout-volume", volume );
986
987         aout_VolumeReport( p_aout, volume );
988     }
989     vlc_mutex_unlock(&p_aout->sys->lock);
990
991     return;
992 }