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 );
347 p_aout->output.output.i_physical_channels
348 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
349 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
353 p_aout->output.output.i_physical_channels
354 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
355 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
358 p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
361 p_aout->output.output.i_physical_channels
362 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
365 if( OpenWaveOutPCM( p_aout,
366 p_aout->output.p_sys->i_wave_device_id,
367 &p_aout->output.output.i_format,
368 p_aout->output.output.i_physical_channels,
369 aout_FormatNbChannels( &p_aout->output.output ),
370 p_aout->output.output.i_rate, false )
373 msg_Err( p_aout, "cannot open waveout audio device" );
374 free( p_aout->output.p_sys );
378 /* Calculate the frame size in bytes */
379 p_aout->output.i_nb_samples = FRAME_SIZE;
380 aout_FormatPrepare( &p_aout->output.output );
381 p_aout->output.p_sys->i_buffer_size = FRAME_SIZE *
382 p_aout->output.output.i_bytes_per_frame;
384 aout_VolumeSoftInit( p_aout );
386 /* Check for hardware volume support */
387 if( waveOutGetDevCaps( (UINT_PTR)p_aout->output.p_sys->h_waveout,
388 &wocaps, sizeof(wocaps) ) == MMSYSERR_NOERROR &&
389 wocaps.dwSupport & WAVECAPS_VOLUME )
392 if( waveOutGetVolume( p_aout->output.p_sys->h_waveout, &i_dummy )
393 == MMSYSERR_NOERROR )
395 p_aout->output.pf_volume_infos = VolumeInfos;
396 p_aout->output.pf_volume_get = VolumeGet;
397 p_aout->output.pf_volume_set = VolumeSet;
403 waveOutReset( p_aout->output.p_sys->h_waveout );
405 /* Allocate silence buffer */
406 p_aout->output.p_sys->p_silence_buffer =
407 malloc( p_aout->output.p_sys->i_buffer_size );
408 if( p_aout->output.p_sys->p_silence_buffer == NULL )
410 free( p_aout->output.p_sys );
413 p_aout->output.p_sys->i_repeat_counter = 0;
416 /* Zero the buffer. WinCE doesn't have calloc(). */
417 memset( p_aout->output.p_sys->p_silence_buffer, 0,
418 p_aout->output.p_sys->i_buffer_size );
420 /* Now we need to setup our waveOut play notification structure */
421 p_aout->output.p_sys->p_notif =
422 vlc_object_create( p_aout, sizeof(notification_thread_t) );
423 p_aout->output.p_sys->p_notif->p_aout = p_aout;
424 p_aout->output.p_sys->event = CreateEvent( NULL, FALSE, FALSE, NULL );
425 p_aout->output.p_sys->new_buffer_event = CreateEvent( NULL, FALSE, FALSE, NULL );
427 /* define startpoint of playback on first call to play()
428 like alsa does (instead of playing a blank sample) */
429 p_aout->output.p_sys->b_playing = 0;
430 p_aout->output.p_sys->start_date = 0;
433 /* Then launch the notification thread */
434 if( vlc_thread_create( p_aout->output.p_sys->p_notif,
435 "waveOut Notification Thread", WaveOutThread,
436 VLC_THREAD_PRIORITY_OUTPUT ) )
438 msg_Err( p_aout, "cannot create WaveOutThread" );
441 /* We need to kick off the playback in order to have the callback properly
443 for( i = 0; i < FRAMES_NUM; i++ )
445 p_aout->output.p_sys->waveheader[i].dwFlags = WHDR_DONE;
446 p_aout->output.p_sys->waveheader[i].dwUser = 0;
452 /*****************************************************************************
453 * Probe: probe the audio device for available formats and channels
454 *****************************************************************************/
455 static void Probe( aout_instance_t * p_aout )
457 vlc_value_t val, text;
459 unsigned int i_physical_channels;
461 var_Create( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
462 text.psz_string = _("Audio Device");
463 var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
465 /* Test for 5.1 support */
466 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
467 AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
468 AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE;
469 if( p_aout->output.output.i_physical_channels == i_physical_channels )
471 if( OpenWaveOutPCM( p_aout,
472 p_aout->output.p_sys->i_wave_device_id,
474 i_physical_channels, 6,
475 p_aout->output.output.i_rate, true )
478 val.i_int = AOUT_VAR_5_1;
479 text.psz_string = (char *)_("5.1");
480 var_Change( p_aout, "audio-device",
481 VLC_VAR_ADDCHOICE, &val, &text );
482 msg_Dbg( p_aout, "device supports 5.1 channels" );
486 /* Test for 2 Front 2 Rear support */
487 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
488 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
489 if( ( p_aout->output.output.i_physical_channels & i_physical_channels )
490 == i_physical_channels )
492 if( OpenWaveOutPCM( p_aout,
493 p_aout->output.p_sys->i_wave_device_id,
495 i_physical_channels, 4,
496 p_aout->output.output.i_rate, true )
499 val.i_int = AOUT_VAR_2F2R;
500 text.psz_string = (char *)_("2 Front 2 Rear");
501 var_Change( p_aout, "audio-device",
502 VLC_VAR_ADDCHOICE, &val, &text );
503 msg_Dbg( p_aout, "device supports 4 channels" );
507 /* Test for stereo support */
508 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
509 if( OpenWaveOutPCM( p_aout,
510 p_aout->output.p_sys->i_wave_device_id,
512 i_physical_channels, 2,
513 p_aout->output.output.i_rate, true )
516 val.i_int = AOUT_VAR_STEREO;
517 text.psz_string = (char *)_("Stereo");
518 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
519 msg_Dbg( p_aout, "device supports 2 channels" );
522 /* Test for mono support */
523 i_physical_channels = AOUT_CHAN_CENTER;
524 if( OpenWaveOutPCM( p_aout,
525 p_aout->output.p_sys->i_wave_device_id,
527 i_physical_channels, 1,
528 p_aout->output.output.i_rate, true )
531 val.i_int = AOUT_VAR_MONO;
532 text.psz_string = (char *)_("Mono");
533 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
534 msg_Dbg( p_aout, "device supports 1 channel" );
537 /* Test for SPDIF support */
538 if ( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
540 if( OpenWaveOut( p_aout,
541 p_aout->output.p_sys->i_wave_device_id,
542 VLC_FOURCC('s','p','d','i'),
543 p_aout->output.output.i_physical_channels,
544 aout_FormatNbChannels( &p_aout->output.output ),
545 p_aout->output.output.i_rate, true )
548 msg_Dbg( p_aout, "device supports A/52 over S/PDIF" );
549 val.i_int = AOUT_VAR_SPDIF;
550 text.psz_string = (char *)_("A/52 over S/PDIF");
551 var_Change( p_aout, "audio-device",
552 VLC_VAR_ADDCHOICE, &val, &text );
553 if( config_GetInt( p_aout, "spdif" ) )
554 var_Set( p_aout, "audio-device", val );
558 var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
561 /* Probe() has failed. */
562 var_Destroy( p_aout, "audio-device" );
566 var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
567 var_SetBool( p_aout, "intf-change", true );
570 /*****************************************************************************
571 * Play: play a sound buffer
572 *****************************************************************************
573 * This doesn't actually play the buffer. This just stores the buffer so it
574 * can be played by the callback thread.
575 *****************************************************************************/
576 static void Play( aout_instance_t *_p_aout )
578 if( !_p_aout->output.p_sys->b_playing )
580 _p_aout->output.p_sys->b_playing = 1;
582 /* get the playing date of the first aout buffer */
583 _p_aout->output.p_sys->start_date =
584 aout_FifoFirstDate( _p_aout, &_p_aout->output.fifo );
586 msg_Dbg( _p_aout, "Wakeup sleeping output thread.");
588 /* wake up the audio output thread */
589 SetEvent( _p_aout->output.p_sys->event );
591 SetEvent( _p_aout->output.p_sys->new_buffer_event );
595 /*****************************************************************************
596 * Close: close the audio device
597 *****************************************************************************/
598 static void Close( vlc_object_t *p_this )
600 aout_instance_t *p_aout = (aout_instance_t *)p_this;
601 aout_sys_t *p_sys = p_aout->output.p_sys;
603 /* Before calling waveOutClose we must reset the device */
604 vlc_object_kill( p_aout );
606 /* wake up the audio thread, to recognize that p_aout died */
607 SetEvent( p_sys->event );
608 SetEvent( p_sys->new_buffer_event );
610 vlc_thread_join( p_sys->p_notif );
611 vlc_object_release( p_sys->p_notif );
614 kill the real output then - when the feed thread
615 is surely terminated!
616 old code could be too early in case that "feeding"
617 was running on termination
619 at this point now its sure, that there will be no new
620 data send to the driver, and we can cancel the last
623 MMRESULT result = waveOutReset( p_sys->h_waveout );
624 if(result != MMSYSERR_NOERROR)
626 msg_Err( p_aout, "waveOutReset failed 0x%x", result );
628 now we must wait, that all buffers are played
629 because cancel doesn't work in this case...
631 if(result == MMSYSERR_NOTSUPPORTED)
634 clear currently played (done) buffers,
635 if returnvalue > 0 (means some buffer still playing)
636 wait for the driver event callback that one buffer
637 is finished with playing, and check again
638 the timeout of 5000ms is just, an emergency exit
639 of this loop, to avoid deadlock in case of other
640 (currently not known bugs, problems, errors cases?)
643 (WaveOutClearDoneBuffers( p_sys ) > 0)
645 (WaitForSingleObject( p_sys->event, 5000) == WAIT_OBJECT_0)
648 msg_Dbg( p_aout, "Wait for waveout device...");
652 WaveOutClearDoneBuffers( p_sys );
655 /* now we can Close the device */
656 if( waveOutClose( p_sys->h_waveout ) != MMSYSERR_NOERROR )
658 msg_Err( p_aout, "waveOutClose failed" );
662 because so long, the waveout device is playing, the callback
663 could occur and need the events
665 CloseHandle( p_sys->event );
666 CloseHandle( p_sys->new_buffer_event);
668 free( p_sys->p_silence_buffer );
672 /*****************************************************************************
673 * OpenWaveOut: open the waveout sound device
674 ****************************************************************************/
675 static int OpenWaveOut( aout_instance_t *p_aout, uint32_t i_device_id, int i_format,
676 int i_channels, int i_nb_channels, int i_rate,
682 /* Set sound format */
684 #define waveformat p_aout->output.p_sys->waveformat
686 waveformat.dwChannelMask = 0;
687 for( i = 0; i < sizeof(pi_channels_src)/sizeof(uint32_t); i++ )
689 if( i_channels & pi_channels_src[i] )
690 waveformat.dwChannelMask |= pi_channels_in[i];
695 case VLC_FOURCC('s','p','d','i'):
697 /* To prevent channel re-ordering */
698 waveformat.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
699 waveformat.Format.wBitsPerSample = 16;
700 waveformat.Samples.wValidBitsPerSample =
701 waveformat.Format.wBitsPerSample;
702 waveformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
703 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF;
706 case VLC_FOURCC('f','l','3','2'):
707 waveformat.Format.wBitsPerSample = sizeof(float) * 8;
708 waveformat.Samples.wValidBitsPerSample =
709 waveformat.Format.wBitsPerSample;
710 waveformat.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
711 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
714 case VLC_FOURCC('s','1','6','l'):
715 waveformat.Format.wBitsPerSample = 16;
716 waveformat.Samples.wValidBitsPerSample =
717 waveformat.Format.wBitsPerSample;
718 waveformat.Format.wFormatTag = WAVE_FORMAT_PCM;
719 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_PCM;
723 waveformat.Format.nChannels = i_nb_channels;
724 waveformat.Format.nSamplesPerSec = i_rate;
725 waveformat.Format.nBlockAlign =
726 waveformat.Format.wBitsPerSample / 8 * i_nb_channels;
727 waveformat.Format.nAvgBytesPerSec =
728 waveformat.Format.nSamplesPerSec * waveformat.Format.nBlockAlign;
730 /* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */
731 if( i_nb_channels <= 2 )
733 waveformat.Format.cbSize = 0;
737 waveformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
738 waveformat.Format.cbSize =
739 sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
743 msg_Dbg( p_aout, "OpenWaveDevice-ID: %u", i_device_id);
744 msg_Dbg( p_aout,"waveformat.Format.cbSize = %d",
745 waveformat.Format.cbSize);
746 msg_Dbg( p_aout,"waveformat.Format.wFormatTag = %u",
747 waveformat.Format.wFormatTag);
748 msg_Dbg( p_aout,"waveformat.Format.nChannels = %u",
749 waveformat.Format.nChannels);
750 msg_Dbg( p_aout,"waveformat.Format.nSamplesPerSec = %d",
751 (int)waveformat.Format.nSamplesPerSec);
752 msg_Dbg( p_aout,"waveformat.Format.nAvgBytesPerSec = %u",
753 (int)waveformat.Format.nAvgBytesPerSec);
754 msg_Dbg( p_aout,"waveformat.Format.nBlockAlign = %d",
755 waveformat.Format.nBlockAlign);
756 msg_Dbg( p_aout,"waveformat.Format.wBitsPerSample = %d",
757 waveformat.Format.wBitsPerSample);
758 msg_Dbg( p_aout,"waveformat.Samples.wValidBitsPerSample = %d",
759 waveformat.Samples.wValidBitsPerSample);
760 msg_Dbg( p_aout,"waveformat.Samples.wSamplesPerBlock = %d",
761 waveformat.Samples.wSamplesPerBlock);
762 msg_Dbg( p_aout,"waveformat.dwChannelMask = %lu",
763 waveformat.dwChannelMask);
766 /* Open the device */
767 result = waveOutOpen( &p_aout->output.p_sys->h_waveout, i_device_id,
768 (WAVEFORMATEX *)&waveformat,
769 (DWORD_PTR)WaveOutCallback, (DWORD_PTR)p_aout,
770 CALLBACK_FUNCTION | (b_probe?WAVE_FORMAT_QUERY:0) );
771 if( result == WAVERR_BADFORMAT )
773 msg_Warn( p_aout, "waveOutOpen failed WAVERR_BADFORMAT" );
776 if( result == MMSYSERR_ALLOCATED )
778 msg_Warn( p_aout, "waveOutOpen failed WAVERR_ALLOCATED" );
781 if( result != MMSYSERR_NOERROR )
783 msg_Warn( p_aout, "waveOutOpen failed" );
787 p_aout->output.p_sys->b_chan_reorder =
788 aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
789 waveformat.dwChannelMask, i_nb_channels,
790 p_aout->output.p_sys->pi_chan_table );
792 if( p_aout->output.p_sys->b_chan_reorder )
794 msg_Dbg( p_aout, "channel reordering needed" );
803 /*****************************************************************************
804 * OpenWaveOutPCM: open a PCM waveout sound device
805 ****************************************************************************/
806 static int OpenWaveOutPCM( aout_instance_t *p_aout, uint32_t i_device_id, int *i_format,
807 int i_channels, int i_nb_channels, int i_rate,
810 bool b_use_float32 = var_CreateGetBool( p_aout, "waveout-float32");
812 if( !b_use_float32 || OpenWaveOut( p_aout, i_device_id, VLC_FOURCC('f','l','3','2'),
813 i_channels, i_nb_channels, i_rate, b_probe )
816 if ( OpenWaveOut( p_aout, i_device_id, VLC_FOURCC('s','1','6','l'),
817 i_channels, i_nb_channels, i_rate, b_probe )
824 *i_format = VLC_FOURCC('s','1','6','l');
830 *i_format = VLC_FOURCC('f','l','3','2');
835 /*****************************************************************************
836 * PlayWaveOut: play a buffer through the WaveOut device
837 *****************************************************************************/
838 static int PlayWaveOut( aout_instance_t *p_aout, HWAVEOUT h_waveout,
839 WAVEHDR *p_waveheader, aout_buffer_t *p_buffer,
844 /* Prepare the buffer */
845 if( p_buffer != NULL )
847 p_waveheader->lpData = p_buffer->p_buffer;
849 copy the buffer to the silence buffer :) so in case we don't
850 get the next buffer fast enough (I will repeat this one a time
851 for AC3 / DTS and SPDIF this will sound better instead of
856 vlc_memcpy( p_aout->output.p_sys->p_silence_buffer,
858 p_aout->output.p_sys->i_buffer_size );
859 p_aout->output.p_sys->i_repeat_counter = 2;
862 /* Use silence buffer instead */
863 if(p_aout->output.p_sys->i_repeat_counter)
865 p_aout->output.p_sys->i_repeat_counter--;
866 if(!p_aout->output.p_sys->i_repeat_counter)
868 vlc_memset( p_aout->output.p_sys->p_silence_buffer,
869 0x00, p_aout->output.p_sys->i_buffer_size );
872 p_waveheader->lpData = p_aout->output.p_sys->p_silence_buffer;
875 p_waveheader->dwUser = p_buffer ? (DWORD_PTR)p_buffer : (DWORD_PTR)1;
876 p_waveheader->dwBufferLength = p_aout->output.p_sys->i_buffer_size;
877 p_waveheader->dwFlags = 0;
879 result = waveOutPrepareHeader( h_waveout, p_waveheader, sizeof(WAVEHDR) );
880 if( result != MMSYSERR_NOERROR )
882 msg_Err( p_aout, "waveOutPrepareHeader failed" );
886 /* Send the buffer to the waveOut queue */
887 result = waveOutWrite( h_waveout, p_waveheader, sizeof(WAVEHDR) );
888 if( result != MMSYSERR_NOERROR )
890 msg_Err( p_aout, "waveOutWrite failed" );
897 /*****************************************************************************
898 * WaveOutCallback: what to do once WaveOut has played its sound samples
899 *****************************************************************************/
900 static void CALLBACK WaveOutCallback( HWAVEOUT h_waveout, UINT uMsg,
902 DWORD dwParam1, DWORD dwParam2 )
904 (void)h_waveout; (void)dwParam1; (void)dwParam2;
905 aout_instance_t *p_aout = (aout_instance_t *)_p_aout;
906 int i, i_queued_frames = 0;
908 if( uMsg != WOM_DONE ) return;
910 if( !vlc_object_alive (p_aout) ) return;
912 /* Find out the current latency */
913 for( i = 0; i < FRAMES_NUM; i++ )
915 /* Check if frame buf is available */
916 if( !(p_aout->output.p_sys->waveheader[i].dwFlags & WHDR_DONE) )
922 /* Don't wake up the thread too much */
923 if( i_queued_frames <= FRAMES_NUM/2 )
924 SetEvent( p_aout->output.p_sys->event );
928 /****************************************************************************
929 * WaveOutClearDoneBuffers: Clear all done marked buffers, and free aout_bufer
930 ****************************************************************************
931 * return value is the number of still playing buffers in the queue
932 ****************************************************************************/
933 static int WaveOutClearDoneBuffers(aout_sys_t *p_sys)
935 WAVEHDR *p_waveheader = p_sys->waveheader;
936 int i_queued_frames = 0;
938 for( int i = 0; i < FRAMES_NUM; i++ )
940 if( (p_waveheader[i].dwFlags & WHDR_DONE) &&
941 p_waveheader[i].dwUser )
943 aout_buffer_t *p_buffer =
944 (aout_buffer_t *)(p_waveheader[i].dwUser);
945 /* Unprepare and free the buffers which has just been played */
946 waveOutUnprepareHeader( p_sys->h_waveout, &p_waveheader[i],
949 if( p_waveheader[i].dwUser != 1 )
950 aout_BufferFree( p_buffer );
952 p_waveheader[i].dwUser = 0;
955 /* Check if frame buf is available */
956 if( !(p_waveheader[i].dwFlags & WHDR_DONE) )
961 return i_queued_frames;
964 /*****************************************************************************
965 * WaveOutThread: this thread will capture play notification events.
966 *****************************************************************************
967 * We use this thread to feed new audio samples to the sound card because
968 * we are not authorized to use waveOutWrite() directly in the waveout
970 *****************************************************************************/
971 static void* WaveOutThread( vlc_object_t *p_this )
973 notification_thread_t *p_notif = (notification_thread_t*)p_this;
974 aout_instance_t *p_aout = p_notif->p_aout;
975 aout_sys_t *p_sys = p_aout->output.p_sys;
976 aout_buffer_t *p_buffer = NULL;
977 WAVEHDR *p_waveheader = p_sys->waveheader;
978 int i, i_queued_frames;
981 uint32_t i_buffer_length = 64;
982 int canc = vlc_savecancel ();
984 /* We don't want any resampling when using S/PDIF */
985 b_sleek = p_aout->output.output.i_format == VLC_FOURCC('s','p','d','i');
987 // wait for first call to "play()"
988 while( !p_sys->start_date && vlc_object_alive (p_aout) )
989 WaitForSingleObject( p_sys->event, INFINITE );
990 if( !vlc_object_alive (p_aout) )
993 msg_Dbg( p_aout, "will start to play in %"PRId64" us",
994 (p_sys->start_date - AOUT_PTS_TOLERANCE/4)-mdate());
996 // than wait a short time... before grabbing first frames
997 mwait( p_sys->start_date - AOUT_PTS_TOLERANCE/4 );
999 #define waveout_warn(msg) msg_Warn( p_aout, "aout_OutputNextBuffer no buffer "\
1000 "got next_date=%d ms, "\
1001 "%d frames to play, "\
1002 "starving? %d, %s",(int)(next_date/(mtime_t)1000), \
1004 p_aout->output.b_starving, msg);
1005 next_date = mdate();
1007 while( vlc_object_alive (p_aout) )
1009 /* Cleanup and find out the current latency */
1010 i_queued_frames = WaveOutClearDoneBuffers( p_sys );
1012 if( !vlc_object_alive (p_aout) ) return NULL;
1014 /* Try to fill in as many frame buffers as possible */
1015 for( i = 0; i < FRAMES_NUM; i++ )
1017 /* Check if frame buf is available */
1018 if( p_waveheader[i].dwFlags & WHDR_DONE )
1020 // next_date = mdate() + 1000000 * i_queued_frames /
1021 // p_aout->output.output.i_rate * p_aout->output.i_nb_samples;
1023 // the realtime has got our back-site:) to come in sync
1024 if(next_date < mdate())
1025 next_date = mdate();
1028 /* Take into account the latency */
1029 p_buffer = aout_OutputNextBuffer( p_aout,
1036 msg_Dbg( p_aout, "aout_OutputNextBuffer no buffer "\
1037 "got next_date=%d ms, "\
1038 "%d frames to play, "\
1039 "starving? %d",(int)(next_date/(mtime_t)1000),
1041 p_aout->output.b_starving);
1043 if(p_aout->output.b_starving)
1045 // means we are too early to request a new buffer?
1046 waveout_warn("waiting...")
1047 next_date = aout_FifoFirstDate( p_aout, &p_aout->output.fifo );
1048 mwait( next_date - AOUT_PTS_TOLERANCE/4 );
1049 next_date = mdate();
1050 p_buffer = aout_OutputNextBuffer( p_aout,
1057 if( !p_buffer && i_queued_frames )
1059 /* We aren't late so no need to play a blank sample */
1065 mtime_t buffer_length = (p_buffer->end_date
1066 - p_buffer->start_date);
1067 next_date = next_date + buffer_length;
1068 i_buffer_length = buffer_length/1000;
1071 /* Do the channel reordering */
1072 if( p_buffer && p_sys->b_chan_reorder )
1074 aout_ChannelReorder( p_buffer->p_buffer,
1075 p_buffer->i_nb_bytes,
1076 p_sys->waveformat.Format.nChannels,
1077 p_sys->pi_chan_table,
1078 p_sys->waveformat.Format.wBitsPerSample );
1081 PlayWaveOut( p_aout, p_sys->h_waveout,
1082 &p_waveheader[i], p_buffer, b_sleek );
1088 if( !vlc_object_alive (p_aout) ) return NULL;
1091 deal with the case that the loop didn't fillup the buffer to the
1092 max - instead of waiting that half the buffer is played before
1093 fillup the waveout buffers, wait only for the next sample buffer
1094 to arrive at the play method...
1096 this will also avoid, that the last buffer is play until the
1097 end, and then trying to get more data, so it will also
1098 work - if the next buffer will arrive some ms before the
1099 last buffer is finished.
1101 if(i_queued_frames < FRAMES_NUM)
1102 WaitForSingleObject( p_sys->new_buffer_event, INFINITE );
1104 WaitForSingleObject( p_sys->event, INFINITE );
1109 vlc_restorecancel (canc);
1113 static int VolumeInfos( aout_instance_t * p_aout, audio_volume_t * pi_soft )
1115 *pi_soft = AOUT_VOLUME_MAX / 2;
1119 static int VolumeGet( aout_instance_t * p_aout, audio_volume_t * pi_volume )
1121 DWORD i_waveout_vol;
1124 waveOutGetVolume( 0, &i_waveout_vol );
1126 waveOutGetVolume( p_aout->output.p_sys->h_waveout, &i_waveout_vol );
1129 i_waveout_vol &= 0xFFFF;
1130 *pi_volume = p_aout->output.i_volume =
1131 (i_waveout_vol * AOUT_VOLUME_MAX + 0xFFFF /*rounding*/) / 2 / 0xFFFF;
1135 static int VolumeSet( aout_instance_t * p_aout, audio_volume_t i_volume )
1137 unsigned long i_waveout_vol = i_volume * 0xFFFF * 2 / AOUT_VOLUME_MAX;
1138 i_waveout_vol |= (i_waveout_vol << 16);
1141 waveOutSetVolume( 0, i_waveout_vol );
1143 waveOutSetVolume( p_aout->output.p_sys->h_waveout, i_waveout_vol );
1146 p_aout->output.i_volume = i_volume;
1152 reload the configuration drop down list, of the Audio Devices
1154 static int ReloadWaveoutDevices( vlc_object_t *p_this, char const *psz_name,
1155 vlc_value_t newval, vlc_value_t oldval, void *data )
1159 module_config_t *p_item = config_FindConfig( p_this, psz_name );
1160 if( !p_item ) return VLC_SUCCESS;
1162 /* Clear-up the current list */
1163 if( p_item->i_list )
1165 /* Keep the first entry */
1166 for( i = 1; i < p_item->i_list; i++ )
1168 free((char *)(p_item->ppsz_list[i]) );
1169 free((char *)(p_item->ppsz_list_text[i]) );
1171 /* TODO: Remove when no more needed */
1172 p_item->ppsz_list[i] = NULL;
1173 p_item->ppsz_list_text[i] = NULL;
1177 int wave_devices = waveOutGetNumDevs();
1180 (char **)realloc( p_item->ppsz_list,
1181 (wave_devices+2) * sizeof(char *) );
1182 p_item->ppsz_list_text =
1183 (char **)realloc( p_item->ppsz_list_text,
1184 (wave_devices+2) * sizeof(char *) );
1187 char sz_dev_name[MAXPNAMELEN+32];
1189 for(int i=0; i<wave_devices; i++)
1191 if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
1192 == MMSYSERR_NOERROR)
1194 sprintf( sz_dev_name, psz_device_name_fmt, caps.szPname,
1198 p_item->ppsz_list[j] = FromLocaleDup( sz_dev_name );
1199 p_item->ppsz_list_text[j] = FromLocaleDup( sz_dev_name );
1205 p_item->ppsz_list[j] = NULL;
1206 p_item->ppsz_list_text[j] = NULL;
1208 /* Signal change to the interface */
1209 p_item->b_dirty = true;
1215 convert devicename to device ID for output
1216 if device not found return WAVE_MAPPER, so let
1217 windows decide which preferred audio device
1220 static uint32_t findDeviceID(char *psz_device_name)
1222 if(!psz_device_name)
1225 uint32_t wave_devices = waveOutGetNumDevs();
1227 char sz_dev_name[MAXPNAMELEN+32];
1228 for(uint32_t i=0; i<wave_devices; i++)
1230 if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
1231 == MMSYSERR_NOERROR)
1233 sprintf(sz_dev_name, psz_device_name_fmt, caps.szPname,
1237 char *psz_temp = FromLocaleDup(sz_dev_name);
1239 if( !stricmp(psz_temp, psz_device_name) )
1241 LocaleFree( psz_temp );
1244 LocaleFree( psz_temp );