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