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