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