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