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