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 *****************************************************************************/
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
35 #include <vlc_charset.h>
40 #define FRAME_SIZE 4096 /* The size is in samples, not in bytes */
43 /*****************************************************************************
45 *****************************************************************************/
47 # define DWORD_PTR DWORD
48 # ifdef waveOutGetDevCaps
49 # undef waveOutGetDevCaps
50 MMRESULT WINAPI waveOutGetDevCaps(UINT, LPWAVEOUTCAPS, UINT);
54 #ifndef WAVE_FORMAT_IEEE_FLOAT
55 # define WAVE_FORMAT_IEEE_FLOAT 0x0003
58 #ifndef WAVE_FORMAT_DOLBY_AC3_SPDIF
59 # define WAVE_FORMAT_DOLBY_AC3_SPDIF 0x0092
62 #ifndef WAVE_FORMAT_EXTENSIBLE
63 #define WAVE_FORMAT_EXTENSIBLE 0xFFFE
66 #ifndef SPEAKER_FRONT_LEFT
67 # define SPEAKER_FRONT_LEFT 0x1
68 # define SPEAKER_FRONT_RIGHT 0x2
69 # define SPEAKER_FRONT_CENTER 0x4
70 # define SPEAKER_LOW_FREQUENCY 0x8
71 # define SPEAKER_BACK_LEFT 0x10
72 # define SPEAKER_BACK_RIGHT 0x20
73 # define SPEAKER_FRONT_LEFT_OF_CENTER 0x40
74 # define SPEAKER_FRONT_RIGHT_OF_CENTER 0x80
75 # define SPEAKER_BACK_CENTER 0x100
76 # define SPEAKER_SIDE_LEFT 0x200
77 # define SPEAKER_SIDE_RIGHT 0x400
78 # define SPEAKER_TOP_CENTER 0x800
79 # define SPEAKER_TOP_FRONT_LEFT 0x1000
80 # define SPEAKER_TOP_FRONT_CENTER 0x2000
81 # define SPEAKER_TOP_FRONT_RIGHT 0x4000
82 # define SPEAKER_TOP_BACK_LEFT 0x8000
83 # define SPEAKER_TOP_BACK_CENTER 0x10000
84 # define SPEAKER_TOP_BACK_RIGHT 0x20000
85 # define SPEAKER_RESERVED 0x80000000
88 #ifndef _WAVEFORMATEXTENSIBLE_
92 WORD wValidBitsPerSample; /* bits of precision */
93 WORD wSamplesPerBlock; /* valid if wBitsPerSample==0 */
94 WORD wReserved; /* If neither applies, set to zero. */
96 DWORD dwChannelMask; /* which channels are */
97 /* present in stream */
99 } WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE;
102 static const GUID __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = {WAVE_FORMAT_IEEE_FLOAT, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
103 static const GUID __KSDATAFORMAT_SUBTYPE_PCM = {WAVE_FORMAT_PCM, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
104 static const GUID __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF = {WAVE_FORMAT_DOLBY_AC3_SPDIF, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
106 /*****************************************************************************
108 *****************************************************************************/
109 static int Open ( vlc_object_t * );
110 static void Close ( vlc_object_t * );
111 static void Play ( aout_instance_t * );
113 /*****************************************************************************
114 * notification_thread_t: waveOut event thread
115 *****************************************************************************/
116 typedef struct notification_thread_t
119 aout_instance_t *p_aout;
121 } notification_thread_t;
123 /* local functions */
124 static void Probe ( aout_instance_t * );
125 static int OpenWaveOut ( aout_instance_t *, uint32_t,
126 int, int, int, int, bool );
127 static int OpenWaveOutPCM( aout_instance_t *, uint32_t,
128 int*, int, int, int, bool );
129 static int PlayWaveOut ( aout_instance_t *, HWAVEOUT, WAVEHDR *,
130 aout_buffer_t *, bool );
132 static void CALLBACK WaveOutCallback ( HWAVEOUT, UINT, DWORD, DWORD, DWORD );
133 static void* WaveOutThread( vlc_object_t * );
135 static int VolumeInfos( aout_instance_t *, audio_volume_t * );
136 static int VolumeGet( aout_instance_t *, audio_volume_t * );
137 static int VolumeSet( aout_instance_t *, audio_volume_t );
139 static int WaveOutClearDoneBuffers(aout_sys_t *p_sys);
141 static int ReloadWaveoutDevices( vlc_object_t *, char const *,
142 vlc_value_t, vlc_value_t, void * );
143 static uint32_t findDeviceID(char *);
145 static const char psz_device_name_fmt[] = "%s ($%x,$%x)";
147 static const char *const ppsz_adev[] = { "wavemapper", };
148 static const char *const ppsz_adev_text[] = { N_("Microsoft Soundmapper") };
152 /*****************************************************************************
154 *****************************************************************************/
155 #define FLOAT_TEXT N_("Use float32 output")
156 #define FLOAT_LONGTEXT N_( \
157 "The option allows you to enable or disable the high-quality float32 " \
158 "audio output mode (which is not well supported by some soundcards)." )
159 #define DEVICE_TEXT N_("Select Audio Device")
160 #define DEVICE_LONG N_("Select special Audio device, or let windows "\
161 "decide (default), change needs VLC restart "\
163 #define DEFAULT_AUDIO_DEVICE N_("Default Audio Device")
166 set_shortname( "WaveOut" )
167 set_description( N_("Win32 waveOut extension output") )
168 set_capability( "audio output", 50 )
169 set_category( CAT_AUDIO )
170 set_subcategory( SUBCAT_AUDIO_AOUT )
171 add_bool( "waveout-float32", 1, 0, FLOAT_TEXT, FLOAT_LONGTEXT, true )
173 add_string( "waveout-audio-device", "wavemapper", NULL,
174 DEVICE_TEXT, DEVICE_LONG, false )
175 add_deprecated_alias( "waveout-dev" ) /* deprecated since 0.9.3 */
176 change_string_list( ppsz_adev, ppsz_adev_text, ReloadWaveoutDevices )
177 change_need_restart ()
178 change_action_add( ReloadWaveoutDevices, N_("Refresh list") )
181 set_callbacks( Open, Close )
184 /*****************************************************************************
185 * aout_sys_t: waveOut audio output method descriptor
186 *****************************************************************************
187 * This structure is part of the audio output thread descriptor.
188 * It describes the waveOut specific properties of an audio device.
189 *****************************************************************************/
192 uint32_t i_wave_device_id; /* ID of selected output device */
194 HWAVEOUT h_waveout; /* handle to waveout instance */
196 WAVEFORMATEXTENSIBLE waveformat; /* audio format */
198 WAVEHDR waveheader[FRAMES_NUM];
200 notification_thread_t *p_notif; /* WaveOutThread id */
202 HANDLE new_buffer_event;
204 // rental from alsa.c to synchronize startup of audiothread
205 int b_playing; /* playing status */
208 int i_repeat_counter;
212 uint8_t *p_silence_buffer; /* buffer we use to play silence */
214 bool b_chan_reorder; /* do we need channel reordering */
215 int pi_chan_table[AOUT_CHAN_MAX];
218 static const uint32_t pi_channels_src[] =
219 { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT,
220 AOUT_CHAN_MIDDLELEFT, AOUT_CHAN_MIDDLERIGHT,
221 AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT, AOUT_CHAN_REARCENTER,
222 AOUT_CHAN_CENTER, AOUT_CHAN_LFE, 0 };
223 static const uint32_t pi_channels_in[] =
224 { SPEAKER_FRONT_LEFT, SPEAKER_FRONT_RIGHT,
225 SPEAKER_SIDE_LEFT, SPEAKER_SIDE_RIGHT,
226 SPEAKER_BACK_LEFT, SPEAKER_BACK_RIGHT, SPEAKER_BACK_CENTER,
227 SPEAKER_FRONT_CENTER, SPEAKER_LOW_FREQUENCY, 0 };
228 static const uint32_t pi_channels_out[] =
229 { SPEAKER_FRONT_LEFT, SPEAKER_FRONT_RIGHT,
230 SPEAKER_FRONT_CENTER, SPEAKER_LOW_FREQUENCY,
231 SPEAKER_BACK_LEFT, SPEAKER_BACK_RIGHT,
233 SPEAKER_SIDE_LEFT, SPEAKER_SIDE_RIGHT, 0 };
235 /*****************************************************************************
236 * Open: open the audio device
237 *****************************************************************************
238 * This function opens and setups Win32 waveOut
239 *****************************************************************************/
240 static int Open( vlc_object_t *p_this )
242 aout_instance_t *p_aout = (aout_instance_t *)p_this;
246 /* Allocate structure */
247 p_aout->output.p_sys = malloc( sizeof( aout_sys_t ) );
249 if( p_aout->output.p_sys == NULL )
252 p_aout->output.pf_play = Play;
253 p_aout->b_die = false;
257 initialize/update Device selection List
259 ReloadWaveoutDevices( p_this, "waveout-audio-device", val, val, NULL);
263 check for configured audio device!
265 char *psz_waveout_dev = var_CreateGetString( p_aout, "waveout-audio-device");
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 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-audio-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, 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, 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 );
415 p_aout->output.p_sys->i_repeat_counter = 0;
418 /* Zero the buffer. WinCE doesn't have calloc(). */
419 memset( p_aout->output.p_sys->p_silence_buffer, 0,
420 p_aout->output.p_sys->i_buffer_size );
422 /* Now we need to setup our waveOut play notification structure */
423 p_aout->output.p_sys->p_notif =
424 vlc_object_create( p_aout, sizeof(notification_thread_t) );
425 p_aout->output.p_sys->p_notif->p_aout = p_aout;
426 p_aout->output.p_sys->event = CreateEvent( NULL, FALSE, FALSE, NULL );
427 p_aout->output.p_sys->new_buffer_event = CreateEvent( NULL, FALSE, FALSE, NULL );
429 /* define startpoint of playback on first call to play()
430 like alsa does (instead of playing a blank sample) */
431 p_aout->output.p_sys->b_playing = 0;
432 p_aout->output.p_sys->start_date = 0;
435 /* Then launch the notification thread */
436 if( vlc_thread_create( p_aout->output.p_sys->p_notif,
437 "waveOut Notification Thread", WaveOutThread,
438 VLC_THREAD_PRIORITY_OUTPUT ) )
440 msg_Err( p_aout, "cannot create WaveOutThread" );
443 /* We need to kick off the playback in order to have the callback properly
445 for( i = 0; i < FRAMES_NUM; i++ )
447 p_aout->output.p_sys->waveheader[i].dwFlags = WHDR_DONE;
448 p_aout->output.p_sys->waveheader[i].dwUser = 0;
454 /*****************************************************************************
455 * Probe: probe the audio device for available formats and channels
456 *****************************************************************************/
457 static void Probe( aout_instance_t * p_aout )
459 vlc_value_t val, text;
461 unsigned int i_physical_channels;
463 var_Create( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
464 text.psz_string = _("Audio Device");
465 var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
467 /* Test for 5.1 support */
468 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
469 AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
470 AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE;
471 if( p_aout->output.output.i_physical_channels == i_physical_channels )
473 if( OpenWaveOutPCM( p_aout,
474 p_aout->output.p_sys->i_wave_device_id,
476 i_physical_channels, 6,
477 p_aout->output.output.i_rate, true )
480 val.i_int = AOUT_VAR_5_1;
481 text.psz_string = (char *)_("5.1");
482 var_Change( p_aout, "audio-device",
483 VLC_VAR_ADDCHOICE, &val, &text );
484 msg_Dbg( p_aout, "device supports 5.1 channels" );
488 /* Test for 2 Front 2 Rear support */
489 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
490 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
491 if( ( p_aout->output.output.i_physical_channels & i_physical_channels )
492 == i_physical_channels )
494 if( OpenWaveOutPCM( p_aout,
495 p_aout->output.p_sys->i_wave_device_id,
497 i_physical_channels, 4,
498 p_aout->output.output.i_rate, true )
501 val.i_int = AOUT_VAR_2F2R;
502 text.psz_string = (char *)_("2 Front 2 Rear");
503 var_Change( p_aout, "audio-device",
504 VLC_VAR_ADDCHOICE, &val, &text );
505 msg_Dbg( p_aout, "device supports 4 channels" );
509 /* Test for stereo support */
510 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
511 if( OpenWaveOutPCM( p_aout,
512 p_aout->output.p_sys->i_wave_device_id,
514 i_physical_channels, 2,
515 p_aout->output.output.i_rate, true )
518 val.i_int = AOUT_VAR_STEREO;
519 text.psz_string = (char *)_("Stereo");
520 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
521 msg_Dbg( p_aout, "device supports 2 channels" );
524 /* Test for mono support */
525 i_physical_channels = AOUT_CHAN_CENTER;
526 if( OpenWaveOutPCM( p_aout,
527 p_aout->output.p_sys->i_wave_device_id,
529 i_physical_channels, 1,
530 p_aout->output.output.i_rate, true )
533 val.i_int = AOUT_VAR_MONO;
534 text.psz_string = (char *)_("Mono");
535 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
536 msg_Dbg( p_aout, "device supports 1 channel" );
539 /* Test for SPDIF support */
540 if ( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
542 if( OpenWaveOut( p_aout,
543 p_aout->output.p_sys->i_wave_device_id,
544 VLC_FOURCC('s','p','d','i'),
545 p_aout->output.output.i_physical_channels,
546 aout_FormatNbChannels( &p_aout->output.output ),
547 p_aout->output.output.i_rate, true )
550 msg_Dbg( p_aout, "device supports A/52 over S/PDIF" );
551 val.i_int = AOUT_VAR_SPDIF;
552 text.psz_string = (char *)_("A/52 over S/PDIF");
553 var_Change( p_aout, "audio-device",
554 VLC_VAR_ADDCHOICE, &val, &text );
555 if( config_GetInt( p_aout, "spdif" ) )
556 var_Set( p_aout, "audio-device", val );
560 var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
563 /* Probe() has failed. */
564 var_Destroy( p_aout, "audio-device" );
568 var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
571 var_Set( p_aout, "intf-change", val );
574 /*****************************************************************************
575 * Play: play a sound buffer
576 *****************************************************************************
577 * This doesn't actually play the buffer. This just stores the buffer so it
578 * can be played by the callback thread.
579 *****************************************************************************/
580 static void Play( aout_instance_t *_p_aout )
582 if( !_p_aout->output.p_sys->b_playing )
584 _p_aout->output.p_sys->b_playing = 1;
586 /* get the playing date of the first aout buffer */
587 _p_aout->output.p_sys->start_date =
588 aout_FifoFirstDate( _p_aout, &_p_aout->output.fifo );
590 msg_Dbg( _p_aout, "Wakeup sleeping output thread.");
592 /* wake up the audio output thread */
593 SetEvent( _p_aout->output.p_sys->event );
595 SetEvent( _p_aout->output.p_sys->new_buffer_event );
599 /*****************************************************************************
600 * Close: close the audio device
601 *****************************************************************************/
602 static void Close( vlc_object_t *p_this )
604 aout_instance_t *p_aout = (aout_instance_t *)p_this;
605 aout_sys_t *p_sys = p_aout->output.p_sys;
607 /* Before calling waveOutClose we must reset the device */
608 vlc_object_kill( p_aout );
610 /* wake up the audio thread, to recognize that p_aout died */
611 SetEvent( p_sys->event );
612 SetEvent( p_sys->new_buffer_event );
614 vlc_thread_join( p_sys->p_notif );
615 vlc_object_release( p_sys->p_notif );
618 kill the real output then - when the feed thread
619 is surely terminated!
620 old code could be too early in case that "feeding"
621 was running on termination
623 at this point now its sure, that there will be no new
624 data send to the driver, and we can cancel the last
627 MMRESULT result = waveOutReset( p_sys->h_waveout );
628 if(result != MMSYSERR_NOERROR)
630 msg_Err( p_aout, "waveOutReset failed 0x%x", result );
632 now we must wait, that all buffers are played
633 because cancel doesn't work in this case...
635 if(result == MMSYSERR_NOTSUPPORTED)
638 clear currently played (done) buffers,
639 if returnvalue > 0 (means some buffer still playing)
640 wait for the driver event callback that one buffer
641 is finished with playing, and check again
642 the timeout of 5000ms is just, an emergency exit
643 of this loop, to avoid deadlock in case of other
644 (currently not known bugs, problems, errors cases?)
647 (WaveOutClearDoneBuffers( p_sys ) > 0)
649 (WaitForSingleObject( p_sys->event, 5000) == WAIT_OBJECT_0)
652 msg_Dbg( p_aout, "Wait for waveout device...");
656 WaveOutClearDoneBuffers( p_sys );
659 /* now we can Close the device */
660 if( waveOutClose( p_sys->h_waveout ) != MMSYSERR_NOERROR )
662 msg_Err( p_aout, "waveOutClose failed" );
666 because so long, the waveout device is playing, the callback
667 could occur and need the events
669 CloseHandle( p_sys->event );
670 CloseHandle( p_sys->new_buffer_event);
672 free( p_sys->p_silence_buffer );
676 /*****************************************************************************
677 * OpenWaveOut: open the waveout sound device
678 ****************************************************************************/
679 static int OpenWaveOut( aout_instance_t *p_aout, uint32_t i_device_id, int i_format,
680 int i_channels, int i_nb_channels, int i_rate,
686 /* Set sound format */
688 #define waveformat p_aout->output.p_sys->waveformat
690 waveformat.dwChannelMask = 0;
691 for( i = 0; i < sizeof(pi_channels_src)/sizeof(uint32_t); i++ )
693 if( i_channels & pi_channels_src[i] )
694 waveformat.dwChannelMask |= pi_channels_in[i];
699 case VLC_FOURCC('s','p','d','i'):
701 /* To prevent channel re-ordering */
702 waveformat.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
703 waveformat.Format.wBitsPerSample = 16;
704 waveformat.Samples.wValidBitsPerSample =
705 waveformat.Format.wBitsPerSample;
706 waveformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
707 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF;
710 case VLC_FOURCC('f','l','3','2'):
711 waveformat.Format.wBitsPerSample = sizeof(float) * 8;
712 waveformat.Samples.wValidBitsPerSample =
713 waveformat.Format.wBitsPerSample;
714 waveformat.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
715 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
718 case VLC_FOURCC('s','1','6','l'):
719 waveformat.Format.wBitsPerSample = 16;
720 waveformat.Samples.wValidBitsPerSample =
721 waveformat.Format.wBitsPerSample;
722 waveformat.Format.wFormatTag = WAVE_FORMAT_PCM;
723 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_PCM;
727 waveformat.Format.nChannels = i_nb_channels;
728 waveformat.Format.nSamplesPerSec = i_rate;
729 waveformat.Format.nBlockAlign =
730 waveformat.Format.wBitsPerSample / 8 * i_nb_channels;
731 waveformat.Format.nAvgBytesPerSec =
732 waveformat.Format.nSamplesPerSec * waveformat.Format.nBlockAlign;
734 /* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */
735 if( i_nb_channels <= 2 )
737 waveformat.Format.cbSize = 0;
741 waveformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
742 waveformat.Format.cbSize =
743 sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
747 msg_Dbg( p_aout, "OpenWaveDevice-ID: %u", i_device_id);
748 msg_Dbg( p_aout,"waveformat.Format.cbSize = %d",
749 waveformat.Format.cbSize);
750 msg_Dbg( p_aout,"waveformat.Format.wFormatTag = %u",
751 waveformat.Format.wFormatTag);
752 msg_Dbg( p_aout,"waveformat.Format.nChannels = %u",
753 waveformat.Format.nChannels);
754 msg_Dbg( p_aout,"waveformat.Format.nSamplesPerSec = %d",
755 (int)waveformat.Format.nSamplesPerSec);
756 msg_Dbg( p_aout,"waveformat.Format.nAvgBytesPerSec = %u",
757 (int)waveformat.Format.nAvgBytesPerSec);
758 msg_Dbg( p_aout,"waveformat.Format.nBlockAlign = %d",
759 waveformat.Format.nBlockAlign);
760 msg_Dbg( p_aout,"waveformat.Format.wBitsPerSample = %d",
761 waveformat.Format.wBitsPerSample);
762 msg_Dbg( p_aout,"waveformat.Samples.wValidBitsPerSample = %d",
763 waveformat.Samples.wValidBitsPerSample);
764 msg_Dbg( p_aout,"waveformat.Samples.wSamplesPerBlock = %d",
765 waveformat.Samples.wSamplesPerBlock);
766 msg_Dbg( p_aout,"waveformat.dwChannelMask = %lu",
767 waveformat.dwChannelMask);
770 /* Open the device */
771 result = waveOutOpen( &p_aout->output.p_sys->h_waveout, i_device_id,
772 (WAVEFORMATEX *)&waveformat,
773 (DWORD_PTR)WaveOutCallback, (DWORD_PTR)p_aout,
774 CALLBACK_FUNCTION | (b_probe?WAVE_FORMAT_QUERY:0) );
775 if( result == WAVERR_BADFORMAT )
777 msg_Warn( p_aout, "waveOutOpen failed WAVERR_BADFORMAT" );
780 if( result == MMSYSERR_ALLOCATED )
782 msg_Warn( p_aout, "waveOutOpen failed WAVERR_ALLOCATED" );
785 if( result != MMSYSERR_NOERROR )
787 msg_Warn( p_aout, "waveOutOpen failed" );
791 p_aout->output.p_sys->b_chan_reorder =
792 aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
793 waveformat.dwChannelMask, i_nb_channels,
794 p_aout->output.p_sys->pi_chan_table );
796 if( p_aout->output.p_sys->b_chan_reorder )
798 msg_Dbg( p_aout, "channel reordering needed" );
807 /*****************************************************************************
808 * OpenWaveOutPCM: open a PCM waveout sound device
809 ****************************************************************************/
810 static int OpenWaveOutPCM( aout_instance_t *p_aout, uint32_t i_device_id, int *i_format,
811 int i_channels, int i_nb_channels, int i_rate,
814 bool b_use_float32 = var_CreateGetBool( p_aout, "waveout-float32");
816 if( !b_use_float32 || OpenWaveOut( p_aout, i_device_id, VLC_FOURCC('f','l','3','2'),
817 i_channels, i_nb_channels, i_rate, b_probe )
820 if ( OpenWaveOut( p_aout, i_device_id, VLC_FOURCC('s','1','6','l'),
821 i_channels, i_nb_channels, i_rate, b_probe )
828 *i_format = VLC_FOURCC('s','1','6','l');
834 *i_format = VLC_FOURCC('f','l','3','2');
839 /*****************************************************************************
840 * PlayWaveOut: play a buffer through the WaveOut device
841 *****************************************************************************/
842 static int PlayWaveOut( aout_instance_t *p_aout, HWAVEOUT h_waveout,
843 WAVEHDR *p_waveheader, aout_buffer_t *p_buffer,
848 /* Prepare the buffer */
849 if( p_buffer != NULL )
851 p_waveheader->lpData = p_buffer->p_buffer;
853 copy the buffer to the silence buffer :) so in case we don't
854 get the next buffer fast enough (I will repeat this one a time
855 for AC3 / DTS and SPDIF this will sound better instead of
860 vlc_memcpy( p_aout->output.p_sys->p_silence_buffer,
862 p_aout->output.p_sys->i_buffer_size );
863 p_aout->output.p_sys->i_repeat_counter = 2;
866 /* Use silence buffer instead */
867 if(p_aout->output.p_sys->i_repeat_counter)
869 p_aout->output.p_sys->i_repeat_counter--;
870 if(!p_aout->output.p_sys->i_repeat_counter)
872 vlc_memset( p_aout->output.p_sys->p_silence_buffer,
873 0x00, p_aout->output.p_sys->i_buffer_size );
876 p_waveheader->lpData = p_aout->output.p_sys->p_silence_buffer;
879 p_waveheader->dwUser = p_buffer ? (DWORD_PTR)p_buffer : (DWORD_PTR)1;
880 p_waveheader->dwBufferLength = p_aout->output.p_sys->i_buffer_size;
881 p_waveheader->dwFlags = 0;
883 result = waveOutPrepareHeader( h_waveout, p_waveheader, sizeof(WAVEHDR) );
884 if( result != MMSYSERR_NOERROR )
886 msg_Err( p_aout, "waveOutPrepareHeader failed" );
890 /* Send the buffer to the waveOut queue */
891 result = waveOutWrite( h_waveout, p_waveheader, sizeof(WAVEHDR) );
892 if( result != MMSYSERR_NOERROR )
894 msg_Err( p_aout, "waveOutWrite failed" );
901 /*****************************************************************************
902 * WaveOutCallback: what to do once WaveOut has played its sound samples
903 *****************************************************************************/
904 static void CALLBACK WaveOutCallback( HWAVEOUT h_waveout, UINT uMsg,
906 DWORD dwParam1, DWORD dwParam2 )
908 (void)h_waveout; (void)dwParam1; (void)dwParam2;
909 aout_instance_t *p_aout = (aout_instance_t *)_p_aout;
910 int i, i_queued_frames = 0;
912 if( uMsg != WOM_DONE ) return;
914 if( !vlc_object_alive (p_aout) ) return;
916 /* Find out the current latency */
917 for( i = 0; i < FRAMES_NUM; i++ )
919 /* Check if frame buf is available */
920 if( !(p_aout->output.p_sys->waveheader[i].dwFlags & WHDR_DONE) )
926 /* Don't wake up the thread too much */
927 if( i_queued_frames <= FRAMES_NUM/2 )
928 SetEvent( p_aout->output.p_sys->event );
932 /****************************************************************************
933 * WaveOutClearDoneBuffers: Clear all done marked buffers, and free aout_bufer
934 ****************************************************************************
935 * return value is the number of still playing buffers in the queue
936 ****************************************************************************/
937 static int WaveOutClearDoneBuffers(aout_sys_t *p_sys)
939 WAVEHDR *p_waveheader = p_sys->waveheader;
940 int i_queued_frames = 0;
942 for( int i = 0; i < FRAMES_NUM; i++ )
944 if( (p_waveheader[i].dwFlags & WHDR_DONE) &&
945 p_waveheader[i].dwUser )
947 aout_buffer_t *p_buffer =
948 (aout_buffer_t *)(p_waveheader[i].dwUser);
949 /* Unprepare and free the buffers which has just been played */
950 waveOutUnprepareHeader( p_sys->h_waveout, &p_waveheader[i],
953 if( p_waveheader[i].dwUser != 1 )
954 aout_BufferFree( p_buffer );
956 p_waveheader[i].dwUser = 0;
959 /* Check if frame buf is available */
960 if( !(p_waveheader[i].dwFlags & WHDR_DONE) )
965 return i_queued_frames;
968 /*****************************************************************************
969 * WaveOutThread: this thread will capture play notification events.
970 *****************************************************************************
971 * We use this thread to feed new audio samples to the sound card because
972 * we are not authorized to use waveOutWrite() directly in the waveout
974 *****************************************************************************/
975 static void* WaveOutThread( vlc_object_t *p_this )
977 notification_thread_t *p_notif = (notification_thread_t*)p_this;
978 aout_instance_t *p_aout = p_notif->p_aout;
979 aout_sys_t *p_sys = p_aout->output.p_sys;
980 aout_buffer_t *p_buffer = NULL;
981 WAVEHDR *p_waveheader = p_sys->waveheader;
982 int i, i_queued_frames;
985 uint32_t i_buffer_length = 64;
986 int canc = vlc_savecancel ();
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 && vlc_object_alive (p_aout) )
993 WaitForSingleObject( p_sys->event, INFINITE );
994 if( !vlc_object_alive (p_aout) )
997 msg_Dbg( p_aout, "will start to play in %"PRId64" 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( vlc_object_alive (p_aout) )
1013 /* Cleanup and find out the current latency */
1014 i_queued_frames = WaveOutClearDoneBuffers( p_sys );
1016 if( !vlc_object_alive (p_aout) ) return NULL;
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( !vlc_object_alive (p_aout) ) return NULL;
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 );
1113 vlc_restorecancel (canc);
1117 static int VolumeInfos( aout_instance_t * p_aout, audio_volume_t * pi_soft )
1119 *pi_soft = AOUT_VOLUME_MAX / 2;
1123 static int VolumeGet( aout_instance_t * p_aout, audio_volume_t * pi_volume )
1125 DWORD i_waveout_vol;
1128 waveOutGetVolume( 0, &i_waveout_vol );
1130 waveOutGetVolume( p_aout->output.p_sys->h_waveout, &i_waveout_vol );
1133 i_waveout_vol &= 0xFFFF;
1134 *pi_volume = p_aout->output.i_volume =
1135 (i_waveout_vol * AOUT_VOLUME_MAX + 0xFFFF /*rounding*/) / 2 / 0xFFFF;
1139 static int VolumeSet( aout_instance_t * p_aout, audio_volume_t i_volume )
1141 unsigned long i_waveout_vol = i_volume * 0xFFFF * 2 / AOUT_VOLUME_MAX;
1142 i_waveout_vol |= (i_waveout_vol << 16);
1145 waveOutSetVolume( 0, i_waveout_vol );
1147 waveOutSetVolume( p_aout->output.p_sys->h_waveout, i_waveout_vol );
1150 p_aout->output.i_volume = i_volume;
1156 reload the configuration drop down list, of the Audio Devices
1158 static int ReloadWaveoutDevices( vlc_object_t *p_this, char const *psz_name,
1159 vlc_value_t newval, vlc_value_t oldval, void *data )
1163 module_config_t *p_item = config_FindConfig( p_this, psz_name );
1164 if( !p_item ) return VLC_SUCCESS;
1166 /* Clear-up the current list */
1167 if( p_item->i_list )
1169 /* Keep the first entry */
1170 for( i = 1; i < p_item->i_list; i++ )
1172 free((char *)(p_item->ppsz_list[i]) );
1173 free((char *)(p_item->ppsz_list_text[i]) );
1175 /* TODO: Remove when no more needed */
1176 p_item->ppsz_list[i] = NULL;
1177 p_item->ppsz_list_text[i] = NULL;
1181 int wave_devices = waveOutGetNumDevs();
1184 (char **)realloc( p_item->ppsz_list,
1185 (wave_devices+2) * sizeof(char *) );
1186 p_item->ppsz_list_text =
1187 (char **)realloc( p_item->ppsz_list_text,
1188 (wave_devices+2) * sizeof(char *) );
1191 char sz_dev_name[MAXPNAMELEN+32];
1193 for(int i=0; i<wave_devices; i++)
1195 if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
1196 == MMSYSERR_NOERROR)
1198 sprintf( sz_dev_name, psz_device_name_fmt, caps.szPname,
1202 p_item->ppsz_list[j] = FromLocaleDup( sz_dev_name );
1203 p_item->ppsz_list_text[j] = FromLocaleDup( sz_dev_name );
1209 p_item->ppsz_list[j] = NULL;
1210 p_item->ppsz_list_text[j] = NULL;
1212 /* Signal change to the interface */
1213 p_item->b_dirty = true;
1219 convert devicename to device ID for output
1220 if device not found return WAVE_MAPPER, so let
1221 windows decide which preferred audio device
1224 static uint32_t findDeviceID(char *psz_device_name)
1226 if(!psz_device_name)
1229 uint32_t wave_devices = waveOutGetNumDevs();
1231 char sz_dev_name[MAXPNAMELEN+32];
1232 for(uint32_t i=0; i<wave_devices; i++)
1234 if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
1235 == MMSYSERR_NOERROR)
1237 sprintf(sz_dev_name, psz_device_name_fmt, caps.szPname,
1241 char *psz_temp = FromLocaleDup(sz_dev_name);
1243 if( !stricmp(psz_temp, psz_device_name) )
1245 LocaleFree( psz_temp );
1248 LocaleFree( psz_temp );