]> git.sesse.net Git - vlc/blob - modules/audio_output/waveout.c
592fc9d48085d7f27cc1c83ace84f8c53431d6b0
[vlc] / modules / audio_output / waveout.c
1 /*****************************************************************************
2  * waveout.c : Windows waveOut plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2001-2009 the VideoLAN team
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
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 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 General Public License for more details.
19  *
20  * You should have received a copy of the GNU 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_aout_intf.h>
42 #include <vlc_charset.h> /* FromWide() */
43 #include <vlc_atomic.h>
44
45 #include "windows_audio_common.h"
46
47 #define FRAME_SIZE 4096              /* The size is in samples, not in bytes */
48
49 /*****************************************************************************
50  * Local prototypes
51  *****************************************************************************/
52 static int  Open         ( vlc_object_t * );
53 static void Close        ( vlc_object_t * );
54 static void Play         ( audio_output_t *, block_t *, mtime_t * );
55
56 /*****************************************************************************
57  * notification_thread_t: waveOut event thread
58  *****************************************************************************/
59 /* local functions */
60 static void Probe        ( audio_output_t * );
61 static int OpenWaveOut   ( audio_output_t *, uint32_t,
62                            int, int, int, int, bool );
63 static int OpenWaveOutPCM( audio_output_t *, uint32_t,
64                            vlc_fourcc_t*, int, int, int, bool );
65 static int PlayWaveOut   ( audio_output_t *, HWAVEOUT, WAVEHDR *,
66                            block_t *, bool );
67
68 static void CALLBACK WaveOutCallback ( HWAVEOUT, UINT, DWORD_PTR, DWORD_PTR, DWORD_PTR );
69 static void* WaveOutThread( void * );
70
71 static int VolumeSet( audio_output_t *, float );
72 static int MuteSet( audio_output_t *, bool );
73
74 static int WaveOutClearDoneBuffers(aout_sys_t *p_sys);
75
76 static int ReloadWaveoutDevices( vlc_object_t *, char const *,
77                                 vlc_value_t, vlc_value_t, void * );
78 static uint32_t findDeviceID(char *);
79
80 static const wchar_t device_name_fmt[] = L"%ls ($%x,$%x)";
81
82 /*****************************************************************************
83  * aout_sys_t: waveOut audio output method descriptor
84  *****************************************************************************
85  * This structure is part of the audio output thread descriptor.
86  * It describes the waveOut specific properties of an audio device.
87  *****************************************************************************/
88 struct aout_sys_t
89 {
90     aout_packet_t packet;
91     uint32_t i_wave_device_id;               /* ID of selected output device */
92
93     HWAVEOUT h_waveout;                        /* handle to waveout instance */
94
95     WAVEFORMATEXTENSIBLE waveformat;                         /* audio format */
96
97     WAVEHDR waveheader[FRAMES_NUM];
98
99     vlc_thread_t thread;
100     vlc_atomic_t abort;
101     HANDLE event;
102     HANDLE new_buffer_event;
103
104     // rental from alsa.c to synchronize startup of audiothread
105     int b_playing;                                         /* playing status */
106     mtime_t start_date;
107
108     int i_repeat_counter;
109
110     int i_buffer_size;
111
112     uint8_t *p_silence_buffer;              /* buffer we use to play silence */
113
114     union {
115         float volume;
116         float soft_gain;
117     };
118     union {
119         bool mute;
120         bool soft_mute;
121     };
122
123     bool b_chan_reorder;              /* do we need channel reordering */
124     int pi_chan_table[AOUT_CHAN_MAX];
125 };
126
127 #include "volume.h"
128
129 /*****************************************************************************
130  * Module descriptor
131  *****************************************************************************/
132 #define DEVICE_TEXT N_("Select Audio Device")
133 #define DEVICE_LONG N_("Select special Audio device, or let windows "\
134                        "decide (default), change needs VLC restart "\
135                        "to apply.")
136 #define DEFAULT_AUDIO_DEVICE N_("Default Audio Device")
137
138 vlc_module_begin ()
139     set_shortname( "WaveOut" )
140     set_description( N_("Win32 waveOut extension output") )
141     set_capability( "audio output", 50 )
142     set_category( CAT_AUDIO )
143     set_subcategory( SUBCAT_AUDIO_AOUT )
144
145     add_string( "waveout-audio-device", "wavemapper",
146                  DEVICE_TEXT, DEVICE_LONG, false )
147        change_string_cb( ReloadWaveoutDevices )
148     add_sw_gain( )
149
150     add_bool( "waveout-float32", true, FLOAT_TEXT, FLOAT_LONGTEXT, true )
151
152     set_callbacks( Open, Close )
153 vlc_module_end ()
154
155 /*****************************************************************************
156  * Open: open the audio device
157  *****************************************************************************
158  * This function opens and setups Win32 waveOut
159  *****************************************************************************/
160 static int Open( vlc_object_t *p_this )
161 {
162     audio_output_t *p_aout = (audio_output_t *)p_this;
163     vlc_value_t val;
164
165     /* Allocate structure */
166     p_aout->sys = malloc( sizeof( aout_sys_t ) );
167
168     if( p_aout->sys == NULL )
169         return VLC_ENOMEM;
170
171     p_aout->pf_play = Play;
172     p_aout->pf_pause = aout_PacketPause;
173     p_aout->pf_flush = aout_PacketFlush;
174
175     /*
176      initialize/update Device selection List
177     */
178     ReloadWaveoutDevices( p_this, "waveout-audio-device", val, val, NULL);
179
180     /*
181       check for configured audio device!
182     */
183     char *psz_waveout_dev = var_CreateGetString( p_aout, "waveout-audio-device");
184
185     p_aout->sys->i_wave_device_id =
186          findDeviceID( psz_waveout_dev );
187
188     if(p_aout->sys->i_wave_device_id == WAVE_MAPPER)
189     {
190        if(psz_waveout_dev &&
191           stricmp(psz_waveout_dev,"wavemapper"))
192        {
193            msg_Warn( p_aout, "configured audio device '%s' not available, "\
194                          "use default instead", psz_waveout_dev );
195        }
196     }
197     free( psz_waveout_dev );
198
199
200     WAVEOUTCAPS waveoutcaps;
201     if(waveOutGetDevCaps( p_aout->sys->i_wave_device_id,
202                           &waveoutcaps,
203                           sizeof(WAVEOUTCAPS)) == MMSYSERR_NOERROR)
204     {
205       /* log debug some infos about driver, to know who to blame
206          if it doesn't work */
207         msg_Dbg( p_aout, "Drivername: %ls", waveoutcaps.szPname);
208         msg_Dbg( p_aout, "Driver Version: %d.%d",
209                           (waveoutcaps.vDriverVersion>>8)&255,
210                           waveoutcaps.vDriverVersion & 255);
211         msg_Dbg( p_aout, "Manufacturer identifier: 0x%x", waveoutcaps.wMid );
212         msg_Dbg( p_aout, "Product identifier: 0x%x", waveoutcaps.wPid );
213     }
214
215
216
217     if( var_Type( p_aout, "audio-device" ) == 0 )
218     {
219         Probe( p_aout );
220     }
221
222     if( var_Get( p_aout, "audio-device", &val ) < 0 )
223     {
224         /* Probe() has failed. */
225         var_Destroy( p_aout, "waveout-audio-device");
226         free( p_aout->sys );
227         return VLC_EGENERIC;
228     }
229
230
231     /* Open the device */
232     if( val.i_int == AOUT_VAR_SPDIF )
233     {
234         p_aout->format.i_format = VLC_CODEC_SPDIFL;
235
236         if( OpenWaveOut( p_aout,
237                          p_aout->sys->i_wave_device_id,
238                          VLC_CODEC_SPDIFL,
239                          p_aout->format.i_physical_channels,
240                          aout_FormatNbChannels( &p_aout->format ),
241                          p_aout->format.i_rate, false )
242             != VLC_SUCCESS )
243         {
244             msg_Err( p_aout, "cannot open waveout audio device" );
245             free( p_aout->sys );
246             return VLC_EGENERIC;
247         }
248
249         /* Calculate the frame size in bytes */
250         p_aout->format.i_bytes_per_frame = AOUT_SPDIF_SIZE;
251         p_aout->format.i_frame_length = A52_FRAME_NB;
252         p_aout->sys->i_buffer_size =
253             p_aout->format.i_bytes_per_frame;
254
255         aout_PacketInit( p_aout, &p_aout->sys->packet, A52_FRAME_NB );
256         p_aout->volume_set = NULL;
257         p_aout->mute_set = NULL;
258     }
259     else
260     {
261         WAVEOUTCAPS wocaps;
262
263         switch( val.i_int )
264         {
265         case AOUT_VAR_5_1:
266             p_aout->format.i_physical_channels
267                     = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
268                       | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
269                       | AOUT_CHAN_LFE;
270             break;
271         case AOUT_VAR_2F2R:
272             p_aout->format.i_physical_channels
273                     = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
274                       | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
275             break;
276         case AOUT_VAR_MONO:
277             p_aout->format.i_physical_channels = AOUT_CHAN_CENTER;
278             break;
279         default:
280             p_aout->format.i_physical_channels
281                     = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
282         }
283
284         if( OpenWaveOutPCM( p_aout,
285                             p_aout->sys->i_wave_device_id,
286                             &p_aout->format.i_format,
287                             p_aout->format.i_physical_channels,
288                             aout_FormatNbChannels( &p_aout->format ),
289                             p_aout->format.i_rate, false )
290             != VLC_SUCCESS )
291         {
292             msg_Err( p_aout, "cannot open waveout audio device" );
293             free( p_aout->sys );
294             return VLC_EGENERIC;
295         }
296
297         /* Calculate the frame size in bytes */
298         aout_FormatPrepare( &p_aout->format );
299         p_aout->sys->i_buffer_size = FRAME_SIZE *
300             p_aout->format.i_bytes_per_frame;
301
302         aout_PacketInit( p_aout, &p_aout->sys->packet, FRAME_SIZE );
303
304 #ifndef UNDER_CE
305         /* Check for hardware volume support */
306         if( waveOutGetDevCaps( (UINT_PTR)p_aout->sys->h_waveout,
307                                &wocaps, sizeof(wocaps) ) == MMSYSERR_NOERROR
308          && (wocaps.dwSupport & WAVECAPS_VOLUME) )
309         {
310             p_aout->volume_set = VolumeSet;
311             p_aout->mute_set = MuteSet;
312             p_aout->sys->volume = 0xffff.fp0;
313             p_aout->sys->mute = false;
314         }
315         else
316 #endif
317             aout_SoftVolumeInit( p_aout );
318     }
319
320     waveOutReset( p_aout->sys->h_waveout );
321
322     /* Allocate silence buffer */
323     p_aout->sys->p_silence_buffer =
324         malloc( p_aout->sys->i_buffer_size );
325     if( p_aout->sys->p_silence_buffer == NULL )
326     {
327         aout_PacketDestroy( p_aout );
328         free( p_aout->sys );
329         return VLC_ENOMEM;
330     }
331     p_aout->sys->i_repeat_counter = 0;
332
333
334     /* Zero the buffer. WinCE doesn't have calloc(). */
335     memset( p_aout->sys->p_silence_buffer, 0,
336             p_aout->sys->i_buffer_size );
337
338     /* Now we need to setup our waveOut play notification structure */
339     p_aout->sys->event = CreateEvent( NULL, FALSE, FALSE, NULL );
340     p_aout->sys->new_buffer_event = CreateEvent( NULL, FALSE, FALSE, NULL );
341
342     /* define startpoint of playback on first call to play()
343       like alsa does (instead of playing a blank sample) */
344     p_aout->sys->b_playing = 0;
345     p_aout->sys->start_date = 0;
346
347
348     /* Then launch the notification thread */
349     vlc_atomic_set( &p_aout->sys->abort, 0);
350     if( vlc_clone( &p_aout->sys->thread,
351                    WaveOutThread, p_aout, VLC_THREAD_PRIORITY_OUTPUT ) )
352     {
353         msg_Err( p_aout, "cannot create WaveOutThread" );
354     }
355
356     /* We need to kick off the playback in order to have the callback properly
357      * working */
358     for( int i = 0; i < FRAMES_NUM; i++ )
359     {
360         p_aout->sys->waveheader[i].dwFlags = WHDR_DONE;
361         p_aout->sys->waveheader[i].dwUser = 0;
362     }
363
364     return VLC_SUCCESS;
365 }
366
367 /*****************************************************************************
368  * Probe: probe the audio device for available formats and channels
369  *****************************************************************************/
370 static void Probe( audio_output_t * p_aout )
371 {
372     vlc_value_t val, text;
373     vlc_fourcc_t i_format;
374     unsigned int i_physical_channels;
375
376     var_Create( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
377     text.psz_string = _("Audio Device");
378     var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
379
380     /* Test for 5.1 support */
381     i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
382                           AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
383                           AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE;
384     if( p_aout->format.i_physical_channels == i_physical_channels )
385     {
386         if( OpenWaveOutPCM( p_aout,
387                             p_aout->sys->i_wave_device_id,
388                             &i_format,
389                             i_physical_channels, 6,
390                             p_aout->format.i_rate, true )
391             == VLC_SUCCESS )
392         {
393             val.i_int = AOUT_VAR_5_1;
394             text.psz_string = (char *)_("5.1");
395             var_Change( p_aout, "audio-device",
396                         VLC_VAR_ADDCHOICE, &val, &text );
397             msg_Dbg( p_aout, "device supports 5.1 channels" );
398         }
399     }
400
401     /* Test for 2 Front 2 Rear support */
402     i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
403                           AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
404     if( ( p_aout->format.i_physical_channels & i_physical_channels )
405         == i_physical_channels )
406     {
407         if( OpenWaveOutPCM( p_aout,
408                             p_aout->sys->i_wave_device_id,
409                             &i_format,
410                             i_physical_channels, 4,
411                             p_aout->format.i_rate, true )
412             == VLC_SUCCESS )
413         {
414             val.i_int = AOUT_VAR_2F2R;
415             text.psz_string = (char *)_("2 Front 2 Rear");
416             var_Change( p_aout, "audio-device",
417                         VLC_VAR_ADDCHOICE, &val, &text );
418             msg_Dbg( p_aout, "device supports 4 channels" );
419         }
420     }
421
422     /* Test for stereo support */
423     i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
424     if( OpenWaveOutPCM( p_aout,
425                         p_aout->sys->i_wave_device_id,
426                         &i_format,
427                         i_physical_channels, 2,
428                         p_aout->format.i_rate, true )
429         == VLC_SUCCESS )
430     {
431         val.i_int = AOUT_VAR_STEREO;
432         text.psz_string = (char *)_("Stereo");
433         var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
434         msg_Dbg( p_aout, "device supports 2 channels" );
435     }
436
437     /* Test for mono support */
438     i_physical_channels = AOUT_CHAN_CENTER;
439     if( OpenWaveOutPCM( p_aout,
440                         p_aout->sys->i_wave_device_id,
441                         &i_format,
442                         i_physical_channels, 1,
443                         p_aout->format.i_rate, true )
444         == VLC_SUCCESS )
445     {
446         val.i_int = AOUT_VAR_MONO;
447         text.psz_string = (char *)_("Mono");
448         var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
449         msg_Dbg( p_aout, "device supports 1 channel" );
450     }
451
452     /* Test for SPDIF support */
453     if ( AOUT_FMT_SPDIF( &p_aout->format ) )
454     {
455         if( OpenWaveOut( p_aout,
456                          p_aout->sys->i_wave_device_id,
457                          VLC_CODEC_SPDIFL,
458                          p_aout->format.i_physical_channels,
459                          aout_FormatNbChannels( &p_aout->format ),
460                          p_aout->format.i_rate, true )
461             == VLC_SUCCESS )
462         {
463             msg_Dbg( p_aout, "device supports A/52 over S/PDIF" );
464             val.i_int = AOUT_VAR_SPDIF;
465             text.psz_string = (char *)_("A/52 over S/PDIF");
466             var_Change( p_aout, "audio-device",
467                         VLC_VAR_ADDCHOICE, &val, &text );
468             if( var_InheritBool( p_aout, "spdif" ) )
469                 var_Set( p_aout, "audio-device", val );
470         }
471     }
472
473     var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
474     if( val.i_int <= 0 )
475     {
476         /* Probe() has failed. */
477         var_Destroy( p_aout, "audio-device" );
478         return;
479     }
480
481     var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
482 }
483
484 /*****************************************************************************
485  * Play: play a sound buffer
486  *****************************************************************************
487  * This doesn't actually play the buffer. This just stores the buffer so it
488  * can be played by the callback thread.
489  *****************************************************************************/
490 static void Play( audio_output_t *_p_aout, block_t *block,
491                   mtime_t *restrict drift )
492 {
493     if( !_p_aout->sys->b_playing )
494     {
495         _p_aout->sys->b_playing = 1;
496
497         /* get the playing date of the first aout buffer */
498         _p_aout->sys->start_date = block->i_pts;
499
500         msg_Dbg( _p_aout, "Wakeup sleeping output thread.");
501
502         /* wake up the audio output thread */
503         SetEvent( _p_aout->sys->event );
504     } else {
505         SetEvent( _p_aout->sys->new_buffer_event );
506     }
507
508     aout_PacketPlay( _p_aout, block, drift );
509 }
510
511 /*****************************************************************************
512  * Close: close the audio device
513  *****************************************************************************/
514 static void Close( vlc_object_t *p_this )
515 {
516     audio_output_t *p_aout = (audio_output_t *)p_this;
517     aout_sys_t *p_sys = p_aout->sys;
518
519     /* Before calling waveOutClose we must reset the device */
520     vlc_atomic_set( &p_sys->abort, 1);
521
522     /* wake up the audio thread, to recognize that p_aout died */
523     SetEvent( p_sys->event );
524     SetEvent( p_sys->new_buffer_event );
525
526     vlc_join( p_sys->thread, NULL );
527
528     /*
529       kill the real output then - when the feed thread
530       is surely terminated!
531       old code could be too early in case that "feeding"
532       was running on termination
533
534       at this point now its sure, that there will be no new
535       data send to the driver, and we can cancel the last
536       running playbuffers
537     */
538     MMRESULT result = waveOutReset( p_sys->h_waveout );
539     if(result != MMSYSERR_NOERROR)
540     {
541        msg_Err( p_aout, "waveOutReset failed 0x%x", result );
542        /*
543         now we must wait, that all buffers are played
544         because cancel doesn't work in this case...
545        */
546        if(result == MMSYSERR_NOTSUPPORTED)
547        {
548            /*
549              clear currently played (done) buffers,
550              if returnvalue > 0 (means some buffer still playing)
551              wait for the driver event callback that one buffer
552              is finished with playing, and check again
553              the timeout of 5000ms is just, an emergency exit
554              of this loop, to avoid deadlock in case of other
555              (currently not known bugs, problems, errors cases?)
556            */
557            while(
558                  (WaveOutClearDoneBuffers( p_sys ) > 0)
559                  &&
560                  (WaitForSingleObject( p_sys->event, 5000) == WAIT_OBJECT_0)
561                 )
562            {
563                  msg_Dbg( p_aout, "Wait for waveout device...");
564            }
565        }
566     } else {
567         WaveOutClearDoneBuffers( p_sys );
568     }
569
570     /* now we can Close the device */
571     if( waveOutClose( p_sys->h_waveout ) != MMSYSERR_NOERROR )
572     {
573         msg_Err( p_aout, "waveOutClose failed" );
574     }
575
576     /*
577       because so long, the waveout device is playing, the callback
578       could occur and need the events
579     */
580     CloseHandle( p_sys->event );
581     CloseHandle( p_sys->new_buffer_event);
582
583     free( p_sys->p_silence_buffer );
584     aout_PacketDestroy( p_aout );
585     free( p_sys );
586 }
587
588 /*****************************************************************************
589  * OpenWaveOut: open the waveout sound device
590  ****************************************************************************/
591 static int OpenWaveOut( audio_output_t *p_aout, uint32_t i_device_id, int i_format,
592                         int i_channels, int i_nb_channels, int i_rate,
593                         bool b_probe )
594 {
595     MMRESULT result;
596
597     /* Set sound format */
598
599 #define waveformat p_aout->sys->waveformat
600
601     waveformat.dwChannelMask = 0;
602     for( unsigned i = 0; pi_vlc_chan_order_wg4[i]; i++ )
603         if( i_channels & pi_vlc_chan_order_wg4[i] )
604             waveformat.dwChannelMask |= pi_channels_in[i];
605
606     switch( i_format )
607     {
608     case VLC_CODEC_SPDIFL:
609         i_nb_channels = 2;
610         /* To prevent channel re-ordering */
611         waveformat.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
612         waveformat.Format.wBitsPerSample = 16;
613         waveformat.Samples.wValidBitsPerSample =
614             waveformat.Format.wBitsPerSample;
615         waveformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
616         waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF;
617         break;
618
619     case VLC_CODEC_FL32:
620         waveformat.Format.wBitsPerSample = sizeof(float) * 8;
621         waveformat.Samples.wValidBitsPerSample =
622             waveformat.Format.wBitsPerSample;
623         waveformat.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
624         waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
625         break;
626
627     case VLC_CODEC_S16L:
628         waveformat.Format.wBitsPerSample = 16;
629         waveformat.Samples.wValidBitsPerSample =
630             waveformat.Format.wBitsPerSample;
631         waveformat.Format.wFormatTag = WAVE_FORMAT_PCM;
632         waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_PCM;
633         break;
634     }
635
636     waveformat.Format.nChannels = i_nb_channels;
637     waveformat.Format.nSamplesPerSec = i_rate;
638     waveformat.Format.nBlockAlign =
639         waveformat.Format.wBitsPerSample / 8 * i_nb_channels;
640     waveformat.Format.nAvgBytesPerSec =
641         waveformat.Format.nSamplesPerSec * waveformat.Format.nBlockAlign;
642
643     /* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */
644     if( i_nb_channels <= 2 )
645     {
646         waveformat.Format.cbSize = 0;
647     }
648     else
649     {
650         waveformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
651         waveformat.Format.cbSize =
652             sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
653     }
654
655     if(!b_probe) {
656         msg_Dbg( p_aout, "OpenWaveDevice-ID: %u", i_device_id);
657         msg_Dbg( p_aout,"waveformat.Format.cbSize          = %d",
658                  waveformat.Format.cbSize);
659         msg_Dbg( p_aout,"waveformat.Format.wFormatTag      = %u",
660                  waveformat.Format.wFormatTag);
661         msg_Dbg( p_aout,"waveformat.Format.nChannels       = %u",
662                  waveformat.Format.nChannels);
663         msg_Dbg( p_aout,"waveformat.Format.nSamplesPerSec  = %d",
664                  (int)waveformat.Format.nSamplesPerSec);
665         msg_Dbg( p_aout,"waveformat.Format.nAvgBytesPerSec = %u",
666                  (int)waveformat.Format.nAvgBytesPerSec);
667         msg_Dbg( p_aout,"waveformat.Format.nBlockAlign     = %d",
668                  waveformat.Format.nBlockAlign);
669         msg_Dbg( p_aout,"waveformat.Format.wBitsPerSample  = %d",
670                  waveformat.Format.wBitsPerSample);
671         msg_Dbg( p_aout,"waveformat.Samples.wValidBitsPerSample = %d",
672                  waveformat.Samples.wValidBitsPerSample);
673         msg_Dbg( p_aout,"waveformat.Samples.wSamplesPerBlock = %d",
674                  waveformat.Samples.wSamplesPerBlock);
675         msg_Dbg( p_aout,"waveformat.dwChannelMask          = %lu",
676                  waveformat.dwChannelMask);
677     }
678
679     /* Open the device */
680     result = waveOutOpen( &p_aout->sys->h_waveout, i_device_id,
681                           (WAVEFORMATEX *)&waveformat,
682                           (DWORD_PTR)WaveOutCallback, (DWORD_PTR)p_aout,
683                           CALLBACK_FUNCTION | (b_probe?WAVE_FORMAT_QUERY:0) );
684     if( result == WAVERR_BADFORMAT )
685     {
686         msg_Warn( p_aout, "waveOutOpen failed WAVERR_BADFORMAT" );
687         return VLC_EGENERIC;
688     }
689     if( result == MMSYSERR_ALLOCATED )
690     {
691         msg_Warn( p_aout, "waveOutOpen failed WAVERR_ALLOCATED" );
692         return VLC_EGENERIC;
693     }
694     if( result != MMSYSERR_NOERROR )
695     {
696         msg_Warn( p_aout, "waveOutOpen failed" );
697         return VLC_EGENERIC;
698     }
699
700     p_aout->sys->b_chan_reorder =
701         aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
702                                   waveformat.dwChannelMask, i_nb_channels,
703                                   p_aout->sys->pi_chan_table );
704
705     if( p_aout->sys->b_chan_reorder )
706     {
707         msg_Dbg( p_aout, "channel reordering needed" );
708     }
709
710     return VLC_SUCCESS;
711
712 #undef waveformat
713
714 }
715
716 /*****************************************************************************
717  * OpenWaveOutPCM: open a PCM waveout sound device
718  ****************************************************************************/
719 static int OpenWaveOutPCM( audio_output_t *p_aout, uint32_t i_device_id,
720                            vlc_fourcc_t *i_format,
721                            int i_channels, int i_nb_channels, int i_rate,
722                            bool b_probe )
723 {
724     bool b_use_float32 = var_CreateGetBool( p_aout, "waveout-float32");
725
726     if( !b_use_float32 || OpenWaveOut( p_aout, i_device_id, VLC_CODEC_FL32,
727                                    i_channels, i_nb_channels, i_rate, b_probe )
728         != VLC_SUCCESS )
729     {
730         if ( OpenWaveOut( p_aout, i_device_id, VLC_CODEC_S16L,
731                           i_channels, i_nb_channels, i_rate, b_probe )
732              != VLC_SUCCESS )
733         {
734             return VLC_EGENERIC;
735         }
736         else
737         {
738             *i_format = VLC_CODEC_S16L;
739             return VLC_SUCCESS;
740         }
741     }
742     else
743     {
744         *i_format = VLC_CODEC_FL32;
745         return VLC_SUCCESS;
746     }
747 }
748
749 /*****************************************************************************
750  * PlayWaveOut: play a buffer through the WaveOut device
751  *****************************************************************************/
752 static int PlayWaveOut( audio_output_t *p_aout, HWAVEOUT h_waveout,
753                         WAVEHDR *p_waveheader, block_t *p_buffer, bool b_spdif)
754 {
755     MMRESULT result;
756
757     /* Prepare the buffer */
758     if( p_buffer != NULL )
759     {
760         p_waveheader->lpData = (LPSTR)p_buffer->p_buffer;
761         /*
762           copy the buffer to the silence buffer :) so in case we don't
763           get the next buffer fast enough (I will repeat this one a time
764           for AC3 / DTS and SPDIF this will sound better instead of
765           a hickup)
766         */
767         if(b_spdif)
768         {
769            memcpy( p_aout->sys->p_silence_buffer,
770                        p_buffer->p_buffer,
771                        p_aout->sys->i_buffer_size );
772            p_aout->sys->i_repeat_counter = 2;
773         }
774     } else {
775         /* Use silence buffer instead */
776         if(p_aout->sys->i_repeat_counter)
777         {
778            p_aout->sys->i_repeat_counter--;
779            if(!p_aout->sys->i_repeat_counter)
780            {
781                memset( p_aout->sys->p_silence_buffer,
782                            0x00, p_aout->sys->i_buffer_size );
783            }
784         }
785         p_waveheader->lpData = (LPSTR)p_aout->sys->p_silence_buffer;
786     }
787
788     p_waveheader->dwUser = p_buffer ? (DWORD_PTR)p_buffer : (DWORD_PTR)1;
789     p_waveheader->dwBufferLength = p_aout->sys->i_buffer_size;
790     p_waveheader->dwFlags = 0;
791
792     result = waveOutPrepareHeader( h_waveout, p_waveheader, sizeof(WAVEHDR) );
793     if( result != MMSYSERR_NOERROR )
794     {
795         msg_Err( p_aout, "waveOutPrepareHeader failed" );
796         return VLC_EGENERIC;
797     }
798
799     /* Send the buffer to the waveOut queue */
800     result = waveOutWrite( h_waveout, p_waveheader, sizeof(WAVEHDR) );
801     if( result != MMSYSERR_NOERROR )
802     {
803         msg_Err( p_aout, "waveOutWrite failed" );
804         return VLC_EGENERIC;
805     }
806
807     return VLC_SUCCESS;
808 }
809
810 /*****************************************************************************
811  * WaveOutCallback: what to do once WaveOut has played its sound samples
812  *****************************************************************************/
813 static void CALLBACK WaveOutCallback( HWAVEOUT h_waveout, UINT uMsg,
814                                       DWORD_PTR _p_aout,
815                                       DWORD_PTR dwParam1, DWORD_PTR dwParam2 )
816 {
817     (void)h_waveout;    (void)dwParam1;    (void)dwParam2;
818     audio_output_t *p_aout = (audio_output_t *)_p_aout;
819     int i_queued_frames = 0;
820
821     if( uMsg != WOM_DONE ) return;
822
823     if( vlc_atomic_get(&p_aout->sys->abort) ) return;
824
825     /* Find out the current latency */
826     for( int i = 0; i < FRAMES_NUM; i++ )
827     {
828         /* Check if frame buf is available */
829         if( !(p_aout->sys->waveheader[i].dwFlags & WHDR_DONE) )
830         {
831             i_queued_frames++;
832         }
833     }
834
835     /* Don't wake up the thread too much */
836     if( i_queued_frames <= FRAMES_NUM/2 )
837         SetEvent( p_aout->sys->event );
838 }
839
840
841 /****************************************************************************
842  * WaveOutClearDoneBuffers: Clear all done marked buffers, and free buffer
843  ****************************************************************************
844  * return value is the number of still playing buffers in the queue
845  ****************************************************************************/
846 static int WaveOutClearDoneBuffers(aout_sys_t *p_sys)
847 {
848     WAVEHDR *p_waveheader = p_sys->waveheader;
849     int i_queued_frames = 0;
850
851     for( int i = 0; i < FRAMES_NUM; i++ )
852     {
853         if( (p_waveheader[i].dwFlags & WHDR_DONE) &&
854             p_waveheader[i].dwUser )
855         {
856             block_t *p_buffer =
857                     (block_t *)(p_waveheader[i].dwUser);
858             /* Unprepare and free the buffers which has just been played */
859             waveOutUnprepareHeader( p_sys->h_waveout, &p_waveheader[i],
860                                     sizeof(WAVEHDR) );
861
862             if( p_waveheader[i].dwUser != 1 )
863                 block_Release( p_buffer );
864
865             p_waveheader[i].dwUser = 0;
866         }
867
868         /* Check if frame buf is available */
869         if( !(p_waveheader[i].dwFlags & WHDR_DONE) )
870         {
871             i_queued_frames++;
872         }
873     }
874     return i_queued_frames;
875 }
876
877 /*****************************************************************************
878  * WaveOutThread: this thread will capture play notification events.
879  *****************************************************************************
880  * We use this thread to feed new audio samples to the sound card because
881  * we are not authorized to use waveOutWrite() directly in the waveout
882  * callback.
883  *****************************************************************************/
884 static void* WaveOutThread( void *data )
885 {
886     audio_output_t *p_aout = data;
887     aout_sys_t *p_sys = p_aout->sys;
888     block_t *p_buffer = NULL;
889     WAVEHDR *p_waveheader = p_sys->waveheader;
890     int i, i_queued_frames;
891     bool b_sleek;
892     mtime_t next_date;
893     int canc = vlc_savecancel ();
894
895     /* We don't want any resampling when using S/PDIF */
896     b_sleek = p_aout->format.i_format == VLC_CODEC_SPDIFL;
897
898     // wait for first call to "play()"
899     while( !p_sys->start_date && !vlc_atomic_get(&p_aout->sys->abort) )
900            WaitForSingleObject( p_sys->event, INFINITE );
901     if( vlc_atomic_get(&p_aout->sys->abort) )
902         return NULL;
903
904     msg_Dbg( p_aout, "will start to play in %"PRId64" us",
905              (p_sys->start_date - AOUT_MAX_PTS_ADVANCE/4)-mdate());
906
907     // than wait a short time... before grabbing first frames
908     mwait( p_sys->start_date - AOUT_MAX_PTS_ADVANCE/4 );
909
910 #define waveout_warn(msg) msg_Warn( p_aout, "aout_PacketNext no buffer "\
911                            "got next_date=%d ms, "\
912                            "%d frames to play, %s",\
913                            (int)(next_date/(mtime_t)1000), \
914                            i_queued_frames, msg);
915     next_date = mdate();
916
917     while( !vlc_atomic_get(&p_aout->sys->abort) )
918     {
919         /* Cleanup and find out the current latency */
920         i_queued_frames = WaveOutClearDoneBuffers( p_sys );
921
922         if( vlc_atomic_get(&p_aout->sys->abort) ) return NULL;
923
924         /* Try to fill in as many frame buffers as possible */
925         for( i = 0; i < FRAMES_NUM; i++ )
926         {
927             /* Check if frame buf is available */
928             if( p_waveheader[i].dwFlags & WHDR_DONE )
929             {
930                 // next_date = mdate() + 1000000 * i_queued_frames /
931                 //  p_aout->format.i_rate * p_aout->i_nb_samples;
932
933                 // the realtime has got our back-site:) to come in sync
934                 if(next_date < mdate())
935                    next_date = mdate();
936
937
938                 /* Take into account the latency */
939                 p_buffer = aout_PacketNext( p_aout, next_date );
940                 if(!p_buffer)
941                 {
942 #if 0
943                     msg_Dbg( p_aout, "aout_PacketNext no buffer got "
944                              "next_date=%"PRId64" ms, %d frames to play",
945                              next_date/1000, i_queued_frames);
946 #endif
947                     // means we are too early to request a new buffer?
948                     waveout_warn("waiting...")
949                     mwait( next_date - AOUT_MAX_PTS_ADVANCE/4 );
950                     next_date = mdate();
951                     p_buffer = aout_PacketNext( p_aout, next_date );
952                 }
953
954                 if( !p_buffer && i_queued_frames )
955                 {
956                     /* We aren't late so no need to play a blank sample */
957                     break;
958                 }
959
960                 if( p_buffer )
961                 {
962                     mtime_t buffer_length = p_buffer->i_length;
963                     next_date = next_date + buffer_length;
964                 }
965
966                 /* Do the channel reordering */
967                 if( p_buffer && p_sys->b_chan_reorder )
968                 {
969                     aout_ChannelReorder( p_buffer->p_buffer,
970                         p_buffer->i_buffer,
971                         p_sys->waveformat.Format.nChannels,
972                         p_sys->pi_chan_table,
973                         p_sys->waveformat.Format.wBitsPerSample );
974                 }
975
976                 PlayWaveOut( p_aout, p_sys->h_waveout,
977                              &p_waveheader[i], p_buffer, b_sleek );
978
979                 i_queued_frames++;
980             }
981         }
982
983         if( vlc_atomic_get(&p_aout->sys->abort) ) return NULL;
984
985         /*
986           deal with the case that the loop didn't fillup the buffer to the
987           max - instead of waiting that half the buffer is played before
988           fillup the waveout buffers, wait only for the next sample buffer
989           to arrive at the play method...
990
991           this will also avoid, that the last buffer is play until the
992           end, and then trying to get more data, so it will also
993           work - if the next buffer will arrive some ms before the
994           last buffer is finished.
995         */
996         if(i_queued_frames < FRAMES_NUM)
997            WaitForSingleObject( p_sys->new_buffer_event, INFINITE );
998         else
999            WaitForSingleObject( p_sys->event, INFINITE );
1000
1001     }
1002
1003 #undef waveout_warn
1004     vlc_restorecancel (canc);
1005     return NULL;
1006 }
1007
1008 #ifndef UNDER_CE
1009 static int VolumeSet( audio_output_t *aout, float volume )
1010 {
1011     aout_sys_t *sys = aout->sys;
1012     const HWAVEOUT hwo = sys->h_waveout;
1013     const float full = 0xffff.fp0;
1014
1015     volume *= full;
1016     if( volume >= full )
1017         return -1;
1018
1019     sys->volume = volume;
1020     if( sys->mute )
1021         return 0;
1022
1023     uint16_t vol = lroundf(volume);
1024     waveOutSetVolume( hwo, vol | (vol << 16) );
1025     return 0;
1026 }
1027
1028 static int MuteSet( audio_output_t * p_aout, bool mute )
1029 {
1030     aout_sys_t *sys = p_aout->sys;
1031     const HWAVEOUT hwo = sys->h_waveout;
1032     uint16_t vol = mute ? 0 : lroundf(sys->volume);
1033
1034     sys->mute = mute;
1035     waveOutSetVolume( hwo, vol | (vol << 16) );
1036     return 0;
1037 }
1038 #endif
1039
1040 /*
1041   reload the configuration drop down list, of the Audio Devices
1042 */
1043 static int ReloadWaveoutDevices( vlc_object_t *p_this, char const *psz_name,
1044                                  vlc_value_t newval, vlc_value_t oldval, void *data )
1045 {
1046     VLC_UNUSED( newval ); VLC_UNUSED( oldval ); VLC_UNUSED( data );
1047
1048     module_config_t *p_item = config_FindConfig( p_this, psz_name );
1049     if( !p_item ) return VLC_SUCCESS;
1050
1051     /* Clear-up the current list */
1052     if( p_item->i_list )
1053     {
1054         int i;
1055
1056         /* Keep the first entry */
1057         for( i = 1; i < p_item->i_list; i++ )
1058         {
1059             free((char *)(p_item->ppsz_list[i]) );
1060             free((char *)(p_item->ppsz_list_text[i]) );
1061         }
1062         /* TODO: Remove when no more needed */
1063         p_item->ppsz_list[i] = NULL;
1064         p_item->ppsz_list_text[i] = NULL;
1065     }
1066     p_item->i_list = 1;
1067
1068     int wave_devices = waveOutGetNumDevs();
1069
1070     p_item->ppsz_list = xrealloc( p_item->ppsz_list,
1071                           (wave_devices+2) * sizeof(char *) );
1072     p_item->ppsz_list_text = xrealloc( p_item->ppsz_list_text,
1073                           (wave_devices+2) * sizeof(char *) );
1074
1075     int j=1;
1076     for(int i=0; i<wave_devices; i++)
1077     {
1078         WAVEOUTCAPS caps;
1079         wchar_t dev_name[MAXPNAMELEN+32];
1080
1081         if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
1082                                                            != MMSYSERR_NOERROR)
1083             continue;
1084
1085         _snwprintf(dev_name, MAXPNAMELEN + 32, device_name_fmt,
1086                  caps.szPname, caps.wMid, caps.wPid);
1087         p_item->ppsz_list[j] = FromWide( dev_name );
1088         p_item->ppsz_list_text[j] = FromWide( dev_name );
1089         p_item->i_list++;
1090         j++;
1091     }
1092     p_item->ppsz_list[j] = NULL;
1093     p_item->ppsz_list_text[j] = NULL;
1094
1095     return VLC_SUCCESS;
1096 }
1097
1098 /*
1099   convert devicename to device ID for output
1100   if device not found return WAVE_MAPPER, so let
1101   windows decide which preferred audio device
1102   should be used.
1103 */
1104 static uint32_t findDeviceID(char *psz_device_name)
1105 {
1106     if( !psz_device_name )
1107        return WAVE_MAPPER;
1108
1109     uint32_t wave_devices = waveOutGetNumDevs();
1110
1111     for( uint32_t i = 0; i < wave_devices; i++ )
1112     {
1113         WAVEOUTCAPS caps;
1114         wchar_t dev_name[MAXPNAMELEN+32];
1115
1116         if( waveOutGetDevCaps( i, &caps, sizeof(WAVEOUTCAPS) )
1117                                                           != MMSYSERR_NOERROR )
1118             continue;
1119
1120         _snwprintf( dev_name, MAXPNAMELEN + 32, device_name_fmt,
1121                   caps.szPname, caps.wMid, caps.wPid );
1122         char *u8 = FromWide(dev_name);
1123         if( !stricmp(u8, psz_device_name) )
1124         {
1125             free( u8 );
1126             return i;
1127         }
1128         free( u8 );
1129     }
1130
1131     return WAVE_MAPPER;
1132 }