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