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