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