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