1 /*****************************************************************************
2 * waveout.c : Windows waveOut plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2001 the VideoLAN team
7 * Authors: Gildas Bazin <gbazin@videolan.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
38 #define FRAME_SIZE 4096 /* The size is in samples, not in bytes */
41 /*****************************************************************************
43 *****************************************************************************/
45 # define DWORD_PTR DWORD
46 # ifdef waveOutGetDevCaps
47 # undef waveOutGetDevCaps
48 MMRESULT WINAPI waveOutGetDevCaps(UINT, LPWAVEOUTCAPS, UINT);
52 #ifndef WAVE_FORMAT_IEEE_FLOAT
53 # define WAVE_FORMAT_IEEE_FLOAT 0x0003
56 #ifndef WAVE_FORMAT_DOLBY_AC3_SPDIF
57 # define WAVE_FORMAT_DOLBY_AC3_SPDIF 0x0092
60 #ifndef WAVE_FORMAT_EXTENSIBLE
61 #define WAVE_FORMAT_EXTENSIBLE 0xFFFE
64 #ifndef SPEAKER_FRONT_LEFT
65 # define SPEAKER_FRONT_LEFT 0x1
66 # define SPEAKER_FRONT_RIGHT 0x2
67 # define SPEAKER_FRONT_CENTER 0x4
68 # define SPEAKER_LOW_FREQUENCY 0x8
69 # define SPEAKER_BACK_LEFT 0x10
70 # define SPEAKER_BACK_RIGHT 0x20
71 # define SPEAKER_FRONT_LEFT_OF_CENTER 0x40
72 # define SPEAKER_FRONT_RIGHT_OF_CENTER 0x80
73 # define SPEAKER_BACK_CENTER 0x100
74 # define SPEAKER_SIDE_LEFT 0x200
75 # define SPEAKER_SIDE_RIGHT 0x400
76 # define SPEAKER_TOP_CENTER 0x800
77 # define SPEAKER_TOP_FRONT_LEFT 0x1000
78 # define SPEAKER_TOP_FRONT_CENTER 0x2000
79 # define SPEAKER_TOP_FRONT_RIGHT 0x4000
80 # define SPEAKER_TOP_BACK_LEFT 0x8000
81 # define SPEAKER_TOP_BACK_CENTER 0x10000
82 # define SPEAKER_TOP_BACK_RIGHT 0x20000
83 # define SPEAKER_RESERVED 0x80000000
86 #ifndef _WAVEFORMATEXTENSIBLE_
90 WORD wValidBitsPerSample; /* bits of precision */
91 WORD wSamplesPerBlock; /* valid if wBitsPerSample==0 */
92 WORD wReserved; /* If neither applies, set to zero. */
94 DWORD dwChannelMask; /* which channels are */
95 /* present in stream */
97 } WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE;
100 static const GUID __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = {WAVE_FORMAT_IEEE_FLOAT, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
101 static const GUID __KSDATAFORMAT_SUBTYPE_PCM = {WAVE_FORMAT_PCM, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
102 static const GUID __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF = {WAVE_FORMAT_DOLBY_AC3_SPDIF, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
104 /*****************************************************************************
106 *****************************************************************************/
107 static int Open ( vlc_object_t * );
108 static void Close ( vlc_object_t * );
109 static void Play ( aout_instance_t * );
111 /*****************************************************************************
112 * notification_thread_t: waveOut event thread
113 *****************************************************************************/
114 typedef struct notification_thread_t
117 aout_instance_t *p_aout;
119 } notification_thread_t;
121 /* local functions */
122 static void Probe ( aout_instance_t * );
123 static int OpenWaveOut ( aout_instance_t *, int, int, int, int, vlc_bool_t );
124 static int OpenWaveOutPCM( aout_instance_t *, int*, int, int, int, vlc_bool_t );
125 static int PlayWaveOut ( aout_instance_t *, HWAVEOUT, WAVEHDR *,
128 static void CALLBACK WaveOutCallback ( HWAVEOUT, UINT, DWORD, DWORD, DWORD );
129 static void WaveOutThread( notification_thread_t * );
131 static int VolumeInfos( aout_instance_t *, audio_volume_t * );
132 static int VolumeGet( aout_instance_t *, audio_volume_t * );
133 static int VolumeSet( aout_instance_t *, audio_volume_t );
135 /*****************************************************************************
137 *****************************************************************************/
138 #define FLOAT_TEXT N_("Use float32 output")
139 #define FLOAT_LONGTEXT N_( \
140 "The option allows you to enable or disable the high-quality float32 " \
141 "audio output mode (which is not well supported by some soundcards)." )
144 set_shortname( "WaveOut" );
145 set_description( _("Win32 waveOut extension output") );
146 set_capability( "audio output", 50 );
147 set_category( CAT_AUDIO );
148 set_subcategory( SUBCAT_AUDIO_AOUT );
149 add_bool( "waveout-float32", 1, 0, FLOAT_TEXT, FLOAT_LONGTEXT, VLC_TRUE );
150 set_callbacks( Open, Close );
153 /*****************************************************************************
154 * aout_sys_t: waveOut audio output method descriptor
155 *****************************************************************************
156 * This structure is part of the audio output thread descriptor.
157 * It describes the waveOut specific properties of an audio device.
158 *****************************************************************************/
161 HWAVEOUT h_waveout; /* handle to waveout instance */
163 WAVEFORMATEXTENSIBLE waveformat; /* audio format */
165 WAVEHDR waveheader[FRAMES_NUM];
167 notification_thread_t *p_notif; /* WaveOutThread id */
172 byte_t *p_silence_buffer; /* buffer we use to play silence */
174 vlc_bool_t b_chan_reorder; /* do we need channel reordering */
175 int pi_chan_table[AOUT_CHAN_MAX];
178 static const uint32_t pi_channels_src[] =
179 { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT,
180 AOUT_CHAN_MIDDLELEFT, AOUT_CHAN_MIDDLERIGHT,
181 AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT,
182 AOUT_CHAN_CENTER, AOUT_CHAN_LFE, 0 };
183 static const uint32_t pi_channels_in[] =
184 { SPEAKER_FRONT_LEFT, SPEAKER_FRONT_RIGHT,
185 SPEAKER_SIDE_LEFT, SPEAKER_SIDE_RIGHT,
186 SPEAKER_BACK_LEFT, SPEAKER_BACK_RIGHT,
187 SPEAKER_FRONT_CENTER, SPEAKER_LOW_FREQUENCY, 0 };
188 static const uint32_t pi_channels_out[] =
189 { SPEAKER_FRONT_LEFT, SPEAKER_FRONT_RIGHT,
190 SPEAKER_FRONT_CENTER, SPEAKER_LOW_FREQUENCY,
191 SPEAKER_BACK_LEFT, SPEAKER_BACK_RIGHT,
192 SPEAKER_SIDE_LEFT, SPEAKER_SIDE_RIGHT, 0 };
194 /*****************************************************************************
195 * Open: open the audio device
196 *****************************************************************************
197 * This function opens and setups Win32 waveOut
198 *****************************************************************************/
199 static int Open( vlc_object_t *p_this )
201 aout_instance_t *p_aout = (aout_instance_t *)p_this;
205 /* Allocate structure */
206 p_aout->output.p_sys = malloc( sizeof( aout_sys_t ) );
208 if( p_aout->output.p_sys == NULL )
210 msg_Err( p_aout, "out of memory" );
214 p_aout->output.pf_play = Play;
215 p_aout->b_die = VLC_FALSE;
217 if( var_Type( p_aout, "audio-device" ) == 0 )
222 if( var_Get( p_aout, "audio-device", &val ) < 0 )
224 /* Probe() has failed. */
225 free( p_aout->output.p_sys );
229 var_Create( p_aout, "waveout-float32", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
231 /* Open the device */
232 if( val.i_int == AOUT_VAR_SPDIF )
234 p_aout->output.output.i_format = VLC_FOURCC('s','p','d','i');
236 if( OpenWaveOut( p_aout, VLC_FOURCC('s','p','d','i'),
237 p_aout->output.output.i_physical_channels,
238 aout_FormatNbChannels( &p_aout->output.output ),
239 p_aout->output.output.i_rate, VLC_FALSE )
242 msg_Err( p_aout, "cannot open waveout audio device" );
243 free( p_aout->output.p_sys );
247 /* Calculate the frame size in bytes */
248 p_aout->output.i_nb_samples = A52_FRAME_NB;
249 p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
250 p_aout->output.output.i_frame_length = A52_FRAME_NB;
251 p_aout->output.p_sys->i_buffer_size =
252 p_aout->output.output.i_bytes_per_frame;
254 aout_VolumeNoneInit( p_aout );
260 if( val.i_int == AOUT_VAR_5_1 )
262 p_aout->output.output.i_physical_channels
263 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
264 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
267 else if( val.i_int == AOUT_VAR_2F2R )
269 p_aout->output.output.i_physical_channels
270 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
271 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
273 else if( val.i_int == AOUT_VAR_MONO )
275 p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
279 p_aout->output.output.i_physical_channels
280 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
283 if( OpenWaveOutPCM( p_aout, &p_aout->output.output.i_format,
284 p_aout->output.output.i_physical_channels,
285 aout_FormatNbChannels( &p_aout->output.output ),
286 p_aout->output.output.i_rate, VLC_FALSE )
289 msg_Err( p_aout, "cannot open waveout audio device" );
290 free( p_aout->output.p_sys );
294 /* Calculate the frame size in bytes */
295 p_aout->output.i_nb_samples = FRAME_SIZE;
296 aout_FormatPrepare( &p_aout->output.output );
297 p_aout->output.p_sys->i_buffer_size = FRAME_SIZE *
298 p_aout->output.output.i_bytes_per_frame;
300 aout_VolumeSoftInit( p_aout );
302 /* Check for hardware volume support */
303 if( waveOutGetDevCaps( (UINT_PTR)p_aout->output.p_sys->h_waveout,
304 &wocaps, sizeof(wocaps) ) == MMSYSERR_NOERROR &&
305 wocaps.dwSupport & WAVECAPS_VOLUME )
308 if( waveOutGetVolume( p_aout->output.p_sys->h_waveout, &i_dummy )
309 == MMSYSERR_NOERROR )
311 p_aout->output.pf_volume_infos = VolumeInfos;
312 p_aout->output.pf_volume_get = VolumeGet;
313 p_aout->output.pf_volume_set = VolumeSet;
319 waveOutReset( p_aout->output.p_sys->h_waveout );
321 /* Allocate silence buffer */
322 p_aout->output.p_sys->p_silence_buffer =
323 malloc( p_aout->output.p_sys->i_buffer_size );
324 if( p_aout->output.p_sys->p_silence_buffer == NULL )
326 free( p_aout->output.p_sys );
327 msg_Err( p_aout, "out of memory" );
331 /* Zero the buffer. WinCE doesn't have calloc(). */
332 memset( p_aout->output.p_sys->p_silence_buffer, 0,
333 p_aout->output.p_sys->i_buffer_size );
335 /* Now we need to setup our waveOut play notification structure */
336 p_aout->output.p_sys->p_notif =
337 vlc_object_create( p_aout, sizeof(notification_thread_t) );
338 p_aout->output.p_sys->p_notif->p_aout = p_aout;
339 p_aout->output.p_sys->event = CreateEvent( NULL, FALSE, FALSE, NULL );
341 /* Then launch the notification thread */
342 if( vlc_thread_create( p_aout->output.p_sys->p_notif,
343 "waveOut Notification Thread", WaveOutThread,
344 VLC_THREAD_PRIORITY_HIGHEST, VLC_FALSE ) )
346 msg_Err( p_aout, "cannot create WaveOutThread" );
349 /* We need to kick off the playback in order to have the callback properly
351 for( i = 0; i < FRAMES_NUM; i++ )
353 p_aout->output.p_sys->waveheader[i].dwFlags = WHDR_DONE;
354 p_aout->output.p_sys->waveheader[i].dwUser = 0;
356 PlayWaveOut( p_aout, p_aout->output.p_sys->h_waveout,
357 &p_aout->output.p_sys->waveheader[0], NULL );
362 /*****************************************************************************
363 * Probe: probe the audio device for available formats and channels
364 *****************************************************************************/
365 static void Probe( aout_instance_t * p_aout )
367 vlc_value_t val, text;
369 unsigned int i_physical_channels;
371 var_Create( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
372 text.psz_string = _("Audio Device");
373 var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
375 /* Test for 5.1 support */
376 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
377 AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
378 AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE;
379 if( p_aout->output.output.i_physical_channels == i_physical_channels )
381 if( OpenWaveOutPCM( p_aout, &i_format,
382 i_physical_channels, 6,
383 p_aout->output.output.i_rate, VLC_TRUE )
386 val.i_int = AOUT_VAR_5_1;
387 text.psz_string = N_("5.1");
388 var_Change( p_aout, "audio-device",
389 VLC_VAR_ADDCHOICE, &val, &text );
390 msg_Dbg( p_aout, "device supports 5.1 channels" );
394 /* Test for 2 Front 2 Rear support */
395 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
396 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
397 if( ( p_aout->output.output.i_physical_channels & i_physical_channels )
398 == i_physical_channels )
400 if( OpenWaveOutPCM( p_aout, &i_format,
401 i_physical_channels, 4,
402 p_aout->output.output.i_rate, VLC_TRUE )
405 val.i_int = AOUT_VAR_2F2R;
406 text.psz_string = N_("2 Front 2 Rear");
407 var_Change( p_aout, "audio-device",
408 VLC_VAR_ADDCHOICE, &val, &text );
409 msg_Dbg( p_aout, "device supports 4 channels" );
413 /* Test for stereo support */
414 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
415 if( OpenWaveOutPCM( p_aout, &i_format,
416 i_physical_channels, 2,
417 p_aout->output.output.i_rate, VLC_TRUE )
420 val.i_int = AOUT_VAR_STEREO;
421 text.psz_string = N_("Stereo");
422 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
423 msg_Dbg( p_aout, "device supports 2 channels" );
426 /* Test for mono support */
427 i_physical_channels = AOUT_CHAN_CENTER;
428 if( OpenWaveOutPCM( p_aout, &i_format,
429 i_physical_channels, 1,
430 p_aout->output.output.i_rate, VLC_TRUE )
433 val.i_int = AOUT_VAR_MONO;
434 text.psz_string = N_("Mono");
435 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
436 msg_Dbg( p_aout, "device supports 1 channel" );
439 /* Test for SPDIF support */
440 if ( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
442 if( OpenWaveOut( p_aout, VLC_FOURCC('s','p','d','i'),
443 p_aout->output.output.i_physical_channels,
444 aout_FormatNbChannels( &p_aout->output.output ),
445 p_aout->output.output.i_rate, VLC_TRUE )
448 msg_Dbg( p_aout, "device supports A/52 over S/PDIF" );
449 val.i_int = AOUT_VAR_SPDIF;
450 text.psz_string = N_("A/52 over S/PDIF");
451 var_Change( p_aout, "audio-device",
452 VLC_VAR_ADDCHOICE, &val, &text );
453 if( config_GetInt( p_aout, "spdif" ) )
454 var_Set( p_aout, "audio-device", val );
458 var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
461 /* Probe() has failed. */
462 var_Destroy( p_aout, "audio-device" );
466 var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
468 val.b_bool = VLC_TRUE;
469 var_Set( p_aout, "intf-change", val );
472 /*****************************************************************************
473 * Play: play a sound buffer
474 *****************************************************************************
475 * This doesn't actually play the buffer. This just stores the buffer so it
476 * can be played by the callback thread.
477 *****************************************************************************/
478 static void Play( aout_instance_t *_p_aout )
482 /*****************************************************************************
483 * Close: close the audio device
484 *****************************************************************************/
485 static void Close( vlc_object_t *p_this )
487 aout_instance_t *p_aout = (aout_instance_t *)p_this;
488 aout_sys_t *p_sys = p_aout->output.p_sys;
490 /* Before calling waveOutClose we must reset the device */
491 vlc_object_kill( p_aout );
493 waveOutReset( p_sys->h_waveout );
495 /* wake up the audio thread */
496 SetEvent( p_sys->event );
497 vlc_thread_join( p_sys->p_notif );
498 vlc_object_release( p_sys->p_notif );
499 CloseHandle( p_sys->event );
501 /* Close the device */
502 if( waveOutClose( p_sys->h_waveout ) != MMSYSERR_NOERROR )
504 msg_Err( p_aout, "waveOutClose failed" );
507 free( p_sys->p_silence_buffer );
511 /*****************************************************************************
512 * OpenWaveOut: open the waveout sound device
513 ****************************************************************************/
514 static int OpenWaveOut( aout_instance_t *p_aout, int i_format,
515 int i_channels, int i_nb_channels, int i_rate,
521 /* Set sound format */
523 #define waveformat p_aout->output.p_sys->waveformat
525 waveformat.dwChannelMask = 0;
526 for( i = 0; i < sizeof(pi_channels_src)/sizeof(uint32_t); i++ )
528 if( i_channels & pi_channels_src[i] )
529 waveformat.dwChannelMask |= pi_channels_in[i];
534 case VLC_FOURCC('s','p','d','i'):
536 /* To prevent channel re-ordering */
537 waveformat.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
538 waveformat.Format.wBitsPerSample = 16;
539 waveformat.Samples.wValidBitsPerSample =
540 waveformat.Format.wBitsPerSample;
541 waveformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
542 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF;
545 case VLC_FOURCC('f','l','3','2'):
546 waveformat.Format.wBitsPerSample = sizeof(float) * 8;
547 waveformat.Samples.wValidBitsPerSample =
548 waveformat.Format.wBitsPerSample;
549 waveformat.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
550 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
553 case VLC_FOURCC('s','1','6','l'):
554 waveformat.Format.wBitsPerSample = 16;
555 waveformat.Samples.wValidBitsPerSample =
556 waveformat.Format.wBitsPerSample;
557 waveformat.Format.wFormatTag = WAVE_FORMAT_PCM;
558 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_PCM;
562 waveformat.Format.nChannels = i_nb_channels;
563 waveformat.Format.nSamplesPerSec = i_rate;
564 waveformat.Format.nBlockAlign =
565 waveformat.Format.wBitsPerSample / 8 * i_nb_channels;
566 waveformat.Format.nAvgBytesPerSec =
567 waveformat.Format.nSamplesPerSec * waveformat.Format.nBlockAlign;
569 /* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */
570 if( i_nb_channels <= 2 )
572 waveformat.Format.cbSize = 0;
576 waveformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
577 waveformat.Format.cbSize =
578 sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
581 /* Open the device */
582 result = waveOutOpen( &p_aout->output.p_sys->h_waveout, WAVE_MAPPER,
583 (WAVEFORMATEX *)&waveformat,
584 (DWORD_PTR)WaveOutCallback, (DWORD_PTR)p_aout,
585 CALLBACK_FUNCTION | (b_probe?WAVE_FORMAT_QUERY:0) );
586 if( result == WAVERR_BADFORMAT )
588 msg_Warn( p_aout, "waveOutOpen failed WAVERR_BADFORMAT" );
591 if( result == MMSYSERR_ALLOCATED )
593 msg_Warn( p_aout, "waveOutOpen failed WAVERR_ALLOCATED" );
596 if( result != MMSYSERR_NOERROR )
598 msg_Warn( p_aout, "waveOutOpen failed" );
602 p_aout->output.p_sys->b_chan_reorder =
603 aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
604 waveformat.dwChannelMask, i_nb_channels,
605 p_aout->output.p_sys->pi_chan_table );
607 if( p_aout->output.p_sys->b_chan_reorder )
609 msg_Dbg( p_aout, "channel reordering needed" );
618 /*****************************************************************************
619 * OpenWaveOutPCM: open a PCM waveout sound device
620 ****************************************************************************/
621 static int OpenWaveOutPCM( aout_instance_t *p_aout, int *i_format,
622 int i_channels, int i_nb_channels, int i_rate,
627 var_Get( p_aout, "waveout-float32", &val );
629 if( !val.b_bool || OpenWaveOut( p_aout, VLC_FOURCC('f','l','3','2'),
630 i_channels, i_nb_channels, i_rate, b_probe )
633 if ( OpenWaveOut( p_aout, VLC_FOURCC('s','1','6','l'),
634 i_channels, i_nb_channels, i_rate, b_probe )
641 *i_format = VLC_FOURCC('s','1','6','l');
647 *i_format = VLC_FOURCC('f','l','3','2');
652 /*****************************************************************************
653 * PlayWaveOut: play a buffer through the WaveOut device
654 *****************************************************************************/
655 static int PlayWaveOut( aout_instance_t *p_aout, HWAVEOUT h_waveout,
656 WAVEHDR *p_waveheader, aout_buffer_t *p_buffer )
660 /* Prepare the buffer */
661 if( p_buffer != NULL )
662 p_waveheader->lpData = p_buffer->p_buffer;
664 /* Use silence buffer instead */
665 p_waveheader->lpData = p_aout->output.p_sys->p_silence_buffer;
667 p_waveheader->dwUser = p_buffer ? (DWORD_PTR)p_buffer : (DWORD_PTR)1;
668 p_waveheader->dwBufferLength = p_aout->output.p_sys->i_buffer_size;
669 p_waveheader->dwFlags = 0;
671 result = waveOutPrepareHeader( h_waveout, p_waveheader, sizeof(WAVEHDR) );
672 if( result != MMSYSERR_NOERROR )
674 msg_Err( p_aout, "waveOutPrepareHeader failed" );
678 /* Send the buffer to the waveOut queue */
679 result = waveOutWrite( h_waveout, p_waveheader, sizeof(WAVEHDR) );
680 if( result != MMSYSERR_NOERROR )
682 msg_Err( p_aout, "waveOutWrite failed" );
689 /*****************************************************************************
690 * WaveOutCallback: what to do once WaveOut has played its sound samples
691 *****************************************************************************/
692 static void CALLBACK WaveOutCallback( HWAVEOUT h_waveout, UINT uMsg,
694 DWORD dwParam1, DWORD dwParam2 )
696 aout_instance_t *p_aout = (aout_instance_t *)_p_aout;
697 int i, i_queued_frames = 0;
699 if( uMsg != WOM_DONE ) return;
701 if( p_aout->b_die ) return;
703 /* Find out the current latency */
704 for( i = 0; i < FRAMES_NUM; i++ )
706 /* Check if frame buf is available */
707 if( !(p_aout->output.p_sys->waveheader[i].dwFlags & WHDR_DONE) )
713 /* Don't wake up the thread too much */
714 if( i_queued_frames < FRAMES_NUM / 2 )
715 SetEvent( p_aout->output.p_sys->event );
718 /*****************************************************************************
719 * WaveOutThread: this thread will capture play notification events.
720 *****************************************************************************
721 * We use this thread to feed new audio samples to the sound card because
722 * we are not authorized to use waveOutWrite() directly in the waveout
724 *****************************************************************************/
725 static void WaveOutThread( notification_thread_t *p_notif )
727 aout_instance_t *p_aout = p_notif->p_aout;
728 aout_sys_t *p_sys = p_aout->output.p_sys;
729 aout_buffer_t *p_buffer = NULL;
730 WAVEHDR *p_waveheader = p_sys->waveheader;
731 int i, i_queued_frames;
734 /* We don't want any resampling when using S/PDIF */
735 b_sleek = p_aout->output.output.i_format == VLC_FOURCC('s','p','d','i');
739 WaitForSingleObject( p_sys->event, INFINITE );
741 /* Cleanup and find out the current latency */
743 for( i = 0; i < FRAMES_NUM; i++ )
745 if( (p_waveheader[i].dwFlags & WHDR_DONE) &&
746 p_waveheader[i].dwUser )
748 aout_buffer_t *p_buffer =
749 (aout_buffer_t *)(p_waveheader[i].dwUser);
750 /* Unprepare and free the buffers which has just been played */
751 waveOutUnprepareHeader( p_sys->h_waveout, &p_waveheader[i],
754 if( p_waveheader[i].dwUser != 1 )
755 aout_BufferFree( p_buffer );
757 p_waveheader[i].dwUser = 0;
760 /* Check if frame buf is available */
761 if( !(p_waveheader[i].dwFlags & WHDR_DONE) )
767 if( p_aout->b_die ) return;
769 /* Try to fill in as many frame buffers as possible */
770 for( i = 0; i < FRAMES_NUM; i++ )
772 /* Check if frame buf is available */
773 if( p_waveheader[i].dwFlags & WHDR_DONE )
775 /* Take into account the latency */
776 p_buffer = aout_OutputNextBuffer( p_aout,
777 mdate() + 1000000 * i_queued_frames /
778 p_aout->output.output.i_rate * p_aout->output.i_nb_samples,
781 if( !p_buffer && i_queued_frames )
783 /* We aren't late so no need to play a blank sample */
787 /* Do the channel reordering */
788 if( p_buffer && p_sys->b_chan_reorder )
790 aout_ChannelReorder( p_buffer->p_buffer,
791 p_buffer->i_nb_bytes,
792 p_sys->waveformat.Format.nChannels,
793 p_sys->pi_chan_table,
794 p_sys->waveformat.Format.wBitsPerSample );
797 PlayWaveOut( p_aout, p_sys->h_waveout,
798 &p_waveheader[i], p_buffer );
806 static int VolumeInfos( aout_instance_t * p_aout, audio_volume_t * pi_soft )
808 *pi_soft = AOUT_VOLUME_MAX / 2;
812 static int VolumeGet( aout_instance_t * p_aout, audio_volume_t * pi_volume )
817 waveOutGetVolume( 0, &i_waveout_vol );
819 waveOutGetVolume( p_aout->output.p_sys->h_waveout, &i_waveout_vol );
822 i_waveout_vol &= 0xFFFF;
823 *pi_volume = p_aout->output.i_volume =
824 (i_waveout_vol * AOUT_VOLUME_MAX + 0xFFFF /*rounding*/) / 2 / 0xFFFF;
828 static int VolumeSet( aout_instance_t * p_aout, audio_volume_t i_volume )
830 unsigned long i_waveout_vol = i_volume * 0xFFFF * 2 / AOUT_VOLUME_MAX;
831 i_waveout_vol |= (i_waveout_vol << 16);
834 waveOutSetVolume( 0, i_waveout_vol );
836 waveOutSetVolume( p_aout->output.p_sys->h_waveout, i_waveout_vol );
839 p_aout->output.i_volume = i_volume;