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