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 *****************************************************************************/
34 #include <vlc_charset.h>
39 #define FRAME_SIZE 4096 /* The size is in samples, not in bytes */
42 /*****************************************************************************
44 *****************************************************************************/
46 # define DWORD_PTR DWORD
47 # ifdef waveOutGetDevCaps
48 # undef waveOutGetDevCaps
49 MMRESULT WINAPI waveOutGetDevCaps(UINT, LPWAVEOUTCAPS, UINT);
53 #ifndef WAVE_FORMAT_IEEE_FLOAT
54 # define WAVE_FORMAT_IEEE_FLOAT 0x0003
57 #ifndef WAVE_FORMAT_DOLBY_AC3_SPDIF
58 # define WAVE_FORMAT_DOLBY_AC3_SPDIF 0x0092
61 #ifndef WAVE_FORMAT_EXTENSIBLE
62 #define WAVE_FORMAT_EXTENSIBLE 0xFFFE
65 #ifndef SPEAKER_FRONT_LEFT
66 # define SPEAKER_FRONT_LEFT 0x1
67 # define SPEAKER_FRONT_RIGHT 0x2
68 # define SPEAKER_FRONT_CENTER 0x4
69 # define SPEAKER_LOW_FREQUENCY 0x8
70 # define SPEAKER_BACK_LEFT 0x10
71 # define SPEAKER_BACK_RIGHT 0x20
72 # define SPEAKER_FRONT_LEFT_OF_CENTER 0x40
73 # define SPEAKER_FRONT_RIGHT_OF_CENTER 0x80
74 # define SPEAKER_BACK_CENTER 0x100
75 # define SPEAKER_SIDE_LEFT 0x200
76 # define SPEAKER_SIDE_RIGHT 0x400
77 # define SPEAKER_TOP_CENTER 0x800
78 # define SPEAKER_TOP_FRONT_LEFT 0x1000
79 # define SPEAKER_TOP_FRONT_CENTER 0x2000
80 # define SPEAKER_TOP_FRONT_RIGHT 0x4000
81 # define SPEAKER_TOP_BACK_LEFT 0x8000
82 # define SPEAKER_TOP_BACK_CENTER 0x10000
83 # define SPEAKER_TOP_BACK_RIGHT 0x20000
84 # define SPEAKER_RESERVED 0x80000000
87 #ifndef _WAVEFORMATEXTENSIBLE_
91 WORD wValidBitsPerSample; /* bits of precision */
92 WORD wSamplesPerBlock; /* valid if wBitsPerSample==0 */
93 WORD wReserved; /* If neither applies, set to zero. */
95 DWORD dwChannelMask; /* which channels are */
96 /* present in stream */
98 } WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE;
101 static const GUID __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = {WAVE_FORMAT_IEEE_FLOAT, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
102 static const GUID __KSDATAFORMAT_SUBTYPE_PCM = {WAVE_FORMAT_PCM, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
103 static const GUID __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF = {WAVE_FORMAT_DOLBY_AC3_SPDIF, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
105 /*****************************************************************************
107 *****************************************************************************/
108 static int Open ( vlc_object_t * );
109 static void Close ( vlc_object_t * );
110 static void Play ( aout_instance_t * );
112 /*****************************************************************************
113 * notification_thread_t: waveOut event thread
114 *****************************************************************************/
115 typedef struct notification_thread_t
118 aout_instance_t *p_aout;
120 } notification_thread_t;
122 /* local functions */
123 static void Probe ( aout_instance_t * );
124 static int OpenWaveOut ( aout_instance_t *, uint32_t,
125 int, int, int, int, vlc_bool_t );
126 static int OpenWaveOutPCM( aout_instance_t *, uint32_t,
127 int*, int, int, int, vlc_bool_t );
128 static int PlayWaveOut ( aout_instance_t *, HWAVEOUT, WAVEHDR *,
129 aout_buffer_t *, vlc_bool_t );
131 static void CALLBACK WaveOutCallback ( HWAVEOUT, UINT, DWORD, DWORD, DWORD );
132 static void WaveOutThread( notification_thread_t * );
134 static int VolumeInfos( aout_instance_t *, audio_volume_t * );
135 static int VolumeGet( aout_instance_t *, audio_volume_t * );
136 static int VolumeSet( aout_instance_t *, audio_volume_t );
138 static int WaveOutClearDoneBuffers(aout_sys_t *p_sys);
140 static int ReloadWaveoutDevices( vlc_object_t *, char const *,
141 vlc_value_t, vlc_value_t, void * );
142 static uint32_t findDeviceID(char *);
144 static const char psz_device_name_fmt[] = "%s ($%x,$%x)";
146 static const char *ppsz_adev[] = { "wavemapper", };
147 static const char *ppsz_adev_text[] = { N_("Microsoft Soundmapper") };
151 /*****************************************************************************
153 *****************************************************************************/
154 #define FLOAT_TEXT N_("Use float32 output")
155 #define FLOAT_LONGTEXT N_( \
156 "The option allows you to enable or disable the high-quality float32 " \
157 "audio output mode (which is not well supported by some soundcards)." )
158 #define DEVICE_TEXT N_("Select Audio Device")
159 #define DEVICE_LONG N_("Select special Audio device, or let windows "\
160 "decide (default), change needs VLC restart "\
162 #define DEFAULT_AUDIO_DEVICE N_("Default Audio Device")
165 set_shortname( "WaveOut" );
166 set_description( _("Win32 waveOut extension output") );
167 set_capability( "audio output", 50 );
168 set_category( CAT_AUDIO );
169 set_subcategory( SUBCAT_AUDIO_AOUT );
170 add_bool( "waveout-float32", 1, 0, FLOAT_TEXT, FLOAT_LONGTEXT, VLC_TRUE );
172 add_string( "waveout-dev", "wavemapper", NULL,
173 DEVICE_TEXT, DEVICE_LONG, VLC_FALSE );
174 change_string_list( ppsz_adev, ppsz_adev_text, ReloadWaveoutDevices );
175 change_need_restart();
176 change_action_add( ReloadWaveoutDevices, N_("Refresh list") );
179 set_callbacks( Open, Close );
182 /*****************************************************************************
183 * aout_sys_t: waveOut audio output method descriptor
184 *****************************************************************************
185 * This structure is part of the audio output thread descriptor.
186 * It describes the waveOut specific properties of an audio device.
187 *****************************************************************************/
190 uint32_t i_wave_device_id; /* ID of selected output device */
192 HWAVEOUT h_waveout; /* handle to waveout instance */
194 WAVEFORMATEXTENSIBLE waveformat; /* audio format */
196 WAVEHDR waveheader[FRAMES_NUM];
198 notification_thread_t *p_notif; /* WaveOutThread id */
200 HANDLE new_buffer_event;
202 // rental from alsa.c to synchronize startup of audiothread
203 int b_playing; /* playing status */
206 int i_repeat_counter;
210 byte_t *p_silence_buffer; /* buffer we use to play silence */
212 vlc_bool_t b_chan_reorder; /* do we need channel reordering */
213 int pi_chan_table[AOUT_CHAN_MAX];
216 static const uint32_t pi_channels_src[] =
217 { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT,
218 AOUT_CHAN_MIDDLELEFT, AOUT_CHAN_MIDDLERIGHT,
219 AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT,
220 AOUT_CHAN_CENTER, AOUT_CHAN_LFE, 0 };
221 static const uint32_t pi_channels_in[] =
222 { SPEAKER_FRONT_LEFT, SPEAKER_FRONT_RIGHT,
223 SPEAKER_SIDE_LEFT, SPEAKER_SIDE_RIGHT,
224 SPEAKER_BACK_LEFT, SPEAKER_BACK_RIGHT,
225 SPEAKER_FRONT_CENTER, SPEAKER_LOW_FREQUENCY, 0 };
226 static const uint32_t pi_channels_out[] =
227 { SPEAKER_FRONT_LEFT, SPEAKER_FRONT_RIGHT,
228 SPEAKER_FRONT_CENTER, SPEAKER_LOW_FREQUENCY,
229 SPEAKER_BACK_LEFT, SPEAKER_BACK_RIGHT,
230 SPEAKER_SIDE_LEFT, SPEAKER_SIDE_RIGHT, 0 };
232 /*****************************************************************************
233 * Open: open the audio device
234 *****************************************************************************
235 * This function opens and setups Win32 waveOut
236 *****************************************************************************/
237 static int Open( vlc_object_t *p_this )
239 aout_instance_t *p_aout = (aout_instance_t *)p_this;
243 /* Allocate structure */
244 p_aout->output.p_sys = malloc( sizeof( aout_sys_t ) );
246 if( p_aout->output.p_sys == NULL )
248 msg_Err( p_aout, "out of memory" );
252 p_aout->output.pf_play = Play;
253 p_aout->b_die = VLC_FALSE;
257 initialize/update Device selection List
259 ReloadWaveoutDevices( p_this, "waveout-dev", val, val, NULL);
263 check for configured audio device!
265 char *psz_waveout_dev = var_CreateGetString( p_aout, "waveout-dev");
267 p_aout->output.p_sys->i_wave_device_id =
268 findDeviceID( psz_waveout_dev );
270 if(p_aout->output.p_sys->i_wave_device_id == WAVE_MAPPER)
272 if(psz_waveout_dev &&
273 stricmp(psz_waveout_dev,"wavemapper"))
275 msg_Warn( p_aout, "configured audio device '%s' not available, "\
276 "use default instead", psz_waveout_dev );
279 if(psz_waveout_dev) free( psz_waveout_dev );
282 WAVEOUTCAPS waveoutcaps;
283 if(waveOutGetDevCaps( p_aout->output.p_sys->i_wave_device_id,
285 sizeof(WAVEOUTCAPS)) == MMSYSERR_NOERROR)
287 /* log debug some infos about driver, to know who to blame
288 if it doesn't work */
289 msg_Dbg( p_aout, "Drivername: %s", waveoutcaps.szPname);
290 msg_Dbg( p_aout, "Driver Version: %d.%d",
291 (waveoutcaps.vDriverVersion>>8)&255,
292 waveoutcaps.vDriverVersion & 255);
293 msg_Dbg( p_aout, "Manufacturer identifier: 0x%x", waveoutcaps.wMid );
294 msg_Dbg( p_aout, "Product identifier: 0x%x", waveoutcaps.wPid );
299 if( var_Type( p_aout, "audio-device" ) == 0 )
304 if( var_Get( p_aout, "audio-device", &val ) < 0 )
306 /* Probe() has failed. */
307 var_Destroy( p_aout, "waveout-device");
308 free( p_aout->output.p_sys );
313 /* Open the device */
314 if( val.i_int == AOUT_VAR_SPDIF )
316 p_aout->output.output.i_format = VLC_FOURCC('s','p','d','i');
318 if( OpenWaveOut( p_aout,
319 p_aout->output.p_sys->i_wave_device_id,
320 VLC_FOURCC('s','p','d','i'),
321 p_aout->output.output.i_physical_channels,
322 aout_FormatNbChannels( &p_aout->output.output ),
323 p_aout->output.output.i_rate, VLC_FALSE )
326 msg_Err( p_aout, "cannot open waveout audio device" );
327 free( p_aout->output.p_sys );
331 /* Calculate the frame size in bytes */
332 p_aout->output.i_nb_samples = A52_FRAME_NB;
333 p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
334 p_aout->output.output.i_frame_length = A52_FRAME_NB;
335 p_aout->output.p_sys->i_buffer_size =
336 p_aout->output.output.i_bytes_per_frame;
338 aout_VolumeNoneInit( p_aout );
344 if( val.i_int == AOUT_VAR_5_1 )
346 p_aout->output.output.i_physical_channels
347 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
348 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
351 else if( val.i_int == AOUT_VAR_2F2R )
353 p_aout->output.output.i_physical_channels
354 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
355 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
357 else if( val.i_int == AOUT_VAR_MONO )
359 p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
363 p_aout->output.output.i_physical_channels
364 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
367 if( OpenWaveOutPCM( p_aout,
368 p_aout->output.p_sys->i_wave_device_id,
369 &p_aout->output.output.i_format,
370 p_aout->output.output.i_physical_channels,
371 aout_FormatNbChannels( &p_aout->output.output ),
372 p_aout->output.output.i_rate, VLC_FALSE )
375 msg_Err( p_aout, "cannot open waveout audio device" );
376 free( p_aout->output.p_sys );
380 /* Calculate the frame size in bytes */
381 p_aout->output.i_nb_samples = FRAME_SIZE;
382 aout_FormatPrepare( &p_aout->output.output );
383 p_aout->output.p_sys->i_buffer_size = FRAME_SIZE *
384 p_aout->output.output.i_bytes_per_frame;
386 aout_VolumeSoftInit( p_aout );
388 /* Check for hardware volume support */
389 if( waveOutGetDevCaps( (UINT_PTR)p_aout->output.p_sys->h_waveout,
390 &wocaps, sizeof(wocaps) ) == MMSYSERR_NOERROR &&
391 wocaps.dwSupport & WAVECAPS_VOLUME )
394 if( waveOutGetVolume( p_aout->output.p_sys->h_waveout, &i_dummy )
395 == MMSYSERR_NOERROR )
397 p_aout->output.pf_volume_infos = VolumeInfos;
398 p_aout->output.pf_volume_get = VolumeGet;
399 p_aout->output.pf_volume_set = VolumeSet;
405 waveOutReset( p_aout->output.p_sys->h_waveout );
407 /* Allocate silence buffer */
408 p_aout->output.p_sys->p_silence_buffer =
409 malloc( p_aout->output.p_sys->i_buffer_size );
410 if( p_aout->output.p_sys->p_silence_buffer == NULL )
412 free( p_aout->output.p_sys );
413 msg_Err( p_aout, "out of memory" );
416 p_aout->output.p_sys->i_repeat_counter = 0;
419 /* Zero the buffer. WinCE doesn't have calloc(). */
420 memset( p_aout->output.p_sys->p_silence_buffer, 0,
421 p_aout->output.p_sys->i_buffer_size );
423 /* Now we need to setup our waveOut play notification structure */
424 p_aout->output.p_sys->p_notif =
425 vlc_object_create( p_aout, sizeof(notification_thread_t) );
426 p_aout->output.p_sys->p_notif->p_aout = p_aout;
427 p_aout->output.p_sys->event = CreateEvent( NULL, FALSE, FALSE, NULL );
428 p_aout->output.p_sys->new_buffer_event = CreateEvent( NULL, FALSE, FALSE, NULL );
430 /* define startpoint of playback on first call to play()
431 like alsa does (instead of playing a blank sample) */
432 p_aout->output.p_sys->b_playing = 0;
433 p_aout->output.p_sys->start_date = 0;
436 /* Then launch the notification thread */
437 if( vlc_thread_create( p_aout->output.p_sys->p_notif,
438 "waveOut Notification Thread", WaveOutThread,
439 VLC_THREAD_PRIORITY_OUTPUT, VLC_FALSE ) )
441 msg_Err( p_aout, "cannot create WaveOutThread" );
444 /* We need to kick off the playback in order to have the callback properly
446 for( i = 0; i < FRAMES_NUM; i++ )
448 p_aout->output.p_sys->waveheader[i].dwFlags = WHDR_DONE;
449 p_aout->output.p_sys->waveheader[i].dwUser = 0;
455 /*****************************************************************************
456 * Probe: probe the audio device for available formats and channels
457 *****************************************************************************/
458 static void Probe( aout_instance_t * p_aout )
460 vlc_value_t val, text;
462 unsigned int i_physical_channels;
464 var_Create( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
465 text.psz_string = _("Audio Device");
466 var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
468 /* Test for 5.1 support */
469 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
470 AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
471 AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE;
472 if( p_aout->output.output.i_physical_channels == i_physical_channels )
474 if( OpenWaveOutPCM( p_aout,
475 p_aout->output.p_sys->i_wave_device_id,
477 i_physical_channels, 6,
478 p_aout->output.output.i_rate, VLC_TRUE )
481 val.i_int = AOUT_VAR_5_1;
482 text.psz_string = (char *)N_("5.1");
483 var_Change( p_aout, "audio-device",
484 VLC_VAR_ADDCHOICE, &val, &text );
485 msg_Dbg( p_aout, "device supports 5.1 channels" );
489 /* Test for 2 Front 2 Rear support */
490 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
491 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
492 if( ( p_aout->output.output.i_physical_channels & i_physical_channels )
493 == i_physical_channels )
495 if( OpenWaveOutPCM( p_aout,
496 p_aout->output.p_sys->i_wave_device_id,
498 i_physical_channels, 4,
499 p_aout->output.output.i_rate, VLC_TRUE )
502 val.i_int = AOUT_VAR_2F2R;
503 text.psz_string = (char *)N_("2 Front 2 Rear");
504 var_Change( p_aout, "audio-device",
505 VLC_VAR_ADDCHOICE, &val, &text );
506 msg_Dbg( p_aout, "device supports 4 channels" );
510 /* Test for stereo support */
511 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
512 if( OpenWaveOutPCM( p_aout,
513 p_aout->output.p_sys->i_wave_device_id,
515 i_physical_channels, 2,
516 p_aout->output.output.i_rate, VLC_TRUE )
519 val.i_int = AOUT_VAR_STEREO;
520 text.psz_string = (char *)N_("Stereo");
521 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
522 msg_Dbg( p_aout, "device supports 2 channels" );
525 /* Test for mono support */
526 i_physical_channels = AOUT_CHAN_CENTER;
527 if( OpenWaveOutPCM( p_aout,
528 p_aout->output.p_sys->i_wave_device_id,
530 i_physical_channels, 1,
531 p_aout->output.output.i_rate, VLC_TRUE )
534 val.i_int = AOUT_VAR_MONO;
535 text.psz_string = (char *)N_("Mono");
536 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
537 msg_Dbg( p_aout, "device supports 1 channel" );
540 /* Test for SPDIF support */
541 if ( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
543 if( OpenWaveOut( p_aout,
544 p_aout->output.p_sys->i_wave_device_id,
545 VLC_FOURCC('s','p','d','i'),
546 p_aout->output.output.i_physical_channels,
547 aout_FormatNbChannels( &p_aout->output.output ),
548 p_aout->output.output.i_rate, VLC_TRUE )
551 msg_Dbg( p_aout, "device supports A/52 over S/PDIF" );
552 val.i_int = AOUT_VAR_SPDIF;
553 text.psz_string = (char *)N_("A/52 over S/PDIF");
554 var_Change( p_aout, "audio-device",
555 VLC_VAR_ADDCHOICE, &val, &text );
556 if( config_GetInt( p_aout, "spdif" ) )
557 var_Set( p_aout, "audio-device", val );
561 var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
564 /* Probe() has failed. */
565 var_Destroy( p_aout, "audio-device" );
569 var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
571 val.b_bool = VLC_TRUE;
572 var_Set( p_aout, "intf-change", val );
575 /*****************************************************************************
576 * Play: play a sound buffer
577 *****************************************************************************
578 * This doesn't actually play the buffer. This just stores the buffer so it
579 * can be played by the callback thread.
580 *****************************************************************************/
581 static void Play( aout_instance_t *_p_aout )
583 if( !_p_aout->output.p_sys->b_playing )
585 _p_aout->output.p_sys->b_playing = 1;
587 /* get the playing date of the first aout buffer */
588 _p_aout->output.p_sys->start_date =
589 aout_FifoFirstDate( _p_aout, &_p_aout->output.fifo );
591 msg_Dbg( _p_aout, "Wakeup sleeping output thread.");
593 /* wake up the audio output thread */
594 SetEvent( _p_aout->output.p_sys->event );
596 SetEvent( _p_aout->output.p_sys->new_buffer_event );
600 /*****************************************************************************
601 * Close: close the audio device
602 *****************************************************************************/
603 static void Close( vlc_object_t *p_this )
605 aout_instance_t *p_aout = (aout_instance_t *)p_this;
606 aout_sys_t *p_sys = p_aout->output.p_sys;
608 /* Before calling waveOutClose we must reset the device */
609 vlc_object_kill( p_aout );
611 /* wake up the audio thread, to recognize that p_aout died */
612 SetEvent( p_sys->event );
613 SetEvent( p_sys->new_buffer_event );
615 vlc_thread_join( p_sys->p_notif );
616 vlc_object_release( p_sys->p_notif );
619 kill the real output then - when the feed thread
620 is surely terminated!
621 old code could be too early in case that "feeding"
622 was running on termination
624 at this point now its sure, that there will be no new
625 data send to the driver, and we can cancel the last
628 MMRESULT result = waveOutReset( p_sys->h_waveout );
629 if(result != MMSYSERR_NOERROR)
631 msg_Err( p_aout, "waveOutReset failed 0x%x", result );
633 now we must wait, that all buffers are played
634 because cancel doesn't work in this case...
636 if(result == MMSYSERR_NOTSUPPORTED)
639 clear currently played (done) buffers,
640 if returnvalue > 0 (means some buffer still playing)
641 wait for the driver event callback that one buffer
642 is finished with playing, and check again
643 the timeout of 5000ms is just, an emergency exit
644 of this loop, to avoid deadlock in case of other
645 (currently not known bugs, problems, errors cases?)
648 (WaveOutClearDoneBuffers( p_sys ) > 0)
650 (WaitForSingleObject( p_sys->event, 5000) == WAIT_OBJECT_0)
653 msg_Dbg( p_aout, "Wait for waveout device...");
657 WaveOutClearDoneBuffers( p_sys );
660 /* now we can Close the device */
661 if( waveOutClose( p_sys->h_waveout ) != MMSYSERR_NOERROR )
663 msg_Err( p_aout, "waveOutClose failed" );
667 because so long, the waveout device is playing, the callback
668 could occur and need the events
670 CloseHandle( p_sys->event );
671 CloseHandle( p_sys->new_buffer_event);
673 free( p_sys->p_silence_buffer );
677 /*****************************************************************************
678 * OpenWaveOut: open the waveout sound device
679 ****************************************************************************/
680 static int OpenWaveOut( aout_instance_t *p_aout, uint32_t i_device_id, int i_format,
681 int i_channels, int i_nb_channels, int i_rate,
687 /* Set sound format */
689 #define waveformat p_aout->output.p_sys->waveformat
691 waveformat.dwChannelMask = 0;
692 for( i = 0; i < sizeof(pi_channels_src)/sizeof(uint32_t); i++ )
694 if( i_channels & pi_channels_src[i] )
695 waveformat.dwChannelMask |= pi_channels_in[i];
700 case VLC_FOURCC('s','p','d','i'):
702 /* To prevent channel re-ordering */
703 waveformat.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
704 waveformat.Format.wBitsPerSample = 16;
705 waveformat.Samples.wValidBitsPerSample =
706 waveformat.Format.wBitsPerSample;
707 waveformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
708 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF;
711 case VLC_FOURCC('f','l','3','2'):
712 waveformat.Format.wBitsPerSample = sizeof(float) * 8;
713 waveformat.Samples.wValidBitsPerSample =
714 waveformat.Format.wBitsPerSample;
715 waveformat.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
716 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
719 case VLC_FOURCC('s','1','6','l'):
720 waveformat.Format.wBitsPerSample = 16;
721 waveformat.Samples.wValidBitsPerSample =
722 waveformat.Format.wBitsPerSample;
723 waveformat.Format.wFormatTag = WAVE_FORMAT_PCM;
724 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_PCM;
728 waveformat.Format.nChannels = i_nb_channels;
729 waveformat.Format.nSamplesPerSec = i_rate;
730 waveformat.Format.nBlockAlign =
731 waveformat.Format.wBitsPerSample / 8 * i_nb_channels;
732 waveformat.Format.nAvgBytesPerSec =
733 waveformat.Format.nSamplesPerSec * waveformat.Format.nBlockAlign;
735 /* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */
736 if( i_nb_channels <= 2 )
738 waveformat.Format.cbSize = 0;
742 waveformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
743 waveformat.Format.cbSize =
744 sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
748 msg_Dbg( p_aout, "OpenWaveDevice-ID: %u", i_device_id);
749 msg_Dbg( p_aout,"waveformat.Format.cbSize = %d",
750 waveformat.Format.cbSize);
751 msg_Dbg( p_aout,"waveformat.Format.wFormatTag = %u",
752 waveformat.Format.wFormatTag);
753 msg_Dbg( p_aout,"waveformat.Format.nChannels = %u",
754 waveformat.Format.nChannels);
755 msg_Dbg( p_aout,"waveformat.Format.nSamplesPerSec = %d",
756 (int)waveformat.Format.nSamplesPerSec);
757 msg_Dbg( p_aout,"waveformat.Format.nAvgBytesPerSec = %u",
758 (int)waveformat.Format.nAvgBytesPerSec);
759 msg_Dbg( p_aout,"waveformat.Format.nBlockAlign = %d",
760 waveformat.Format.nBlockAlign);
761 msg_Dbg( p_aout,"waveformat.Format.wBitsPerSample = %d",
762 waveformat.Format.wBitsPerSample);
763 msg_Dbg( p_aout,"waveformat.Samples.wValidBitsPerSample = %d",
764 waveformat.Samples.wValidBitsPerSample);
765 msg_Dbg( p_aout,"waveformat.Samples.wSamplesPerBlock = %d",
766 waveformat.Samples.wSamplesPerBlock);
767 msg_Dbg( p_aout,"waveformat.dwChannelMask = %lu",
768 waveformat.dwChannelMask);
771 /* Open the device */
772 result = waveOutOpen( &p_aout->output.p_sys->h_waveout, i_device_id,
773 (WAVEFORMATEX *)&waveformat,
774 (DWORD_PTR)WaveOutCallback, (DWORD_PTR)p_aout,
775 CALLBACK_FUNCTION | (b_probe?WAVE_FORMAT_QUERY:0) );
776 if( result == WAVERR_BADFORMAT )
778 msg_Warn( p_aout, "waveOutOpen failed WAVERR_BADFORMAT" );
781 if( result == MMSYSERR_ALLOCATED )
783 msg_Warn( p_aout, "waveOutOpen failed WAVERR_ALLOCATED" );
786 if( result != MMSYSERR_NOERROR )
788 msg_Warn( p_aout, "waveOutOpen failed" );
792 p_aout->output.p_sys->b_chan_reorder =
793 aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
794 waveformat.dwChannelMask, i_nb_channels,
795 p_aout->output.p_sys->pi_chan_table );
797 if( p_aout->output.p_sys->b_chan_reorder )
799 msg_Dbg( p_aout, "channel reordering needed" );
808 /*****************************************************************************
809 * OpenWaveOutPCM: open a PCM waveout sound device
810 ****************************************************************************/
811 static int OpenWaveOutPCM( aout_instance_t *p_aout, uint32_t i_device_id, int *i_format,
812 int i_channels, int i_nb_channels, int i_rate,
815 vlc_bool_t b_use_float32 = var_CreateGetBool( p_aout, "waveout-float32");
817 if( !b_use_float32 || OpenWaveOut( p_aout, i_device_id, VLC_FOURCC('f','l','3','2'),
818 i_channels, i_nb_channels, i_rate, b_probe )
821 if ( OpenWaveOut( p_aout, i_device_id, VLC_FOURCC('s','1','6','l'),
822 i_channels, i_nb_channels, i_rate, b_probe )
829 *i_format = VLC_FOURCC('s','1','6','l');
835 *i_format = VLC_FOURCC('f','l','3','2');
840 /*****************************************************************************
841 * PlayWaveOut: play a buffer through the WaveOut device
842 *****************************************************************************/
843 static int PlayWaveOut( aout_instance_t *p_aout, HWAVEOUT h_waveout,
844 WAVEHDR *p_waveheader, aout_buffer_t *p_buffer,
849 /* Prepare the buffer */
850 if( p_buffer != NULL )
852 p_waveheader->lpData = p_buffer->p_buffer;
854 copy the buffer to the silence buffer :) so in case we don't
855 get the next buffer fast enough (I will repeat this one a time
856 for AC3 / DTS and SPDIF this will sound better instead of
861 p_aout->p_libvlc->pf_memcpy( p_aout->output.p_sys->p_silence_buffer,
863 p_aout->output.p_sys->i_buffer_size );
864 p_aout->output.p_sys->i_repeat_counter = 2;
867 /* Use silence buffer instead */
868 if(p_aout->output.p_sys->i_repeat_counter)
870 p_aout->output.p_sys->i_repeat_counter--;
871 if(!p_aout->output.p_sys->i_repeat_counter)
873 p_aout->p_libvlc->pf_memset( p_aout->output.p_sys->p_silence_buffer,
875 p_aout->output.p_sys->i_buffer_size
879 p_waveheader->lpData = p_aout->output.p_sys->p_silence_buffer;
882 p_waveheader->dwUser = p_buffer ? (DWORD_PTR)p_buffer : (DWORD_PTR)1;
883 p_waveheader->dwBufferLength = p_aout->output.p_sys->i_buffer_size;
884 p_waveheader->dwFlags = 0;
886 result = waveOutPrepareHeader( h_waveout, p_waveheader, sizeof(WAVEHDR) );
887 if( result != MMSYSERR_NOERROR )
889 msg_Err( p_aout, "waveOutPrepareHeader failed" );
893 /* Send the buffer to the waveOut queue */
894 result = waveOutWrite( h_waveout, p_waveheader, sizeof(WAVEHDR) );
895 if( result != MMSYSERR_NOERROR )
897 msg_Err( p_aout, "waveOutWrite failed" );
904 /*****************************************************************************
905 * WaveOutCallback: what to do once WaveOut has played its sound samples
906 *****************************************************************************/
907 static void CALLBACK WaveOutCallback( HWAVEOUT h_waveout, UINT uMsg,
909 DWORD dwParam1, DWORD dwParam2 )
911 aout_instance_t *p_aout = (aout_instance_t *)_p_aout;
912 int i, i_queued_frames = 0;
914 if( uMsg != WOM_DONE ) return;
916 if( p_aout->b_die ) return;
918 /* Find out the current latency */
919 for( i = 0; i < FRAMES_NUM; i++ )
921 /* Check if frame buf is available */
922 if( !(p_aout->output.p_sys->waveheader[i].dwFlags & WHDR_DONE) )
928 /* Don't wake up the thread too much */
929 if( i_queued_frames <= FRAMES_NUM/2 )
930 SetEvent( p_aout->output.p_sys->event );
934 /****************************************************************************
935 * WaveOutClearDoneBuffers: Clear all done marked buffers, and free aout_bufer
936 ****************************************************************************
937 * return value is the number of still playing buffers in the queue
938 ****************************************************************************/
939 static int WaveOutClearDoneBuffers(aout_sys_t *p_sys)
941 WAVEHDR *p_waveheader = p_sys->waveheader;
942 int i_queued_frames = 0;
944 for( int i = 0; i < FRAMES_NUM; i++ )
946 if( (p_waveheader[i].dwFlags & WHDR_DONE) &&
947 p_waveheader[i].dwUser )
949 aout_buffer_t *p_buffer =
950 (aout_buffer_t *)(p_waveheader[i].dwUser);
951 /* Unprepare and free the buffers which has just been played */
952 waveOutUnprepareHeader( p_sys->h_waveout, &p_waveheader[i],
955 if( p_waveheader[i].dwUser != 1 )
956 aout_BufferFree( p_buffer );
958 p_waveheader[i].dwUser = 0;
961 /* Check if frame buf is available */
962 if( !(p_waveheader[i].dwFlags & WHDR_DONE) )
967 return i_queued_frames;
970 /*****************************************************************************
971 * WaveOutThread: this thread will capture play notification events.
972 *****************************************************************************
973 * We use this thread to feed new audio samples to the sound card because
974 * we are not authorized to use waveOutWrite() directly in the waveout
976 *****************************************************************************/
977 static void WaveOutThread( notification_thread_t *p_notif )
979 aout_instance_t *p_aout = p_notif->p_aout;
980 aout_sys_t *p_sys = p_aout->output.p_sys;
981 aout_buffer_t *p_buffer = NULL;
982 WAVEHDR *p_waveheader = p_sys->waveheader;
983 int i, i_queued_frames;
986 uint32_t i_buffer_length = 64;
988 /* We don't want any resampling when using S/PDIF */
989 b_sleek = p_aout->output.output.i_format == VLC_FOURCC('s','p','d','i');
991 // wait for first call to "play()"
992 while( !p_sys->start_date && !p_aout->b_die )
993 WaitForSingleObject( p_sys->event, INFINITE );
997 msg_Dbg( p_aout, "will start to play in "I64Fd" us",
998 (p_sys->start_date - AOUT_PTS_TOLERANCE/4)-mdate());
1000 // than wait a short time... before grabbing first frames
1001 mwait( p_sys->start_date - AOUT_PTS_TOLERANCE/4 );
1003 #define waveout_warn(msg) msg_Warn( p_aout, "aout_OutputNextBuffer no buffer "\
1004 "got next_date=%d ms, "\
1005 "%d frames to play, "\
1006 "starving? %d, %s",(int)(next_date/(mtime_t)1000), \
1008 p_aout->output.b_starving, msg);
1009 next_date = mdate();
1011 while( !p_aout->b_die )
1013 /* Cleanup and find out the current latency */
1014 i_queued_frames = WaveOutClearDoneBuffers( p_sys );
1016 if( p_aout->b_die ) return;
1018 /* Try to fill in as many frame buffers as possible */
1019 for( i = 0; i < FRAMES_NUM; i++ )
1021 /* Check if frame buf is available */
1022 if( p_waveheader[i].dwFlags & WHDR_DONE )
1024 // next_date = mdate() + 1000000 * i_queued_frames /
1025 // p_aout->output.output.i_rate * p_aout->output.i_nb_samples;
1027 // the realtime has got our back-site:) to come in sync
1028 if(next_date < mdate())
1029 next_date = mdate();
1032 /* Take into account the latency */
1033 p_buffer = aout_OutputNextBuffer( p_aout,
1040 msg_Dbg( p_aout, "aout_OutputNextBuffer no buffer "\
1041 "got next_date=%d ms, "\
1042 "%d frames to play, "\
1043 "starving? %d",(int)(next_date/(mtime_t)1000),
1045 p_aout->output.b_starving);
1047 if(p_aout->output.b_starving)
1049 // means we are too early to request a new buffer?
1050 waveout_warn("waiting...")
1051 next_date = aout_FifoFirstDate( p_aout, &p_aout->output.fifo );
1052 mwait( next_date - AOUT_PTS_TOLERANCE/4 );
1053 next_date = mdate();
1054 p_buffer = aout_OutputNextBuffer( p_aout,
1061 if( !p_buffer && i_queued_frames )
1063 /* We aren't late so no need to play a blank sample */
1069 mtime_t buffer_length = (p_buffer->end_date
1070 - p_buffer->start_date);
1071 next_date = next_date + buffer_length;
1072 i_buffer_length = buffer_length/1000;
1075 /* Do the channel reordering */
1076 if( p_buffer && p_sys->b_chan_reorder )
1078 aout_ChannelReorder( p_buffer->p_buffer,
1079 p_buffer->i_nb_bytes,
1080 p_sys->waveformat.Format.nChannels,
1081 p_sys->pi_chan_table,
1082 p_sys->waveformat.Format.wBitsPerSample );
1085 PlayWaveOut( p_aout, p_sys->h_waveout,
1086 &p_waveheader[i], p_buffer, b_sleek );
1092 if( p_aout->b_die ) return;
1095 deal with the case that the loop didn't fillup the buffer to the
1096 max - instead of waiting that half the buffer is played before
1097 fillup the waveout buffers, wait only for the next sample buffer
1098 to arrive at the play method...
1100 this will also avoid, that the last buffer is play until the
1101 end, and then trying to get more data, so it will also
1102 work - if the next buffer will arrive some ms before the
1103 last buffer is finished.
1105 if(i_queued_frames < FRAMES_NUM)
1106 WaitForSingleObject( p_sys->new_buffer_event, INFINITE );
1108 WaitForSingleObject( p_sys->event, INFINITE );
1115 static int VolumeInfos( aout_instance_t * p_aout, audio_volume_t * pi_soft )
1117 *pi_soft = AOUT_VOLUME_MAX / 2;
1121 static int VolumeGet( aout_instance_t * p_aout, audio_volume_t * pi_volume )
1123 DWORD i_waveout_vol;
1126 waveOutGetVolume( 0, &i_waveout_vol );
1128 waveOutGetVolume( p_aout->output.p_sys->h_waveout, &i_waveout_vol );
1131 i_waveout_vol &= 0xFFFF;
1132 *pi_volume = p_aout->output.i_volume =
1133 (i_waveout_vol * AOUT_VOLUME_MAX + 0xFFFF /*rounding*/) / 2 / 0xFFFF;
1137 static int VolumeSet( aout_instance_t * p_aout, audio_volume_t i_volume )
1139 unsigned long i_waveout_vol = i_volume * 0xFFFF * 2 / AOUT_VOLUME_MAX;
1140 i_waveout_vol |= (i_waveout_vol << 16);
1143 waveOutSetVolume( 0, i_waveout_vol );
1145 waveOutSetVolume( p_aout->output.p_sys->h_waveout, i_waveout_vol );
1148 p_aout->output.i_volume = i_volume;
1154 reload the configuration drop down list, of the Audio Devices
1156 static int ReloadWaveoutDevices( vlc_object_t *p_this, char const *psz_name,
1157 vlc_value_t newval, vlc_value_t oldval, void *data )
1161 module_config_t *p_item = config_FindConfig( p_this, psz_name );
1162 if( !p_item ) return VLC_SUCCESS;
1164 /* Clear-up the current list */
1165 if( p_item->i_list )
1167 /* Keep the first entry */
1168 for( i = 1; i < p_item->i_list; i++ )
1170 free((char *)(p_item->ppsz_list[i]) );
1171 free((char *)(p_item->ppsz_list_text[i]) );
1173 /* TODO: Remove when no more needed */
1174 p_item->ppsz_list[i] = NULL;
1175 p_item->ppsz_list_text[i] = NULL;
1179 int wave_devices = waveOutGetNumDevs();
1182 (char **)realloc( p_item->ppsz_list,
1183 (wave_devices+2) * sizeof(char *) );
1184 p_item->ppsz_list_text =
1185 (char **)realloc( p_item->ppsz_list_text,
1186 (wave_devices+2) * sizeof(char *) );
1189 char sz_dev_name[MAXPNAMELEN+32];
1191 for(int i=0; i<wave_devices; i++)
1193 if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
1194 == MMSYSERR_NOERROR)
1196 sprintf(sz_dev_name,psz_device_name_fmt,caps.szPname,
1200 p_item->ppsz_list[j] = strdup( sz_dev_name );
1201 p_item->ppsz_list_text[j] = FromLocaleDup( sz_dev_name );
1207 p_item->ppsz_list[j] = NULL;
1208 p_item->ppsz_list_text[j] = NULL;
1210 /* Signal change to the interface */
1211 p_item->b_dirty = VLC_TRUE;
1217 convert devicename to device ID for output
1218 if device not found return WAVE_MAPPER, so let
1219 windows decide which prefered audio device
1222 static uint32_t findDeviceID(char *psz_device_name)
1224 if(!psz_device_name)
1227 uint32_t wave_devices = waveOutGetNumDevs();
1229 char sz_dev_name[MAXPNAMELEN+32];
1230 for(uint32_t i=0; i<wave_devices; i++)
1232 if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
1233 == MMSYSERR_NOERROR)
1235 sprintf(sz_dev_name,psz_device_name_fmt,caps.szPname,
1239 if(!stricmp(sz_dev_name,psz_device_name))