]> git.sesse.net Git - vlc/blob - modules/audio_output/waveout.c
Clean the played waveout frames in Play and Stop
[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 struct lkwavehdr
59 {
60     WAVEHDR hdr;
61     struct lkwavehdr * p_next;
62 };
63
64 /* local functions */
65 static void Probe        ( audio_output_t *, const audio_sample_format_t * );
66 static int OpenWaveOut   ( audio_output_t *, uint32_t,
67                            int, int, int, int, bool );
68 static int OpenWaveOutPCM( audio_output_t *, uint32_t,
69                            vlc_fourcc_t*, int, int, int, bool );
70 static int PlayWaveOut   ( audio_output_t *, HWAVEOUT, struct lkwavehdr *,
71                            block_t *, bool );
72
73 static void CALLBACK WaveOutCallback ( HWAVEOUT, UINT, DWORD_PTR, DWORD_PTR, DWORD_PTR );
74
75 static void WaveOutClean( aout_sys_t * p_sys );
76
77 static void WaveOutClearBuffer( HWAVEOUT, WAVEHDR *);
78
79 static int ReloadWaveoutDevices( vlc_object_t *, const char *,
80                                  char ***, char *** );
81 static uint32_t findDeviceID(char *);
82 static int WaveOutTimeGet(audio_output_t * , mtime_t *);
83 static void WaveOutFlush( audio_output_t *, bool);
84 static void WaveOutPause( audio_output_t *, bool, mtime_t);
85
86 static const wchar_t device_name_fmt[] = L"%ls ($%x,$%x)";
87
88 /*****************************************************************************
89  * aout_sys_t: waveOut audio output method descriptor
90  *****************************************************************************
91  * This structure is part of the audio output thread descriptor.
92  * It describes the waveOut specific properties of an audio device.
93  *****************************************************************************/
94
95 struct aout_sys_t
96 {
97     uint32_t i_wave_device_id;               /* ID of selected output device */
98
99     HWAVEOUT h_waveout;                        /* handle to waveout instance */
100
101     WAVEFORMATEXTENSIBLE waveformat;                         /* audio format */
102
103     size_t i_frames;
104
105     int i_repeat_counter;
106
107     int i_buffer_size;
108
109     int i_rate;
110     bool b_spdif;
111
112     uint8_t *p_silence_buffer;              /* buffer we use to play silence */
113
114     float soft_gain;
115     bool soft_mute;
116
117     uint8_t chans_to_reorder;              /* do we need channel reordering */
118     uint8_t chan_table[AOUT_CHAN_MAX];
119     vlc_fourcc_t format;
120
121     mtime_t i_played_length;
122
123     struct lkwavehdr * p_free_list;
124
125     vlc_mutex_t lock;
126     vlc_cond_t cond;
127 };
128
129 #include "volume.h"
130
131 /*****************************************************************************
132  * Module descriptor
133  *****************************************************************************/
134 #define DEVICE_TEXT N_("Select Audio Device")
135 #define DEVICE_LONG N_("Select special Audio device, or let windows "\
136                        "decide (default), change needs VLC restart "\
137                        "to apply.")
138 #define DEFAULT_AUDIO_DEVICE N_("Default Audio Device")
139
140 vlc_module_begin ()
141     set_shortname( "WaveOut" )
142     set_description( N_("Win32 waveOut extension output") )
143     set_capability( "audio output", 50 )
144     set_category( CAT_AUDIO )
145     set_subcategory( SUBCAT_AUDIO_AOUT )
146
147     add_string( "waveout-audio-device", "wavemapper",
148                  DEVICE_TEXT, DEVICE_LONG, false )
149        change_string_cb( ReloadWaveoutDevices )
150     add_sw_gain( )
151
152     add_bool( "waveout-float32", true, FLOAT_TEXT, FLOAT_LONGTEXT, true )
153
154     set_callbacks( Open, Close )
155 vlc_module_end ()
156
157 /*****************************************************************************
158  * Opens the audio device
159  *****************************************************************************
160  * This function opens and setups Win32 waveOut
161  *****************************************************************************/
162 static int Start( audio_output_t *p_aout, audio_sample_format_t *restrict fmt )
163 {
164     vlc_value_t val;
165
166     p_aout->time_get = WaveOutTimeGet;
167     p_aout->play = Play;
168     p_aout->pause = WaveOutPause;
169     p_aout->flush = WaveOutFlush;
170
171     /*
172       check for configured audio device!
173     */
174     char *psz_waveout_dev = var_CreateGetString( p_aout, "waveout-audio-device");
175
176     p_aout->sys->i_wave_device_id =
177          findDeviceID( psz_waveout_dev );
178
179     if(p_aout->sys->i_wave_device_id == WAVE_MAPPER)
180     {
181        if(psz_waveout_dev &&
182           stricmp(psz_waveout_dev,"wavemapper"))
183        {
184            msg_Warn( p_aout, "configured audio device '%s' not available, "\
185                          "use default instead", psz_waveout_dev );
186        }
187     }
188     free( psz_waveout_dev );
189
190
191     WAVEOUTCAPS waveoutcaps;
192     if(waveOutGetDevCaps( p_aout->sys->i_wave_device_id,
193                           &waveoutcaps,
194                           sizeof(WAVEOUTCAPS)) == MMSYSERR_NOERROR)
195     {
196       /* log debug some infos about driver, to know who to blame
197          if it doesn't work */
198         msg_Dbg( p_aout, "Drivername: %ls", waveoutcaps.szPname);
199         msg_Dbg( p_aout, "Driver Version: %d.%d",
200                           (waveoutcaps.vDriverVersion>>8)&255,
201                           waveoutcaps.vDriverVersion & 255);
202         msg_Dbg( p_aout, "Manufacturer identifier: 0x%x", waveoutcaps.wMid );
203         msg_Dbg( p_aout, "Product identifier: 0x%x", waveoutcaps.wPid );
204     }
205
206
207
208     if( var_Type( p_aout, "audio-device" ) == 0 )
209     {
210         Probe( p_aout, fmt );
211     }
212
213     if( var_Get( p_aout, "audio-device", &val ) < 0 )
214     {
215         /* Probe() has failed. */
216         var_Destroy( p_aout, "waveout-audio-device");
217         return VLC_EGENERIC;
218     }
219
220
221     /* Open the device */
222     if( val.i_int == AOUT_VAR_SPDIF )
223     {
224         fmt->i_format = VLC_CODEC_SPDIFL;
225
226         if( OpenWaveOut( p_aout, p_aout->sys->i_wave_device_id,
227                          VLC_CODEC_SPDIFL, fmt->i_physical_channels,
228                          aout_FormatNbChannels( fmt ), fmt->i_rate, false )
229             != VLC_SUCCESS )
230         {
231             msg_Err( p_aout, "cannot open waveout audio device" );
232             return VLC_EGENERIC;
233         }
234
235         /* Calculate the frame size in bytes */
236         fmt->i_bytes_per_frame = AOUT_SPDIF_SIZE;
237         fmt->i_frame_length = A52_FRAME_NB;
238         p_aout->sys->i_buffer_size = fmt->i_bytes_per_frame;
239         p_aout->sys->b_spdif = true;
240     }
241     else
242     {
243         switch( val.i_int )
244         {
245         case AOUT_VAR_5_1:
246             fmt->i_physical_channels
247                     = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
248                       | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
249                       | AOUT_CHAN_LFE;
250             break;
251         case AOUT_VAR_2F2R:
252             fmt->i_physical_channels
253                     = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
254                       | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
255             break;
256         case AOUT_VAR_MONO:
257             fmt->i_physical_channels = AOUT_CHAN_CENTER;
258             break;
259         default:
260             fmt->i_physical_channels = AOUT_CHANS_STEREO;
261         }
262
263         if( OpenWaveOutPCM( p_aout, p_aout->sys->i_wave_device_id,
264                             &fmt->i_format, fmt->i_physical_channels,
265                             aout_FormatNbChannels( fmt ), fmt->i_rate, false )
266             != VLC_SUCCESS )
267         {
268             msg_Err( p_aout, "cannot open waveout audio device" );
269             return VLC_EGENERIC;
270         }
271
272         /* Calculate the frame size in bytes */
273         aout_FormatPrepare( fmt );
274         p_aout->sys->i_buffer_size = FRAME_SIZE * fmt->i_bytes_per_frame;
275
276         aout_SoftVolumeStart( p_aout );
277
278         p_aout->sys->b_spdif = false;
279     }
280
281     p_aout->sys->i_rate = fmt->i_rate;
282
283     waveOutReset( p_aout->sys->h_waveout );
284
285     /* Allocate silence buffer */
286     p_aout->sys->p_silence_buffer =
287         malloc( p_aout->sys->i_buffer_size );
288     if( p_aout->sys->p_silence_buffer == NULL )
289     {
290         msg_Err( p_aout, "Couldn't alloc silence buffer... aborting");
291         return VLC_ENOMEM;
292     }
293     p_aout->sys->i_repeat_counter = 0;
294
295
296     /* Zero the buffer. WinCE doesn't have calloc(). */
297     memset( p_aout->sys->p_silence_buffer, 0,
298             p_aout->sys->i_buffer_size );
299
300     /* Now we need to setup our waveOut play notification structure */
301     p_aout->sys->i_frames = 0;
302     p_aout->sys->i_played_length = 0;
303     p_aout->sys->p_free_list = NULL;
304
305     return VLC_SUCCESS;
306 }
307
308 /*****************************************************************************
309  * Probe: probe the audio device for available formats and channels
310  *****************************************************************************/
311 static void Probe( audio_output_t * p_aout, const audio_sample_format_t *fmt )
312 {
313     vlc_value_t val, text;
314     vlc_fourcc_t i_format;
315     unsigned int i_physical_channels;
316
317     var_Create( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
318     text.psz_string = _("Audio Device");
319     var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
320
321     /* Test for 5.1 support */
322     i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
323                           AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
324                           AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE;
325     if( fmt->i_physical_channels == i_physical_channels )
326     {
327         if( OpenWaveOutPCM( p_aout, p_aout->sys->i_wave_device_id,
328                             &i_format, i_physical_channels, 6,
329                             fmt->i_rate, true )
330             == VLC_SUCCESS )
331         {
332             val.i_int = AOUT_VAR_5_1;
333             text.psz_string = (char *)_("5.1");
334             var_Change( p_aout, "audio-device",
335                         VLC_VAR_ADDCHOICE, &val, &text );
336             msg_Dbg( p_aout, "device supports 5.1 channels" );
337         }
338     }
339
340     /* Test for 2 Front 2 Rear support */
341     i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
342                           AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
343     if( ( fmt->i_physical_channels & i_physical_channels )
344         == i_physical_channels )
345     {
346         if( OpenWaveOutPCM( p_aout,p_aout->sys->i_wave_device_id,
347                             &i_format, i_physical_channels, 4,
348                             fmt->i_rate, true )
349             == VLC_SUCCESS )
350         {
351             val.i_int = AOUT_VAR_2F2R;
352             text.psz_string = (char *)_("2 Front 2 Rear");
353             var_Change( p_aout, "audio-device",
354                         VLC_VAR_ADDCHOICE, &val, &text );
355             msg_Dbg( p_aout, "device supports 4 channels" );
356         }
357     }
358
359     /* Test for stereo support */
360     i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
361     if( OpenWaveOutPCM( p_aout, p_aout->sys->i_wave_device_id,
362                         &i_format,i_physical_channels, 2,
363                         fmt->i_rate, true )
364         == VLC_SUCCESS )
365     {
366         val.i_int = AOUT_VAR_STEREO;
367         text.psz_string = (char *)_("Stereo");
368         var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
369         msg_Dbg( p_aout, "device supports 2 channels" );
370     }
371
372     /* Test for mono support */
373     i_physical_channels = AOUT_CHAN_CENTER;
374     if( OpenWaveOutPCM( p_aout, p_aout->sys->i_wave_device_id,
375                         &i_format, i_physical_channels, 1, fmt->i_rate, true )
376         == VLC_SUCCESS )
377     {
378         val.i_int = AOUT_VAR_MONO;
379         text.psz_string = (char *)_("Mono");
380         var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
381         msg_Dbg( p_aout, "device supports 1 channel" );
382     }
383
384     /* Test for SPDIF support */
385     if ( AOUT_FMT_SPDIF( fmt ) )
386     {
387         if( OpenWaveOut( p_aout, p_aout->sys->i_wave_device_id,
388                          VLC_CODEC_SPDIFL, fmt->i_physical_channels,
389                          aout_FormatNbChannels( fmt ), fmt->i_rate, true )
390             == VLC_SUCCESS )
391         {
392             msg_Dbg( p_aout, "device supports A/52 over S/PDIF" );
393             val.i_int = AOUT_VAR_SPDIF;
394             text.psz_string = (char *)_("A/52 over S/PDIF");
395             var_Change( p_aout, "audio-device",
396                         VLC_VAR_ADDCHOICE, &val, &text );
397             if( var_InheritBool( p_aout, "spdif" ) )
398                 var_Set( p_aout, "audio-device", val );
399         }
400     }
401
402     var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
403     if( val.i_int <= 0 )
404     {
405         /* Probe() has failed. */
406         var_Destroy( p_aout, "audio-device" );
407         return;
408     }
409
410     var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
411 }
412
413 /*****************************************************************************
414  * Play: play a sound buffer
415  *****************************************************************************
416  * This doesn't actually play the buffer. This just stores the buffer so it
417  * can be played by the callback thread.
418  *****************************************************************************/
419 static void Play( audio_output_t *p_aout, block_t *block )
420 {
421     struct lkwavehdr * p_waveheader = 
422         (struct lkwavehdr *) malloc(sizeof(struct lkwavehdr));
423     if(!p_waveheader)
424     {
425         msg_Err(p_aout, "Couldn't alloc WAVEHDR");
426         if( block )
427             block_Release( block );
428         return;
429     }
430
431     p_waveheader->p_next = NULL;
432
433     if( block && p_aout->sys->chans_to_reorder )
434     {
435         aout_ChannelReorder( block->p_buffer, block->i_buffer,
436                              p_aout->sys->waveformat.Format.nChannels,
437                              p_aout->sys->chan_table, p_aout->sys->format );
438     }
439     while( PlayWaveOut( p_aout, p_aout->sys->h_waveout, p_waveheader, block,       
440                         p_aout->sys->b_spdif ) != VLC_SUCCESS )
441
442     {
443         msg_Warn( p_aout, "Couln't write frame... sleeping");
444         msleep( block->i_length );
445     }
446
447     WaveOutClean( p_aout->sys );
448
449     vlc_mutex_lock( &p_aout->sys->lock );
450     p_aout->sys->i_frames++;
451     p_aout->sys->i_played_length += block->i_length;
452     vlc_mutex_unlock( &p_aout->sys->lock );
453 }
454
455 /*****************************************************************************
456  * Close: close the audio device
457  *****************************************************************************/
458 static void Stop( audio_output_t *p_aout )
459 {
460     aout_sys_t *p_sys = p_aout->sys;
461
462     /* Before calling waveOutClose we must reset the device */
463     MMRESULT result = waveOutReset( p_sys->h_waveout );
464     if(result != MMSYSERR_NOERROR)
465     {
466        msg_Err( p_aout, "waveOutReset failed 0x%x", result );
467        /*
468         now we must wait, that all buffers are played
469         because cancel doesn't work in this case...
470        */
471        if(result == MMSYSERR_NOTSUPPORTED)
472        {
473            /*
474              clear currently played (done) buffers,
475              if returnvalue > 0 (means some buffer still playing)
476              wait for the driver event callback that one buffer
477              is finished with playing, and check again
478              the timeout of 5000ms is just, an emergency exit
479              of this loop, to avoid deadlock in case of other
480              (currently not known bugs, problems, errors cases?)
481            */
482             WaveOutFlush( p_aout, true );
483        }
484     }
485
486     /* wait for the frames to be queued in cleaning list */
487     WaveOutFlush( p_aout, true );
488     WaveOutClean( p_aout->sys );
489
490     /* now we can Close the device */
491     if( waveOutClose( p_sys->h_waveout ) != MMSYSERR_NOERROR )
492     {
493         msg_Err( p_aout, "waveOutClose failed" );
494     }
495
496     free( p_sys->p_silence_buffer );
497     p_aout->sys->i_played_length = 0;
498 }
499
500 /*****************************************************************************
501  * OpenWaveOut: open the waveout sound device
502  ****************************************************************************/
503 static int OpenWaveOut( audio_output_t *p_aout, uint32_t i_device_id, int i_format,
504                         int i_channels, int i_nb_channels, int i_rate,
505                         bool b_probe )
506 {
507     MMRESULT result;
508
509     /* Set sound format */
510
511 #define waveformat p_aout->sys->waveformat
512
513     waveformat.dwChannelMask = 0;
514     for( unsigned i = 0; pi_vlc_chan_order_wg4[i]; i++ )
515         if( i_channels & pi_vlc_chan_order_wg4[i] )
516             waveformat.dwChannelMask |= pi_channels_in[i];
517
518     switch( i_format )
519     {
520     case VLC_CODEC_SPDIFL:
521         i_nb_channels = 2;
522         /* To prevent channel re-ordering */
523         waveformat.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
524         waveformat.Format.wBitsPerSample = 16;
525         waveformat.Samples.wValidBitsPerSample =
526             waveformat.Format.wBitsPerSample;
527         waveformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
528         waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF;
529         break;
530
531     case VLC_CODEC_FL32:
532         waveformat.Format.wBitsPerSample = sizeof(float) * 8;
533         waveformat.Samples.wValidBitsPerSample =
534             waveformat.Format.wBitsPerSample;
535         waveformat.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
536         waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
537         break;
538
539     case VLC_CODEC_S16N:
540         waveformat.Format.wBitsPerSample = 16;
541         waveformat.Samples.wValidBitsPerSample =
542             waveformat.Format.wBitsPerSample;
543         waveformat.Format.wFormatTag = WAVE_FORMAT_PCM;
544         waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_PCM;
545         break;
546     }
547
548     waveformat.Format.nChannels = i_nb_channels;
549     waveformat.Format.nSamplesPerSec = i_rate;
550     waveformat.Format.nBlockAlign =
551         waveformat.Format.wBitsPerSample / 8 * i_nb_channels;
552     waveformat.Format.nAvgBytesPerSec =
553         waveformat.Format.nSamplesPerSec * waveformat.Format.nBlockAlign;
554
555     /* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */
556     if( i_nb_channels <= 2 )
557     {
558         waveformat.Format.cbSize = 0;
559     }
560     else
561     {
562         waveformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
563         waveformat.Format.cbSize =
564             sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
565     }
566
567     if(!b_probe) {
568         msg_Dbg( p_aout, "OpenWaveDevice-ID: %u", i_device_id);
569         msg_Dbg( p_aout,"waveformat.Format.cbSize          = %d",
570                  waveformat.Format.cbSize);
571         msg_Dbg( p_aout,"waveformat.Format.wFormatTag      = %u",
572                  waveformat.Format.wFormatTag);
573         msg_Dbg( p_aout,"waveformat.Format.nChannels       = %u",
574                  waveformat.Format.nChannels);
575         msg_Dbg( p_aout,"waveformat.Format.nSamplesPerSec  = %d",
576                  (int)waveformat.Format.nSamplesPerSec);
577         msg_Dbg( p_aout,"waveformat.Format.nAvgBytesPerSec = %u",
578                  (int)waveformat.Format.nAvgBytesPerSec);
579         msg_Dbg( p_aout,"waveformat.Format.nBlockAlign     = %d",
580                  waveformat.Format.nBlockAlign);
581         msg_Dbg( p_aout,"waveformat.Format.wBitsPerSample  = %d",
582                  waveformat.Format.wBitsPerSample);
583         msg_Dbg( p_aout,"waveformat.Samples.wValidBitsPerSample = %d",
584                  waveformat.Samples.wValidBitsPerSample);
585         msg_Dbg( p_aout,"waveformat.Samples.wSamplesPerBlock = %d",
586                  waveformat.Samples.wSamplesPerBlock);
587         msg_Dbg( p_aout,"waveformat.dwChannelMask          = %lu",
588                  waveformat.dwChannelMask);
589     }
590
591     /* Open the device */
592     result = waveOutOpen( &p_aout->sys->h_waveout, i_device_id,
593                           (WAVEFORMATEX *)&waveformat,
594                           (DWORD_PTR)WaveOutCallback, (DWORD_PTR)p_aout,
595                           CALLBACK_FUNCTION | (b_probe?WAVE_FORMAT_QUERY:0) );
596     if( result == WAVERR_BADFORMAT )
597     {
598         msg_Warn( p_aout, "waveOutOpen failed WAVERR_BADFORMAT" );
599         return VLC_EGENERIC;
600     }
601     if( result == MMSYSERR_ALLOCATED )
602     {
603         msg_Warn( p_aout, "waveOutOpen failed WAVERR_ALLOCATED" );
604         return VLC_EGENERIC;
605     }
606     if( result != MMSYSERR_NOERROR )
607     {
608         msg_Warn( p_aout, "waveOutOpen failed" );
609         return VLC_EGENERIC;
610     }
611
612     p_aout->sys->chans_to_reorder =
613         aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
614                                   waveformat.dwChannelMask,
615                                   p_aout->sys->chan_table );
616     if( p_aout->sys->chans_to_reorder )
617         msg_Dbg( p_aout, "channel reordering needed" );
618     p_aout->sys->format = i_format;
619
620     return VLC_SUCCESS;
621
622 #undef waveformat
623
624 }
625
626 /*****************************************************************************
627  * OpenWaveOutPCM: open a PCM waveout sound device
628  ****************************************************************************/
629 static int OpenWaveOutPCM( audio_output_t *p_aout, uint32_t i_device_id,
630                            vlc_fourcc_t *i_format,
631                            int i_channels, int i_nb_channels, int i_rate,
632                            bool b_probe )
633 {
634     bool b_use_float32 = var_CreateGetBool( p_aout, "waveout-float32");
635
636     if( !b_use_float32 || OpenWaveOut( p_aout, i_device_id, VLC_CODEC_FL32,
637                                    i_channels, i_nb_channels, i_rate, b_probe )
638         != VLC_SUCCESS )
639     {
640         if ( OpenWaveOut( p_aout, i_device_id, VLC_CODEC_S16N,
641                           i_channels, i_nb_channels, i_rate, b_probe )
642              != VLC_SUCCESS )
643         {
644             return VLC_EGENERIC;
645         }
646         else
647         {
648             *i_format = VLC_CODEC_S16N;
649             return VLC_SUCCESS;
650         }
651     }
652     else
653     {
654         *i_format = VLC_CODEC_FL32;
655         return VLC_SUCCESS;
656     }
657 }
658
659 /*****************************************************************************
660  * PlayWaveOut: play a buffer through the WaveOut device
661  *****************************************************************************/
662 static int PlayWaveOut( audio_output_t *p_aout, HWAVEOUT h_waveout,
663                         struct lkwavehdr *p_waveheader, block_t *p_buffer, bool b_spdif)
664 {
665     MMRESULT result;
666
667     /* Prepare the buffer */
668     if( p_buffer != NULL )
669     {
670         p_waveheader->hdr.lpData = (LPSTR)p_buffer->p_buffer;
671         p_waveheader->hdr.dwBufferLength = p_buffer->i_buffer;
672         /*
673           copy the buffer to the silence buffer :) so in case we don't
674           get the next buffer fast enough (I will repeat this one a time
675           for AC3 / DTS and SPDIF this will sound better instead of
676           a hickup)
677         */
678         if(b_spdif)
679         {
680            memcpy( p_aout->sys->p_silence_buffer,
681                        p_buffer->p_buffer,
682                        p_aout->sys->i_buffer_size );
683            p_aout->sys->i_repeat_counter = 2;
684         }
685     } else {
686         /* Use silence buffer instead */
687         if(p_aout->sys->i_repeat_counter)
688         {
689            p_aout->sys->i_repeat_counter--;
690            if(!p_aout->sys->i_repeat_counter)
691            {
692                memset( p_aout->sys->p_silence_buffer,
693                            0x00, p_aout->sys->i_buffer_size );
694            }
695         }
696         p_waveheader->hdr.lpData = (LPSTR)p_aout->sys->p_silence_buffer;
697         p_waveheader->hdr.dwBufferLength = p_aout->sys->i_buffer_size;
698     }
699
700     p_waveheader->hdr.dwUser = p_buffer ? (DWORD_PTR)p_buffer : (DWORD_PTR)1;
701     p_waveheader->hdr.dwFlags = 0;
702
703     result = waveOutPrepareHeader( h_waveout, &p_waveheader->hdr, sizeof(WAVEHDR) );
704     if( result != MMSYSERR_NOERROR )
705     {
706         msg_Err( p_aout, "waveOutPrepareHeader failed" );
707         return VLC_EGENERIC;
708     }
709
710     /* Send the buffer to the waveOut queue */
711     result = waveOutWrite( h_waveout, &p_waveheader->hdr, sizeof(WAVEHDR) );
712     if( result != MMSYSERR_NOERROR )
713     {
714         msg_Err( p_aout, "waveOutWrite failed" );
715         return VLC_EGENERIC;
716     }
717
718     return VLC_SUCCESS;
719 }
720
721 /*****************************************************************************
722  * WaveOutCallback: what to do once WaveOut has played its sound samples
723  *****************************************************************************/
724 static void CALLBACK WaveOutCallback( HWAVEOUT h_waveout, UINT uMsg,
725                                       DWORD_PTR _p_aout,
726                                       DWORD_PTR dwParam1, DWORD_PTR dwParam2 )
727 {
728     (void) h_waveout;
729     (void) dwParam2;
730     audio_output_t *p_aout = (audio_output_t *)_p_aout;
731     struct lkwavehdr * p_waveheader =  (struct lkwavehdr *) dwParam1;
732
733     if( uMsg != WOM_DONE ) return;
734
735     vlc_mutex_lock( &p_aout->sys->lock );
736     p_waveheader->p_next = p_aout->sys->p_free_list;
737     p_aout->sys->p_free_list = p_waveheader;
738     p_aout->sys->i_frames--;
739     vlc_cond_broadcast( &p_aout->sys->cond );
740     vlc_mutex_unlock( &p_aout->sys->lock );
741 }
742
743 static void WaveOutClean( aout_sys_t * p_sys )
744 {
745     struct lkwavehdr *p_whdr, *p_list;
746
747     vlc_mutex_lock(&p_sys->lock);
748     p_list =  p_sys->p_free_list;
749     p_sys->p_free_list = NULL;
750     vlc_mutex_unlock(&p_sys->lock);
751
752     while( p_list )
753     {
754         p_whdr = p_list;
755         p_list = p_list->p_next;
756         WaveOutClearBuffer( p_sys->h_waveout, &p_whdr->hdr );
757         free(p_whdr);
758     }
759 }
760
761 static void WaveOutClearBuffer( HWAVEOUT h_waveout, WAVEHDR *p_waveheader )
762 {   
763     block_t *p_buffer = (block_t *)(p_waveheader->dwUser);
764     /* Unprepare and free the buffers which has just been played */
765     waveOutUnprepareHeader( h_waveout, p_waveheader, sizeof(WAVEHDR) );
766
767     if( p_waveheader->dwUser != 1 )
768         block_Release( p_buffer );
769 }
770
771 /*
772   reload the configuration drop down list, of the Audio Devices
773 */
774 static int ReloadWaveoutDevices( vlc_object_t *p_this, char const *psz_name,
775                                  char ***values, char ***descs )
776 {
777     int n = 0, nb_devices = waveOutGetNumDevs();
778
779     VLC_UNUSED( p_this); VLC_UNUSED( psz_name );
780
781     *values = xmalloc( (nb_devices + 1) * sizeof(char *) );
782     *descs = xmalloc( (nb_devices + 1) * sizeof(char *) );
783
784     (*values)[n] = strdup( "wavemapper" );
785     (*descs)[n] = strdup( _("Microsoft Soundmapper") );
786     n++;
787
788     for(int i = 0; i < nb_devices; i++)
789     {
790         WAVEOUTCAPS caps;
791         wchar_t dev_name[MAXPNAMELEN+32];
792
793         if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
794                                                            != MMSYSERR_NOERROR)
795             continue;
796
797         _snwprintf(dev_name, MAXPNAMELEN + 32, device_name_fmt,
798                    caps.szPname, caps.wMid, caps.wPid);
799         (*values)[n] = FromWide( dev_name );
800         (*descs)[n] = strdup( (*values)[n] );
801         n++;
802     }
803
804     return n;
805 }
806
807 /*
808   convert devicename to device ID for output
809   if device not found return WAVE_MAPPER, so let
810   windows decide which preferred audio device
811   should be used.
812 */
813 static uint32_t findDeviceID(char *psz_device_name)
814 {
815     if( !psz_device_name )
816        return WAVE_MAPPER;
817
818     uint32_t wave_devices = waveOutGetNumDevs();
819
820     for( uint32_t i = 0; i < wave_devices; i++ )
821     {
822         WAVEOUTCAPS caps;
823         wchar_t dev_name[MAXPNAMELEN+32];
824
825         if( waveOutGetDevCaps( i, &caps, sizeof(WAVEOUTCAPS) )
826                                                           != MMSYSERR_NOERROR )
827             continue;
828
829         _snwprintf( dev_name, MAXPNAMELEN + 32, device_name_fmt,
830                   caps.szPname, caps.wMid, caps.wPid );
831         char *u8 = FromWide(dev_name);
832         if( !stricmp(u8, psz_device_name) )
833         {
834             free( u8 );
835             return i;
836         }
837         free( u8 );
838     }
839
840     return WAVE_MAPPER;
841 }
842
843 static int Open(vlc_object_t *obj)
844 {
845     audio_output_t *aout = (audio_output_t *)obj;
846     aout_sys_t *sys = malloc(sizeof (*sys));
847
848     if (unlikely(sys == NULL))
849         return VLC_ENOMEM;
850     aout->sys = sys;
851     aout->start = Start;
852     aout->stop = Stop;
853     aout_SoftVolumeInit(aout);
854
855     vlc_mutex_init( &sys->lock );
856     vlc_cond_init( &sys->cond );
857     return VLC_SUCCESS;
858 }
859
860 static void Close(vlc_object_t *obj)
861 {
862     audio_output_t *aout = (audio_output_t *)obj;
863     aout_sys_t *sys = aout->sys;
864
865     vlc_cond_destroy( &sys->cond );
866     vlc_mutex_destroy( &sys->lock );
867
868     free(sys);
869 }
870
871 static int WaveOutTimeGet(audio_output_t * p_aout, mtime_t *delay)
872 {
873     MMTIME mmtime;
874     mmtime.wType = TIME_SAMPLES;
875
876     if( !p_aout->sys->i_frames )
877         return -1;
878
879     if( waveOutGetPosition( p_aout->sys->h_waveout, &mmtime, sizeof(MMTIME) ) 
880             != MMSYSERR_NOERROR )
881     {
882         msg_Err( p_aout, "waveOutGetPosition failed");
883         return -1;
884     }
885
886     mtime_t i_pos = (mtime_t) mmtime.u.sample * CLOCK_FREQ / p_aout->sys->i_rate;
887     *delay = p_aout->sys->i_played_length - i_pos;
888     return 0;
889 }
890
891 static void WaveOutFlush( audio_output_t *p_aout, bool wait)
892 {
893     MMRESULT res;
894     if( !wait )
895     {
896         res  = waveOutReset( p_aout->sys->h_waveout );
897         p_aout->sys->i_played_length = 0;
898         if( res != MMSYSERR_NOERROR )
899             msg_Err( p_aout, "waveOutReset failed");
900     }
901     else
902     {
903         vlc_mutex_lock( &p_aout->sys->lock );
904         while( p_aout->sys->i_frames )
905         {
906             vlc_cond_wait( &p_aout->sys->cond, &p_aout->sys-> lock );
907         }
908         vlc_mutex_unlock( &p_aout->sys->lock );
909     }
910 }
911
912 static void WaveOutPause( audio_output_t * p_aout, bool pause, mtime_t date)
913 {
914     MMRESULT res;
915     (void) date;
916     if(pause)
917     {
918         res = waveOutPause( p_aout->sys->h_waveout );
919         if( res != MMSYSERR_NOERROR )
920         {
921             msg_Err( p_aout, "waveOutPause failed (0x%x)", res);
922             return;
923         }
924     }
925     else
926     {
927         res = waveOutRestart( p_aout->sys->h_waveout );
928         if( res != MMSYSERR_NOERROR )
929         {
930             msg_Err( p_aout, "waveOutRestart failed (0x%x)", res);
931             return;
932         }
933     }
934 }