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-dev", "wavemapper", NULL,
174 DEVICE_TEXT, DEVICE_LONG, false );
175 change_string_list( ppsz_adev, ppsz_adev_text, ReloadWaveoutDevices );
176 change_need_restart();
177 change_action_add( ReloadWaveoutDevices, N_("Refresh list") );
180 set_callbacks( Open, Close );
183 /*****************************************************************************
184 * aout_sys_t: waveOut audio output method descriptor
185 *****************************************************************************
186 * This structure is part of the audio output thread descriptor.
187 * It describes the waveOut specific properties of an audio device.
188 *****************************************************************************/
191 uint32_t i_wave_device_id; /* ID of selected output device */
193 HWAVEOUT h_waveout; /* handle to waveout instance */
195 WAVEFORMATEXTENSIBLE waveformat; /* audio format */
197 WAVEHDR waveheader[FRAMES_NUM];
199 notification_thread_t *p_notif; /* WaveOutThread id */
201 HANDLE new_buffer_event;
203 // rental from alsa.c to synchronize startup of audiothread
204 int b_playing; /* playing status */
207 int i_repeat_counter;
211 uint8_t *p_silence_buffer; /* buffer we use to play silence */
213 bool b_chan_reorder; /* do we need channel reordering */
214 int pi_chan_table[AOUT_CHAN_MAX];
217 static const uint32_t pi_channels_src[] =
218 { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT,
219 AOUT_CHAN_MIDDLELEFT, AOUT_CHAN_MIDDLERIGHT,
220 AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT, AOUT_CHAN_REARCENTER,
221 AOUT_CHAN_CENTER, AOUT_CHAN_LFE, 0 };
222 static const uint32_t pi_channels_in[] =
223 { SPEAKER_FRONT_LEFT, SPEAKER_FRONT_RIGHT,
224 SPEAKER_SIDE_LEFT, SPEAKER_SIDE_RIGHT,
225 SPEAKER_BACK_LEFT, SPEAKER_BACK_RIGHT, SPEAKER_BACK_CENTER,
226 SPEAKER_FRONT_CENTER, SPEAKER_LOW_FREQUENCY, 0 };
227 static const uint32_t pi_channels_out[] =
228 { SPEAKER_FRONT_LEFT, SPEAKER_FRONT_RIGHT,
229 SPEAKER_FRONT_CENTER, SPEAKER_LOW_FREQUENCY,
230 SPEAKER_BACK_LEFT, SPEAKER_BACK_RIGHT,
232 SPEAKER_SIDE_LEFT, SPEAKER_SIDE_RIGHT, 0 };
234 /*****************************************************************************
235 * Open: open the audio device
236 *****************************************************************************
237 * This function opens and setups Win32 waveOut
238 *****************************************************************************/
239 static int Open( vlc_object_t *p_this )
241 aout_instance_t *p_aout = (aout_instance_t *)p_this;
245 /* Allocate structure */
246 p_aout->output.p_sys = malloc( sizeof( aout_sys_t ) );
248 if( p_aout->output.p_sys == NULL )
251 p_aout->output.pf_play = Play;
252 p_aout->b_die = false;
256 initialize/update Device selection List
258 ReloadWaveoutDevices( p_this, "waveout-dev", val, val, NULL);
262 check for configured audio device!
264 char *psz_waveout_dev = var_CreateGetString( p_aout, "waveout-dev");
266 p_aout->output.p_sys->i_wave_device_id =
267 findDeviceID( psz_waveout_dev );
269 if(p_aout->output.p_sys->i_wave_device_id == WAVE_MAPPER)
271 if(psz_waveout_dev &&
272 stricmp(psz_waveout_dev,"wavemapper"))
274 msg_Warn( p_aout, "configured audio device '%s' not available, "\
275 "use default instead", psz_waveout_dev );
278 free( psz_waveout_dev );
281 WAVEOUTCAPS waveoutcaps;
282 if(waveOutGetDevCaps( p_aout->output.p_sys->i_wave_device_id,
284 sizeof(WAVEOUTCAPS)) == MMSYSERR_NOERROR)
286 /* log debug some infos about driver, to know who to blame
287 if it doesn't work */
288 msg_Dbg( p_aout, "Drivername: %s", waveoutcaps.szPname);
289 msg_Dbg( p_aout, "Driver Version: %d.%d",
290 (waveoutcaps.vDriverVersion>>8)&255,
291 waveoutcaps.vDriverVersion & 255);
292 msg_Dbg( p_aout, "Manufacturer identifier: 0x%x", waveoutcaps.wMid );
293 msg_Dbg( p_aout, "Product identifier: 0x%x", waveoutcaps.wPid );
298 if( var_Type( p_aout, "audio-device" ) == 0 )
303 if( var_Get( p_aout, "audio-device", &val ) < 0 )
305 /* Probe() has failed. */
306 var_Destroy( p_aout, "waveout-device");
307 free( p_aout->output.p_sys );
312 /* Open the device */
313 if( val.i_int == AOUT_VAR_SPDIF )
315 p_aout->output.output.i_format = VLC_FOURCC('s','p','d','i');
317 if( OpenWaveOut( p_aout,
318 p_aout->output.p_sys->i_wave_device_id,
319 VLC_FOURCC('s','p','d','i'),
320 p_aout->output.output.i_physical_channels,
321 aout_FormatNbChannels( &p_aout->output.output ),
322 p_aout->output.output.i_rate, false )
325 msg_Err( p_aout, "cannot open waveout audio device" );
326 free( p_aout->output.p_sys );
330 /* Calculate the frame size in bytes */
331 p_aout->output.i_nb_samples = A52_FRAME_NB;
332 p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
333 p_aout->output.output.i_frame_length = A52_FRAME_NB;
334 p_aout->output.p_sys->i_buffer_size =
335 p_aout->output.output.i_bytes_per_frame;
337 aout_VolumeNoneInit( p_aout );
343 if( val.i_int == AOUT_VAR_5_1 )
345 p_aout->output.output.i_physical_channels
346 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
347 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
350 else if( val.i_int == AOUT_VAR_2F2R )
352 p_aout->output.output.i_physical_channels
353 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
354 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
356 else if( val.i_int == AOUT_VAR_MONO )
358 p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
362 p_aout->output.output.i_physical_channels
363 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
366 if( OpenWaveOutPCM( p_aout,
367 p_aout->output.p_sys->i_wave_device_id,
368 &p_aout->output.output.i_format,
369 p_aout->output.output.i_physical_channels,
370 aout_FormatNbChannels( &p_aout->output.output ),
371 p_aout->output.output.i_rate, false )
374 msg_Err( p_aout, "cannot open waveout audio device" );
375 free( p_aout->output.p_sys );
379 /* Calculate the frame size in bytes */
380 p_aout->output.i_nb_samples = FRAME_SIZE;
381 aout_FormatPrepare( &p_aout->output.output );
382 p_aout->output.p_sys->i_buffer_size = FRAME_SIZE *
383 p_aout->output.output.i_bytes_per_frame;
385 aout_VolumeSoftInit( p_aout );
387 /* Check for hardware volume support */
388 if( waveOutGetDevCaps( (UINT_PTR)p_aout->output.p_sys->h_waveout,
389 &wocaps, sizeof(wocaps) ) == MMSYSERR_NOERROR &&
390 wocaps.dwSupport & WAVECAPS_VOLUME )
393 if( waveOutGetVolume( p_aout->output.p_sys->h_waveout, &i_dummy )
394 == MMSYSERR_NOERROR )
396 p_aout->output.pf_volume_infos = VolumeInfos;
397 p_aout->output.pf_volume_get = VolumeGet;
398 p_aout->output.pf_volume_set = VolumeSet;
404 waveOutReset( p_aout->output.p_sys->h_waveout );
406 /* Allocate silence buffer */
407 p_aout->output.p_sys->p_silence_buffer =
408 malloc( p_aout->output.p_sys->i_buffer_size );
409 if( p_aout->output.p_sys->p_silence_buffer == NULL )
411 free( p_aout->output.p_sys );
414 p_aout->output.p_sys->i_repeat_counter = 0;
417 /* Zero the buffer. WinCE doesn't have calloc(). */
418 memset( p_aout->output.p_sys->p_silence_buffer, 0,
419 p_aout->output.p_sys->i_buffer_size );
421 /* Now we need to setup our waveOut play notification structure */
422 p_aout->output.p_sys->p_notif =
423 vlc_object_create( p_aout, sizeof(notification_thread_t) );
424 p_aout->output.p_sys->p_notif->p_aout = p_aout;
425 p_aout->output.p_sys->event = CreateEvent( NULL, FALSE, FALSE, NULL );
426 p_aout->output.p_sys->new_buffer_event = CreateEvent( NULL, FALSE, FALSE, NULL );
428 /* define startpoint of playback on first call to play()
429 like alsa does (instead of playing a blank sample) */
430 p_aout->output.p_sys->b_playing = 0;
431 p_aout->output.p_sys->start_date = 0;
434 /* Then launch the notification thread */
435 if( vlc_thread_create( p_aout->output.p_sys->p_notif,
436 "waveOut Notification Thread", WaveOutThread,
437 VLC_THREAD_PRIORITY_OUTPUT, false ) )
439 msg_Err( p_aout, "cannot create WaveOutThread" );
442 /* We need to kick off the playback in order to have the callback properly
444 for( i = 0; i < FRAMES_NUM; i++ )
446 p_aout->output.p_sys->waveheader[i].dwFlags = WHDR_DONE;
447 p_aout->output.p_sys->waveheader[i].dwUser = 0;
453 /*****************************************************************************
454 * Probe: probe the audio device for available formats and channels
455 *****************************************************************************/
456 static void Probe( aout_instance_t * p_aout )
458 vlc_value_t val, text;
460 unsigned int i_physical_channels;
462 var_Create( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
463 text.psz_string = _("Audio Device");
464 var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
466 /* Test for 5.1 support */
467 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
468 AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
469 AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE;
470 if( p_aout->output.output.i_physical_channels == i_physical_channels )
472 if( OpenWaveOutPCM( p_aout,
473 p_aout->output.p_sys->i_wave_device_id,
475 i_physical_channels, 6,
476 p_aout->output.output.i_rate, true )
479 val.i_int = AOUT_VAR_5_1;
480 text.psz_string = (char *)N_("5.1");
481 var_Change( p_aout, "audio-device",
482 VLC_VAR_ADDCHOICE, &val, &text );
483 msg_Dbg( p_aout, "device supports 5.1 channels" );
487 /* Test for 2 Front 2 Rear support */
488 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
489 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
490 if( ( p_aout->output.output.i_physical_channels & i_physical_channels )
491 == i_physical_channels )
493 if( OpenWaveOutPCM( p_aout,
494 p_aout->output.p_sys->i_wave_device_id,
496 i_physical_channels, 4,
497 p_aout->output.output.i_rate, true )
500 val.i_int = AOUT_VAR_2F2R;
501 text.psz_string = (char *)N_("2 Front 2 Rear");
502 var_Change( p_aout, "audio-device",
503 VLC_VAR_ADDCHOICE, &val, &text );
504 msg_Dbg( p_aout, "device supports 4 channels" );
508 /* Test for stereo support */
509 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
510 if( OpenWaveOutPCM( p_aout,
511 p_aout->output.p_sys->i_wave_device_id,
513 i_physical_channels, 2,
514 p_aout->output.output.i_rate, true )
517 val.i_int = AOUT_VAR_STEREO;
518 text.psz_string = (char *)N_("Stereo");
519 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
520 msg_Dbg( p_aout, "device supports 2 channels" );
523 /* Test for mono support */
524 i_physical_channels = AOUT_CHAN_CENTER;
525 if( OpenWaveOutPCM( p_aout,
526 p_aout->output.p_sys->i_wave_device_id,
528 i_physical_channels, 1,
529 p_aout->output.output.i_rate, true )
532 val.i_int = AOUT_VAR_MONO;
533 text.psz_string = (char *)N_("Mono");
534 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
535 msg_Dbg( p_aout, "device supports 1 channel" );
538 /* Test for SPDIF support */
539 if ( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
541 if( OpenWaveOut( p_aout,
542 p_aout->output.p_sys->i_wave_device_id,
543 VLC_FOURCC('s','p','d','i'),
544 p_aout->output.output.i_physical_channels,
545 aout_FormatNbChannels( &p_aout->output.output ),
546 p_aout->output.output.i_rate, true )
549 msg_Dbg( p_aout, "device supports A/52 over S/PDIF" );
550 val.i_int = AOUT_VAR_SPDIF;
551 text.psz_string = (char *)N_("A/52 over S/PDIF");
552 var_Change( p_aout, "audio-device",
553 VLC_VAR_ADDCHOICE, &val, &text );
554 if( config_GetInt( p_aout, "spdif" ) )
555 var_Set( p_aout, "audio-device", val );
559 var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
562 /* Probe() has failed. */
563 var_Destroy( p_aout, "audio-device" );
567 var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
570 var_Set( p_aout, "intf-change", val );
573 /*****************************************************************************
574 * Play: play a sound buffer
575 *****************************************************************************
576 * This doesn't actually play the buffer. This just stores the buffer so it
577 * can be played by the callback thread.
578 *****************************************************************************/
579 static void Play( aout_instance_t *_p_aout )
581 if( !_p_aout->output.p_sys->b_playing )
583 _p_aout->output.p_sys->b_playing = 1;
585 /* get the playing date of the first aout buffer */
586 _p_aout->output.p_sys->start_date =
587 aout_FifoFirstDate( _p_aout, &_p_aout->output.fifo );
589 msg_Dbg( _p_aout, "Wakeup sleeping output thread.");
591 /* wake up the audio output thread */
592 SetEvent( _p_aout->output.p_sys->event );
594 SetEvent( _p_aout->output.p_sys->new_buffer_event );
598 /*****************************************************************************
599 * Close: close the audio device
600 *****************************************************************************/
601 static void Close( vlc_object_t *p_this )
603 aout_instance_t *p_aout = (aout_instance_t *)p_this;
604 aout_sys_t *p_sys = p_aout->output.p_sys;
606 /* Before calling waveOutClose we must reset the device */
607 vlc_object_kill( p_aout );
609 /* wake up the audio thread, to recognize that p_aout died */
610 SetEvent( p_sys->event );
611 SetEvent( p_sys->new_buffer_event );
613 vlc_thread_join( p_sys->p_notif );
614 vlc_object_release( p_sys->p_notif );
617 kill the real output then - when the feed thread
618 is surely terminated!
619 old code could be too early in case that "feeding"
620 was running on termination
622 at this point now its sure, that there will be no new
623 data send to the driver, and we can cancel the last
626 MMRESULT result = waveOutReset( p_sys->h_waveout );
627 if(result != MMSYSERR_NOERROR)
629 msg_Err( p_aout, "waveOutReset failed 0x%x", result );
631 now we must wait, that all buffers are played
632 because cancel doesn't work in this case...
634 if(result == MMSYSERR_NOTSUPPORTED)
637 clear currently played (done) buffers,
638 if returnvalue > 0 (means some buffer still playing)
639 wait for the driver event callback that one buffer
640 is finished with playing, and check again
641 the timeout of 5000ms is just, an emergency exit
642 of this loop, to avoid deadlock in case of other
643 (currently not known bugs, problems, errors cases?)
646 (WaveOutClearDoneBuffers( p_sys ) > 0)
648 (WaitForSingleObject( p_sys->event, 5000) == WAIT_OBJECT_0)
651 msg_Dbg( p_aout, "Wait for waveout device...");
655 WaveOutClearDoneBuffers( p_sys );
658 /* now we can Close the device */
659 if( waveOutClose( p_sys->h_waveout ) != MMSYSERR_NOERROR )
661 msg_Err( p_aout, "waveOutClose failed" );
665 because so long, the waveout device is playing, the callback
666 could occur and need the events
668 CloseHandle( p_sys->event );
669 CloseHandle( p_sys->new_buffer_event);
671 free( p_sys->p_silence_buffer );
675 /*****************************************************************************
676 * OpenWaveOut: open the waveout sound device
677 ****************************************************************************/
678 static int OpenWaveOut( aout_instance_t *p_aout, uint32_t i_device_id, int i_format,
679 int i_channels, int i_nb_channels, int i_rate,
685 /* Set sound format */
687 #define waveformat p_aout->output.p_sys->waveformat
689 waveformat.dwChannelMask = 0;
690 for( i = 0; i < sizeof(pi_channels_src)/sizeof(uint32_t); i++ )
692 if( i_channels & pi_channels_src[i] )
693 waveformat.dwChannelMask |= pi_channels_in[i];
698 case VLC_FOURCC('s','p','d','i'):
700 /* To prevent channel re-ordering */
701 waveformat.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
702 waveformat.Format.wBitsPerSample = 16;
703 waveformat.Samples.wValidBitsPerSample =
704 waveformat.Format.wBitsPerSample;
705 waveformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
706 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF;
709 case VLC_FOURCC('f','l','3','2'):
710 waveformat.Format.wBitsPerSample = sizeof(float) * 8;
711 waveformat.Samples.wValidBitsPerSample =
712 waveformat.Format.wBitsPerSample;
713 waveformat.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
714 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
717 case VLC_FOURCC('s','1','6','l'):
718 waveformat.Format.wBitsPerSample = 16;
719 waveformat.Samples.wValidBitsPerSample =
720 waveformat.Format.wBitsPerSample;
721 waveformat.Format.wFormatTag = WAVE_FORMAT_PCM;
722 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_PCM;
726 waveformat.Format.nChannels = i_nb_channels;
727 waveformat.Format.nSamplesPerSec = i_rate;
728 waveformat.Format.nBlockAlign =
729 waveformat.Format.wBitsPerSample / 8 * i_nb_channels;
730 waveformat.Format.nAvgBytesPerSec =
731 waveformat.Format.nSamplesPerSec * waveformat.Format.nBlockAlign;
733 /* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */
734 if( i_nb_channels <= 2 )
736 waveformat.Format.cbSize = 0;
740 waveformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
741 waveformat.Format.cbSize =
742 sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
746 msg_Dbg( p_aout, "OpenWaveDevice-ID: %u", i_device_id);
747 msg_Dbg( p_aout,"waveformat.Format.cbSize = %d",
748 waveformat.Format.cbSize);
749 msg_Dbg( p_aout,"waveformat.Format.wFormatTag = %u",
750 waveformat.Format.wFormatTag);
751 msg_Dbg( p_aout,"waveformat.Format.nChannels = %u",
752 waveformat.Format.nChannels);
753 msg_Dbg( p_aout,"waveformat.Format.nSamplesPerSec = %d",
754 (int)waveformat.Format.nSamplesPerSec);
755 msg_Dbg( p_aout,"waveformat.Format.nAvgBytesPerSec = %u",
756 (int)waveformat.Format.nAvgBytesPerSec);
757 msg_Dbg( p_aout,"waveformat.Format.nBlockAlign = %d",
758 waveformat.Format.nBlockAlign);
759 msg_Dbg( p_aout,"waveformat.Format.wBitsPerSample = %d",
760 waveformat.Format.wBitsPerSample);
761 msg_Dbg( p_aout,"waveformat.Samples.wValidBitsPerSample = %d",
762 waveformat.Samples.wValidBitsPerSample);
763 msg_Dbg( p_aout,"waveformat.Samples.wSamplesPerBlock = %d",
764 waveformat.Samples.wSamplesPerBlock);
765 msg_Dbg( p_aout,"waveformat.dwChannelMask = %lu",
766 waveformat.dwChannelMask);
769 /* Open the device */
770 result = waveOutOpen( &p_aout->output.p_sys->h_waveout, i_device_id,
771 (WAVEFORMATEX *)&waveformat,
772 (DWORD_PTR)WaveOutCallback, (DWORD_PTR)p_aout,
773 CALLBACK_FUNCTION | (b_probe?WAVE_FORMAT_QUERY:0) );
774 if( result == WAVERR_BADFORMAT )
776 msg_Warn( p_aout, "waveOutOpen failed WAVERR_BADFORMAT" );
779 if( result == MMSYSERR_ALLOCATED )
781 msg_Warn( p_aout, "waveOutOpen failed WAVERR_ALLOCATED" );
784 if( result != MMSYSERR_NOERROR )
786 msg_Warn( p_aout, "waveOutOpen failed" );
790 p_aout->output.p_sys->b_chan_reorder =
791 aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
792 waveformat.dwChannelMask, i_nb_channels,
793 p_aout->output.p_sys->pi_chan_table );
795 if( p_aout->output.p_sys->b_chan_reorder )
797 msg_Dbg( p_aout, "channel reordering needed" );
806 /*****************************************************************************
807 * OpenWaveOutPCM: open a PCM waveout sound device
808 ****************************************************************************/
809 static int OpenWaveOutPCM( aout_instance_t *p_aout, uint32_t i_device_id, int *i_format,
810 int i_channels, int i_nb_channels, int i_rate,
813 bool b_use_float32 = var_CreateGetBool( p_aout, "waveout-float32");
815 if( !b_use_float32 || OpenWaveOut( p_aout, i_device_id, VLC_FOURCC('f','l','3','2'),
816 i_channels, i_nb_channels, i_rate, b_probe )
819 if ( OpenWaveOut( p_aout, i_device_id, VLC_FOURCC('s','1','6','l'),
820 i_channels, i_nb_channels, i_rate, b_probe )
827 *i_format = VLC_FOURCC('s','1','6','l');
833 *i_format = VLC_FOURCC('f','l','3','2');
838 /*****************************************************************************
839 * PlayWaveOut: play a buffer through the WaveOut device
840 *****************************************************************************/
841 static int PlayWaveOut( aout_instance_t *p_aout, HWAVEOUT h_waveout,
842 WAVEHDR *p_waveheader, aout_buffer_t *p_buffer,
847 /* Prepare the buffer */
848 if( p_buffer != NULL )
850 p_waveheader->lpData = p_buffer->p_buffer;
852 copy the buffer to the silence buffer :) so in case we don't
853 get the next buffer fast enough (I will repeat this one a time
854 for AC3 / DTS and SPDIF this will sound better instead of
859 vlc_memcpy( p_aout->output.p_sys->p_silence_buffer,
861 p_aout->output.p_sys->i_buffer_size );
862 p_aout->output.p_sys->i_repeat_counter = 2;
865 /* Use silence buffer instead */
866 if(p_aout->output.p_sys->i_repeat_counter)
868 p_aout->output.p_sys->i_repeat_counter--;
869 if(!p_aout->output.p_sys->i_repeat_counter)
871 vlc_memset( p_aout->output.p_sys->p_silence_buffer,
872 0x00, p_aout->output.p_sys->i_buffer_size );
875 p_waveheader->lpData = p_aout->output.p_sys->p_silence_buffer;
878 p_waveheader->dwUser = p_buffer ? (DWORD_PTR)p_buffer : (DWORD_PTR)1;
879 p_waveheader->dwBufferLength = p_aout->output.p_sys->i_buffer_size;
880 p_waveheader->dwFlags = 0;
882 result = waveOutPrepareHeader( h_waveout, p_waveheader, sizeof(WAVEHDR) );
883 if( result != MMSYSERR_NOERROR )
885 msg_Err( p_aout, "waveOutPrepareHeader failed" );
889 /* Send the buffer to the waveOut queue */
890 result = waveOutWrite( h_waveout, p_waveheader, sizeof(WAVEHDR) );
891 if( result != MMSYSERR_NOERROR )
893 msg_Err( p_aout, "waveOutWrite failed" );
900 /*****************************************************************************
901 * WaveOutCallback: what to do once WaveOut has played its sound samples
902 *****************************************************************************/
903 static void CALLBACK WaveOutCallback( HWAVEOUT h_waveout, UINT uMsg,
905 DWORD dwParam1, DWORD dwParam2 )
907 (void)h_waveout; (void)dwParam1; (void)dwParam2;
908 aout_instance_t *p_aout = (aout_instance_t *)_p_aout;
909 int i, i_queued_frames = 0;
911 if( uMsg != WOM_DONE ) return;
913 if( !vlc_object_alive (p_aout) ) return;
915 /* Find out the current latency */
916 for( i = 0; i < FRAMES_NUM; i++ )
918 /* Check if frame buf is available */
919 if( !(p_aout->output.p_sys->waveheader[i].dwFlags & WHDR_DONE) )
925 /* Don't wake up the thread too much */
926 if( i_queued_frames <= FRAMES_NUM/2 )
927 SetEvent( p_aout->output.p_sys->event );
931 /****************************************************************************
932 * WaveOutClearDoneBuffers: Clear all done marked buffers, and free aout_bufer
933 ****************************************************************************
934 * return value is the number of still playing buffers in the queue
935 ****************************************************************************/
936 static int WaveOutClearDoneBuffers(aout_sys_t *p_sys)
938 WAVEHDR *p_waveheader = p_sys->waveheader;
939 int i_queued_frames = 0;
941 for( int i = 0; i < FRAMES_NUM; i++ )
943 if( (p_waveheader[i].dwFlags & WHDR_DONE) &&
944 p_waveheader[i].dwUser )
946 aout_buffer_t *p_buffer =
947 (aout_buffer_t *)(p_waveheader[i].dwUser);
948 /* Unprepare and free the buffers which has just been played */
949 waveOutUnprepareHeader( p_sys->h_waveout, &p_waveheader[i],
952 if( p_waveheader[i].dwUser != 1 )
953 aout_BufferFree( p_buffer );
955 p_waveheader[i].dwUser = 0;
958 /* Check if frame buf is available */
959 if( !(p_waveheader[i].dwFlags & WHDR_DONE) )
964 return i_queued_frames;
967 /*****************************************************************************
968 * WaveOutThread: this thread will capture play notification events.
969 *****************************************************************************
970 * We use this thread to feed new audio samples to the sound card because
971 * we are not authorized to use waveOutWrite() directly in the waveout
973 *****************************************************************************/
974 static void* WaveOutThread( vlc_object_t *p_this )
976 notification_thread_t *p_notif = (notification_thread_t*)p_this;
977 aout_instance_t *p_aout = p_notif->p_aout;
978 aout_sys_t *p_sys = p_aout->output.p_sys;
979 aout_buffer_t *p_buffer = NULL;
980 WAVEHDR *p_waveheader = p_sys->waveheader;
981 int i, i_queued_frames;
984 uint32_t i_buffer_length = 64;
985 int canc = vlc_savecancel ();
987 /* We don't want any resampling when using S/PDIF */
988 b_sleek = p_aout->output.output.i_format == VLC_FOURCC('s','p','d','i');
990 // wait for first call to "play()"
991 while( !p_sys->start_date && vlc_object_alive (p_aout) )
992 WaitForSingleObject( p_sys->event, INFINITE );
993 if( !vlc_object_alive (p_aout) )
996 msg_Dbg( p_aout, "will start to play in %"PRId64" us",
997 (p_sys->start_date - AOUT_PTS_TOLERANCE/4)-mdate());
999 // than wait a short time... before grabbing first frames
1000 mwait( p_sys->start_date - AOUT_PTS_TOLERANCE/4 );
1002 #define waveout_warn(msg) msg_Warn( p_aout, "aout_OutputNextBuffer no buffer "\
1003 "got next_date=%d ms, "\
1004 "%d frames to play, "\
1005 "starving? %d, %s",(int)(next_date/(mtime_t)1000), \
1007 p_aout->output.b_starving, msg);
1008 next_date = mdate();
1010 while( vlc_object_alive (p_aout) )
1012 /* Cleanup and find out the current latency */
1013 i_queued_frames = WaveOutClearDoneBuffers( p_sys );
1015 if( !vlc_object_alive (p_aout) ) return NULL;
1017 /* Try to fill in as many frame buffers as possible */
1018 for( i = 0; i < FRAMES_NUM; i++ )
1020 /* Check if frame buf is available */
1021 if( p_waveheader[i].dwFlags & WHDR_DONE )
1023 // next_date = mdate() + 1000000 * i_queued_frames /
1024 // p_aout->output.output.i_rate * p_aout->output.i_nb_samples;
1026 // the realtime has got our back-site:) to come in sync
1027 if(next_date < mdate())
1028 next_date = mdate();
1031 /* Take into account the latency */
1032 p_buffer = aout_OutputNextBuffer( p_aout,
1039 msg_Dbg( p_aout, "aout_OutputNextBuffer no buffer "\
1040 "got next_date=%d ms, "\
1041 "%d frames to play, "\
1042 "starving? %d",(int)(next_date/(mtime_t)1000),
1044 p_aout->output.b_starving);
1046 if(p_aout->output.b_starving)
1048 // means we are too early to request a new buffer?
1049 waveout_warn("waiting...")
1050 next_date = aout_FifoFirstDate( p_aout, &p_aout->output.fifo );
1051 mwait( next_date - AOUT_PTS_TOLERANCE/4 );
1052 next_date = mdate();
1053 p_buffer = aout_OutputNextBuffer( p_aout,
1060 if( !p_buffer && i_queued_frames )
1062 /* We aren't late so no need to play a blank sample */
1068 mtime_t buffer_length = (p_buffer->end_date
1069 - p_buffer->start_date);
1070 next_date = next_date + buffer_length;
1071 i_buffer_length = buffer_length/1000;
1074 /* Do the channel reordering */
1075 if( p_buffer && p_sys->b_chan_reorder )
1077 aout_ChannelReorder( p_buffer->p_buffer,
1078 p_buffer->i_nb_bytes,
1079 p_sys->waveformat.Format.nChannels,
1080 p_sys->pi_chan_table,
1081 p_sys->waveformat.Format.wBitsPerSample );
1084 PlayWaveOut( p_aout, p_sys->h_waveout,
1085 &p_waveheader[i], p_buffer, b_sleek );
1091 if( !vlc_object_alive (p_aout) ) return NULL;
1094 deal with the case that the loop didn't fillup the buffer to the
1095 max - instead of waiting that half the buffer is played before
1096 fillup the waveout buffers, wait only for the next sample buffer
1097 to arrive at the play method...
1099 this will also avoid, that the last buffer is play until the
1100 end, and then trying to get more data, so it will also
1101 work - if the next buffer will arrive some ms before the
1102 last buffer is finished.
1104 if(i_queued_frames < FRAMES_NUM)
1105 WaitForSingleObject( p_sys->new_buffer_event, INFINITE );
1107 WaitForSingleObject( p_sys->event, INFINITE );
1112 vlc_restorecancel (canc);
1116 static int VolumeInfos( aout_instance_t * p_aout, audio_volume_t * pi_soft )
1118 *pi_soft = AOUT_VOLUME_MAX / 2;
1122 static int VolumeGet( aout_instance_t * p_aout, audio_volume_t * pi_volume )
1124 DWORD i_waveout_vol;
1127 waveOutGetVolume( 0, &i_waveout_vol );
1129 waveOutGetVolume( p_aout->output.p_sys->h_waveout, &i_waveout_vol );
1132 i_waveout_vol &= 0xFFFF;
1133 *pi_volume = p_aout->output.i_volume =
1134 (i_waveout_vol * AOUT_VOLUME_MAX + 0xFFFF /*rounding*/) / 2 / 0xFFFF;
1138 static int VolumeSet( aout_instance_t * p_aout, audio_volume_t i_volume )
1140 unsigned long i_waveout_vol = i_volume * 0xFFFF * 2 / AOUT_VOLUME_MAX;
1141 i_waveout_vol |= (i_waveout_vol << 16);
1144 waveOutSetVolume( 0, i_waveout_vol );
1146 waveOutSetVolume( p_aout->output.p_sys->h_waveout, i_waveout_vol );
1149 p_aout->output.i_volume = i_volume;
1155 reload the configuration drop down list, of the Audio Devices
1157 static int ReloadWaveoutDevices( vlc_object_t *p_this, char const *psz_name,
1158 vlc_value_t newval, vlc_value_t oldval, void *data )
1162 module_config_t *p_item = config_FindConfig( p_this, psz_name );
1163 if( !p_item ) return VLC_SUCCESS;
1165 /* Clear-up the current list */
1166 if( p_item->i_list )
1168 /* Keep the first entry */
1169 for( i = 1; i < p_item->i_list; i++ )
1171 free((char *)(p_item->ppsz_list[i]) );
1172 free((char *)(p_item->ppsz_list_text[i]) );
1174 /* TODO: Remove when no more needed */
1175 p_item->ppsz_list[i] = NULL;
1176 p_item->ppsz_list_text[i] = NULL;
1180 int wave_devices = waveOutGetNumDevs();
1183 (char **)realloc( p_item->ppsz_list,
1184 (wave_devices+2) * sizeof(char *) );
1185 p_item->ppsz_list_text =
1186 (char **)realloc( p_item->ppsz_list_text,
1187 (wave_devices+2) * sizeof(char *) );
1190 char sz_dev_name[MAXPNAMELEN+32];
1192 for(int i=0; i<wave_devices; i++)
1194 if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
1195 == MMSYSERR_NOERROR)
1197 sprintf( sz_dev_name, psz_device_name_fmt, caps.szPname,
1201 p_item->ppsz_list[j] = FromLocaleDup( sz_dev_name );
1202 p_item->ppsz_list_text[j] = FromLocaleDup( sz_dev_name );
1208 p_item->ppsz_list[j] = NULL;
1209 p_item->ppsz_list_text[j] = NULL;
1211 /* Signal change to the interface */
1212 p_item->b_dirty = true;
1218 convert devicename to device ID for output
1219 if device not found return WAVE_MAPPER, so let
1220 windows decide which preferred audio device
1223 static uint32_t findDeviceID(char *psz_device_name)
1225 if(!psz_device_name)
1228 uint32_t wave_devices = waveOutGetNumDevs();
1230 char sz_dev_name[MAXPNAMELEN+32];
1231 for(uint32_t i=0; i<wave_devices; i++)
1233 if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
1234 == MMSYSERR_NOERROR)
1236 sprintf(sz_dev_name, psz_device_name_fmt, caps.szPname,
1240 char *psz_temp = FromLocaleDup(sz_dev_name);
1242 if( !stricmp(psz_temp, psz_device_name) )
1244 LocaleFree( psz_temp );
1247 LocaleFree( psz_temp );