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