1 /*****************************************************************************
2 * waveout.c : Windows waveOut plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2001-2009 the VideoLAN team
7 * Authors: Gildas Bazin <gbazin@videolan.org>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
36 #include <vlc_charset.h> /* FromLocaleDup, LocaleFree */
37 #include <vlc_atomic.h>
39 #include "windows_audio_common.h"
41 #define FRAME_SIZE 4096 /* The size is in samples, not in bytes */
43 /*****************************************************************************
45 *****************************************************************************/
46 static int Open ( vlc_object_t * );
47 static void Close ( vlc_object_t * );
48 static void Play ( aout_instance_t * );
50 /*****************************************************************************
51 * notification_thread_t: waveOut event thread
52 *****************************************************************************/
54 static void Probe ( aout_instance_t * );
55 static int OpenWaveOut ( aout_instance_t *, uint32_t,
56 int, int, int, int, bool );
57 static int OpenWaveOutPCM( aout_instance_t *, uint32_t,
58 vlc_fourcc_t*, int, int, int, bool );
59 static int PlayWaveOut ( aout_instance_t *, HWAVEOUT, WAVEHDR *,
60 aout_buffer_t *, bool );
62 static void CALLBACK WaveOutCallback ( HWAVEOUT, UINT, DWORD, DWORD, DWORD );
63 static void* WaveOutThread( void * );
65 static int VolumeSet( aout_instance_t *, audio_volume_t, bool );
67 static int WaveOutClearDoneBuffers(aout_sys_t *p_sys);
69 static int ReloadWaveoutDevices( vlc_object_t *, char const *,
70 vlc_value_t, vlc_value_t, void * );
71 static uint32_t findDeviceID(char *);
73 static const char psz_device_name_fmt[] = "%s ($%x,$%x)";
75 static const char *const ppsz_adev[] = { "wavemapper", };
76 static const char *const ppsz_adev_text[] = { N_("Microsoft Soundmapper") };
79 /*****************************************************************************
81 *****************************************************************************/
82 #define DEVICE_TEXT N_("Select Audio Device")
83 #define DEVICE_LONG N_("Select special Audio device, or let windows "\
84 "decide (default), change needs VLC restart "\
86 #define DEFAULT_AUDIO_DEVICE N_("Default Audio Device")
89 set_shortname( "WaveOut" )
90 set_description( N_("Win32 waveOut extension output") )
91 set_capability( "audio output", 50 )
92 set_category( CAT_AUDIO )
93 set_subcategory( SUBCAT_AUDIO_AOUT )
94 add_bool( "waveout-float32", true, FLOAT_TEXT, FLOAT_LONGTEXT, true )
96 add_string( "waveout-audio-device", "wavemapper",
97 DEVICE_TEXT, DEVICE_LONG, false )
98 add_deprecated_alias( "waveout-dev" ) /* deprecated since 0.9.3 */
99 change_string_list( ppsz_adev, ppsz_adev_text, ReloadWaveoutDevices )
100 change_action_add( ReloadWaveoutDevices, N_("Refresh list") )
102 set_callbacks( Open, Close )
105 /*****************************************************************************
106 * aout_sys_t: waveOut audio output method descriptor
107 *****************************************************************************
108 * This structure is part of the audio output thread descriptor.
109 * It describes the waveOut specific properties of an audio device.
110 *****************************************************************************/
113 uint32_t i_wave_device_id; /* ID of selected output device */
115 HWAVEOUT h_waveout; /* handle to waveout instance */
117 WAVEFORMATEXTENSIBLE waveformat; /* audio format */
119 WAVEHDR waveheader[FRAMES_NUM];
124 HANDLE new_buffer_event;
126 // rental from alsa.c to synchronize startup of audiothread
127 int b_playing; /* playing status */
130 int i_repeat_counter;
134 uint8_t *p_silence_buffer; /* buffer we use to play silence */
136 bool b_chan_reorder; /* do we need channel reordering */
137 int pi_chan_table[AOUT_CHAN_MAX];
140 /*****************************************************************************
141 * Open: open the audio device
142 *****************************************************************************
143 * This function opens and setups Win32 waveOut
144 *****************************************************************************/
145 static int Open( vlc_object_t *p_this )
147 aout_instance_t *p_aout = (aout_instance_t *)p_this;
150 /* Allocate structure */
151 p_aout->output.p_sys = malloc( sizeof( aout_sys_t ) );
153 if( p_aout->output.p_sys == NULL )
156 p_aout->output.pf_play = Play;
157 p_aout->b_die = false;
161 initialize/update Device selection List
163 ReloadWaveoutDevices( p_this, "waveout-audio-device", val, val, NULL);
167 check for configured audio device!
169 char *psz_waveout_dev = var_CreateGetString( p_aout, "waveout-audio-device");
171 p_aout->output.p_sys->i_wave_device_id =
172 findDeviceID( psz_waveout_dev );
174 if(p_aout->output.p_sys->i_wave_device_id == WAVE_MAPPER)
176 if(psz_waveout_dev &&
177 stricmp(psz_waveout_dev,"wavemapper"))
179 msg_Warn( p_aout, "configured audio device '%s' not available, "\
180 "use default instead", psz_waveout_dev );
183 free( psz_waveout_dev );
186 WAVEOUTCAPS waveoutcaps;
187 if(waveOutGetDevCaps( p_aout->output.p_sys->i_wave_device_id,
189 sizeof(WAVEOUTCAPS)) == MMSYSERR_NOERROR)
191 /* log debug some infos about driver, to know who to blame
192 if it doesn't work */
193 msg_Dbg( p_aout, "Drivername: %s", waveoutcaps.szPname);
194 msg_Dbg( p_aout, "Driver Version: %d.%d",
195 (waveoutcaps.vDriverVersion>>8)&255,
196 waveoutcaps.vDriverVersion & 255);
197 msg_Dbg( p_aout, "Manufacturer identifier: 0x%x", waveoutcaps.wMid );
198 msg_Dbg( p_aout, "Product identifier: 0x%x", waveoutcaps.wPid );
203 if( var_Type( p_aout, "audio-device" ) == 0 )
208 if( var_Get( p_aout, "audio-device", &val ) < 0 )
210 /* Probe() has failed. */
211 var_Destroy( p_aout, "waveout-audio-device");
212 free( p_aout->output.p_sys );
217 /* Open the device */
218 if( val.i_int == AOUT_VAR_SPDIF )
220 p_aout->output.output.i_format = VLC_CODEC_SPDIFL;
222 if( OpenWaveOut( p_aout,
223 p_aout->output.p_sys->i_wave_device_id,
225 p_aout->output.output.i_physical_channels,
226 aout_FormatNbChannels( &p_aout->output.output ),
227 p_aout->output.output.i_rate, false )
230 msg_Err( p_aout, "cannot open waveout audio device" );
231 free( p_aout->output.p_sys );
235 /* Calculate the frame size in bytes */
236 p_aout->output.i_nb_samples = A52_FRAME_NB;
237 p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
238 p_aout->output.output.i_frame_length = A52_FRAME_NB;
239 p_aout->output.p_sys->i_buffer_size =
240 p_aout->output.output.i_bytes_per_frame;
242 aout_VolumeNoneInit( p_aout );
251 p_aout->output.output.i_physical_channels
252 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
253 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
257 p_aout->output.output.i_physical_channels
258 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
259 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
262 p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
265 p_aout->output.output.i_physical_channels
266 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
269 if( OpenWaveOutPCM( p_aout,
270 p_aout->output.p_sys->i_wave_device_id,
271 &p_aout->output.output.i_format,
272 p_aout->output.output.i_physical_channels,
273 aout_FormatNbChannels( &p_aout->output.output ),
274 p_aout->output.output.i_rate, false )
277 msg_Err( p_aout, "cannot open waveout audio device" );
278 free( p_aout->output.p_sys );
282 /* Calculate the frame size in bytes */
283 p_aout->output.i_nb_samples = FRAME_SIZE;
284 aout_FormatPrepare( &p_aout->output.output );
285 p_aout->output.p_sys->i_buffer_size = FRAME_SIZE *
286 p_aout->output.output.i_bytes_per_frame;
288 aout_VolumeSoftInit( p_aout );
290 /* Check for hardware volume support */
291 if( waveOutGetDevCaps( (UINT_PTR)p_aout->output.p_sys->h_waveout,
292 &wocaps, sizeof(wocaps) ) == MMSYSERR_NOERROR &&
293 wocaps.dwSupport & WAVECAPS_VOLUME )
296 if( waveOutGetVolume( p_aout->output.p_sys->h_waveout, &i_dummy )
297 == MMSYSERR_NOERROR )
299 p_aout->output.pf_volume_set = VolumeSet;
305 waveOutReset( p_aout->output.p_sys->h_waveout );
307 /* Allocate silence buffer */
308 p_aout->output.p_sys->p_silence_buffer =
309 malloc( p_aout->output.p_sys->i_buffer_size );
310 if( p_aout->output.p_sys->p_silence_buffer == NULL )
312 free( p_aout->output.p_sys );
315 p_aout->output.p_sys->i_repeat_counter = 0;
318 /* Zero the buffer. WinCE doesn't have calloc(). */
319 memset( p_aout->output.p_sys->p_silence_buffer, 0,
320 p_aout->output.p_sys->i_buffer_size );
322 /* Now we need to setup our waveOut play notification structure */
323 p_aout->output.p_sys->event = CreateEvent( NULL, FALSE, FALSE, NULL );
324 p_aout->output.p_sys->new_buffer_event = CreateEvent( NULL, FALSE, FALSE, NULL );
326 /* define startpoint of playback on first call to play()
327 like alsa does (instead of playing a blank sample) */
328 p_aout->output.p_sys->b_playing = 0;
329 p_aout->output.p_sys->start_date = 0;
332 /* Then launch the notification thread */
333 vlc_atomic_set( &p_aout->output.p_sys->abort, 0);
334 if( vlc_clone( &p_aout->output.p_sys->thread,
335 WaveOutThread, p_aout, VLC_THREAD_PRIORITY_OUTPUT ) )
337 msg_Err( p_aout, "cannot create WaveOutThread" );
340 /* We need to kick off the playback in order to have the callback properly
342 for( int i = 0; i < FRAMES_NUM; i++ )
344 p_aout->output.p_sys->waveheader[i].dwFlags = WHDR_DONE;
345 p_aout->output.p_sys->waveheader[i].dwUser = 0;
351 /*****************************************************************************
352 * Probe: probe the audio device for available formats and channels
353 *****************************************************************************/
354 static void Probe( aout_instance_t * p_aout )
356 vlc_value_t val, text;
357 vlc_fourcc_t i_format;
358 unsigned int i_physical_channels;
360 var_Create( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
361 text.psz_string = _("Audio Device");
362 var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
364 /* Test for 5.1 support */
365 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
366 AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
367 AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE;
368 if( p_aout->output.output.i_physical_channels == i_physical_channels )
370 if( OpenWaveOutPCM( p_aout,
371 p_aout->output.p_sys->i_wave_device_id,
373 i_physical_channels, 6,
374 p_aout->output.output.i_rate, true )
377 val.i_int = AOUT_VAR_5_1;
378 text.psz_string = (char *)_("5.1");
379 var_Change( p_aout, "audio-device",
380 VLC_VAR_ADDCHOICE, &val, &text );
381 msg_Dbg( p_aout, "device supports 5.1 channels" );
385 /* Test for 2 Front 2 Rear support */
386 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
387 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
388 if( ( p_aout->output.output.i_physical_channels & i_physical_channels )
389 == i_physical_channels )
391 if( OpenWaveOutPCM( p_aout,
392 p_aout->output.p_sys->i_wave_device_id,
394 i_physical_channels, 4,
395 p_aout->output.output.i_rate, true )
398 val.i_int = AOUT_VAR_2F2R;
399 text.psz_string = (char *)_("2 Front 2 Rear");
400 var_Change( p_aout, "audio-device",
401 VLC_VAR_ADDCHOICE, &val, &text );
402 msg_Dbg( p_aout, "device supports 4 channels" );
406 /* Test for stereo support */
407 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
408 if( OpenWaveOutPCM( p_aout,
409 p_aout->output.p_sys->i_wave_device_id,
411 i_physical_channels, 2,
412 p_aout->output.output.i_rate, true )
415 val.i_int = AOUT_VAR_STEREO;
416 text.psz_string = (char *)_("Stereo");
417 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
418 msg_Dbg( p_aout, "device supports 2 channels" );
421 /* Test for mono support */
422 i_physical_channels = AOUT_CHAN_CENTER;
423 if( OpenWaveOutPCM( p_aout,
424 p_aout->output.p_sys->i_wave_device_id,
426 i_physical_channels, 1,
427 p_aout->output.output.i_rate, true )
430 val.i_int = AOUT_VAR_MONO;
431 text.psz_string = (char *)_("Mono");
432 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
433 msg_Dbg( p_aout, "device supports 1 channel" );
436 /* Test for SPDIF support */
437 if ( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
439 if( OpenWaveOut( p_aout,
440 p_aout->output.p_sys->i_wave_device_id,
442 p_aout->output.output.i_physical_channels,
443 aout_FormatNbChannels( &p_aout->output.output ),
444 p_aout->output.output.i_rate, true )
447 msg_Dbg( p_aout, "device supports A/52 over S/PDIF" );
448 val.i_int = AOUT_VAR_SPDIF;
449 text.psz_string = (char *)_("A/52 over S/PDIF");
450 var_Change( p_aout, "audio-device",
451 VLC_VAR_ADDCHOICE, &val, &text );
452 if( var_InheritBool( p_aout, "spdif" ) )
453 var_Set( p_aout, "audio-device", val );
457 var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
460 /* Probe() has failed. */
461 var_Destroy( p_aout, "audio-device" );
465 var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
466 var_TriggerCallback( p_aout, "intf-change" );
469 /*****************************************************************************
470 * Play: play a sound buffer
471 *****************************************************************************
472 * This doesn't actually play the buffer. This just stores the buffer so it
473 * can be played by the callback thread.
474 *****************************************************************************/
475 static void Play( aout_instance_t *_p_aout )
477 if( !_p_aout->output.p_sys->b_playing )
479 _p_aout->output.p_sys->b_playing = 1;
481 /* get the playing date of the first aout buffer */
482 _p_aout->output.p_sys->start_date =
483 aout_FifoFirstDate( &_p_aout->output.fifo );
485 msg_Dbg( _p_aout, "Wakeup sleeping output thread.");
487 /* wake up the audio output thread */
488 SetEvent( _p_aout->output.p_sys->event );
490 SetEvent( _p_aout->output.p_sys->new_buffer_event );
494 /*****************************************************************************
495 * Close: close the audio device
496 *****************************************************************************/
497 static void Close( vlc_object_t *p_this )
499 aout_instance_t *p_aout = (aout_instance_t *)p_this;
500 aout_sys_t *p_sys = p_aout->output.p_sys;
502 /* Before calling waveOutClose we must reset the device */
503 vlc_atomic_set( &p_sys->abort, 1);
505 /* wake up the audio thread, to recognize that p_aout died */
506 SetEvent( p_sys->event );
507 SetEvent( p_sys->new_buffer_event );
509 vlc_join( p_sys->thread, NULL );
512 kill the real output then - when the feed thread
513 is surely terminated!
514 old code could be too early in case that "feeding"
515 was running on termination
517 at this point now its sure, that there will be no new
518 data send to the driver, and we can cancel the last
521 MMRESULT result = waveOutReset( p_sys->h_waveout );
522 if(result != MMSYSERR_NOERROR)
524 msg_Err( p_aout, "waveOutReset failed 0x%x", result );
526 now we must wait, that all buffers are played
527 because cancel doesn't work in this case...
529 if(result == MMSYSERR_NOTSUPPORTED)
532 clear currently played (done) buffers,
533 if returnvalue > 0 (means some buffer still playing)
534 wait for the driver event callback that one buffer
535 is finished with playing, and check again
536 the timeout of 5000ms is just, an emergency exit
537 of this loop, to avoid deadlock in case of other
538 (currently not known bugs, problems, errors cases?)
541 (WaveOutClearDoneBuffers( p_sys ) > 0)
543 (WaitForSingleObject( p_sys->event, 5000) == WAIT_OBJECT_0)
546 msg_Dbg( p_aout, "Wait for waveout device...");
550 WaveOutClearDoneBuffers( p_sys );
553 /* now we can Close the device */
554 if( waveOutClose( p_sys->h_waveout ) != MMSYSERR_NOERROR )
556 msg_Err( p_aout, "waveOutClose failed" );
560 because so long, the waveout device is playing, the callback
561 could occur and need the events
563 CloseHandle( p_sys->event );
564 CloseHandle( p_sys->new_buffer_event);
566 free( p_sys->p_silence_buffer );
570 /*****************************************************************************
571 * OpenWaveOut: open the waveout sound device
572 ****************************************************************************/
573 static int OpenWaveOut( aout_instance_t *p_aout, uint32_t i_device_id, int i_format,
574 int i_channels, int i_nb_channels, int i_rate,
579 /* Set sound format */
581 #define waveformat p_aout->output.p_sys->waveformat
583 waveformat.dwChannelMask = 0;
584 for( unsigned i = 0; i < sizeof(pi_channels_src)/sizeof(uint32_t); i++ )
586 if( i_channels & pi_channels_src[i] )
587 waveformat.dwChannelMask |= pi_channels_in[i];
592 case VLC_CODEC_SPDIFL:
594 /* To prevent channel re-ordering */
595 waveformat.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
596 waveformat.Format.wBitsPerSample = 16;
597 waveformat.Samples.wValidBitsPerSample =
598 waveformat.Format.wBitsPerSample;
599 waveformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
600 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF;
604 waveformat.Format.wBitsPerSample = sizeof(float) * 8;
605 waveformat.Samples.wValidBitsPerSample =
606 waveformat.Format.wBitsPerSample;
607 waveformat.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
608 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
612 waveformat.Format.wBitsPerSample = 16;
613 waveformat.Samples.wValidBitsPerSample =
614 waveformat.Format.wBitsPerSample;
615 waveformat.Format.wFormatTag = WAVE_FORMAT_PCM;
616 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_PCM;
620 waveformat.Format.nChannels = i_nb_channels;
621 waveformat.Format.nSamplesPerSec = i_rate;
622 waveformat.Format.nBlockAlign =
623 waveformat.Format.wBitsPerSample / 8 * i_nb_channels;
624 waveformat.Format.nAvgBytesPerSec =
625 waveformat.Format.nSamplesPerSec * waveformat.Format.nBlockAlign;
627 /* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */
628 if( i_nb_channels <= 2 )
630 waveformat.Format.cbSize = 0;
634 waveformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
635 waveformat.Format.cbSize =
636 sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
640 msg_Dbg( p_aout, "OpenWaveDevice-ID: %u", i_device_id);
641 msg_Dbg( p_aout,"waveformat.Format.cbSize = %d",
642 waveformat.Format.cbSize);
643 msg_Dbg( p_aout,"waveformat.Format.wFormatTag = %u",
644 waveformat.Format.wFormatTag);
645 msg_Dbg( p_aout,"waveformat.Format.nChannels = %u",
646 waveformat.Format.nChannels);
647 msg_Dbg( p_aout,"waveformat.Format.nSamplesPerSec = %d",
648 (int)waveformat.Format.nSamplesPerSec);
649 msg_Dbg( p_aout,"waveformat.Format.nAvgBytesPerSec = %u",
650 (int)waveformat.Format.nAvgBytesPerSec);
651 msg_Dbg( p_aout,"waveformat.Format.nBlockAlign = %d",
652 waveformat.Format.nBlockAlign);
653 msg_Dbg( p_aout,"waveformat.Format.wBitsPerSample = %d",
654 waveformat.Format.wBitsPerSample);
655 msg_Dbg( p_aout,"waveformat.Samples.wValidBitsPerSample = %d",
656 waveformat.Samples.wValidBitsPerSample);
657 msg_Dbg( p_aout,"waveformat.Samples.wSamplesPerBlock = %d",
658 waveformat.Samples.wSamplesPerBlock);
659 msg_Dbg( p_aout,"waveformat.dwChannelMask = %lu",
660 waveformat.dwChannelMask);
663 /* Open the device */
664 result = waveOutOpen( &p_aout->output.p_sys->h_waveout, i_device_id,
665 (WAVEFORMATEX *)&waveformat,
666 (DWORD_PTR)WaveOutCallback, (DWORD_PTR)p_aout,
667 CALLBACK_FUNCTION | (b_probe?WAVE_FORMAT_QUERY:0) );
668 if( result == WAVERR_BADFORMAT )
670 msg_Warn( p_aout, "waveOutOpen failed WAVERR_BADFORMAT" );
673 if( result == MMSYSERR_ALLOCATED )
675 msg_Warn( p_aout, "waveOutOpen failed WAVERR_ALLOCATED" );
678 if( result != MMSYSERR_NOERROR )
680 msg_Warn( p_aout, "waveOutOpen failed" );
684 p_aout->output.p_sys->b_chan_reorder =
685 aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
686 waveformat.dwChannelMask, i_nb_channels,
687 p_aout->output.p_sys->pi_chan_table );
689 if( p_aout->output.p_sys->b_chan_reorder )
691 msg_Dbg( p_aout, "channel reordering needed" );
700 /*****************************************************************************
701 * OpenWaveOutPCM: open a PCM waveout sound device
702 ****************************************************************************/
703 static int OpenWaveOutPCM( aout_instance_t *p_aout, uint32_t i_device_id,
704 vlc_fourcc_t *i_format,
705 int i_channels, int i_nb_channels, int i_rate,
708 bool b_use_float32 = var_CreateGetBool( p_aout, "waveout-float32");
710 if( !b_use_float32 || OpenWaveOut( p_aout, i_device_id, VLC_CODEC_FL32,
711 i_channels, i_nb_channels, i_rate, b_probe )
714 if ( OpenWaveOut( p_aout, i_device_id, VLC_CODEC_S16L,
715 i_channels, i_nb_channels, i_rate, b_probe )
722 *i_format = VLC_CODEC_S16L;
728 *i_format = VLC_CODEC_FL32;
733 /*****************************************************************************
734 * PlayWaveOut: play a buffer through the WaveOut device
735 *****************************************************************************/
736 static int PlayWaveOut( aout_instance_t *p_aout, HWAVEOUT h_waveout,
737 WAVEHDR *p_waveheader, aout_buffer_t *p_buffer,
742 /* Prepare the buffer */
743 if( p_buffer != NULL )
745 p_waveheader->lpData = (LPSTR)p_buffer->p_buffer;
747 copy the buffer to the silence buffer :) so in case we don't
748 get the next buffer fast enough (I will repeat this one a time
749 for AC3 / DTS and SPDIF this will sound better instead of
754 vlc_memcpy( p_aout->output.p_sys->p_silence_buffer,
756 p_aout->output.p_sys->i_buffer_size );
757 p_aout->output.p_sys->i_repeat_counter = 2;
760 /* Use silence buffer instead */
761 if(p_aout->output.p_sys->i_repeat_counter)
763 p_aout->output.p_sys->i_repeat_counter--;
764 if(!p_aout->output.p_sys->i_repeat_counter)
766 vlc_memset( p_aout->output.p_sys->p_silence_buffer,
767 0x00, p_aout->output.p_sys->i_buffer_size );
770 p_waveheader->lpData = (LPSTR)p_aout->output.p_sys->p_silence_buffer;
773 p_waveheader->dwUser = p_buffer ? (DWORD_PTR)p_buffer : (DWORD_PTR)1;
774 p_waveheader->dwBufferLength = p_aout->output.p_sys->i_buffer_size;
775 p_waveheader->dwFlags = 0;
777 result = waveOutPrepareHeader( h_waveout, p_waveheader, sizeof(WAVEHDR) );
778 if( result != MMSYSERR_NOERROR )
780 msg_Err( p_aout, "waveOutPrepareHeader failed" );
784 /* Send the buffer to the waveOut queue */
785 result = waveOutWrite( h_waveout, p_waveheader, sizeof(WAVEHDR) );
786 if( result != MMSYSERR_NOERROR )
788 msg_Err( p_aout, "waveOutWrite failed" );
795 /*****************************************************************************
796 * WaveOutCallback: what to do once WaveOut has played its sound samples
797 *****************************************************************************/
798 static void CALLBACK WaveOutCallback( HWAVEOUT h_waveout, UINT uMsg,
800 DWORD dwParam1, DWORD dwParam2 )
802 (void)h_waveout; (void)dwParam1; (void)dwParam2;
803 aout_instance_t *p_aout = (aout_instance_t *)_p_aout;
804 int i_queued_frames = 0;
806 if( uMsg != WOM_DONE ) return;
808 if( vlc_atomic_get(&p_aout->output.p_sys->abort) ) return;
810 /* Find out the current latency */
811 for( int i = 0; i < FRAMES_NUM; i++ )
813 /* Check if frame buf is available */
814 if( !(p_aout->output.p_sys->waveheader[i].dwFlags & WHDR_DONE) )
820 /* Don't wake up the thread too much */
821 if( i_queued_frames <= FRAMES_NUM/2 )
822 SetEvent( p_aout->output.p_sys->event );
826 /****************************************************************************
827 * WaveOutClearDoneBuffers: Clear all done marked buffers, and free aout_bufer
828 ****************************************************************************
829 * return value is the number of still playing buffers in the queue
830 ****************************************************************************/
831 static int WaveOutClearDoneBuffers(aout_sys_t *p_sys)
833 WAVEHDR *p_waveheader = p_sys->waveheader;
834 int i_queued_frames = 0;
836 for( int i = 0; i < FRAMES_NUM; i++ )
838 if( (p_waveheader[i].dwFlags & WHDR_DONE) &&
839 p_waveheader[i].dwUser )
841 aout_buffer_t *p_buffer =
842 (aout_buffer_t *)(p_waveheader[i].dwUser);
843 /* Unprepare and free the buffers which has just been played */
844 waveOutUnprepareHeader( p_sys->h_waveout, &p_waveheader[i],
847 if( p_waveheader[i].dwUser != 1 )
848 aout_BufferFree( p_buffer );
850 p_waveheader[i].dwUser = 0;
853 /* Check if frame buf is available */
854 if( !(p_waveheader[i].dwFlags & WHDR_DONE) )
859 return i_queued_frames;
862 /*****************************************************************************
863 * WaveOutThread: this thread will capture play notification events.
864 *****************************************************************************
865 * We use this thread to feed new audio samples to the sound card because
866 * we are not authorized to use waveOutWrite() directly in the waveout
868 *****************************************************************************/
869 static void* WaveOutThread( void *data )
871 aout_instance_t *p_aout = data;
872 aout_sys_t *p_sys = p_aout->output.p_sys;
873 aout_buffer_t *p_buffer = NULL;
874 WAVEHDR *p_waveheader = p_sys->waveheader;
875 int i, i_queued_frames;
878 uint32_t i_buffer_length = 64;
879 int canc = vlc_savecancel ();
881 /* We don't want any resampling when using S/PDIF */
882 b_sleek = p_aout->output.output.i_format == VLC_CODEC_SPDIFL;
884 // wait for first call to "play()"
885 while( !p_sys->start_date && !vlc_atomic_get(&p_aout->output.p_sys->abort) )
886 WaitForSingleObject( p_sys->event, INFINITE );
887 if( vlc_atomic_get(&p_aout->output.p_sys->abort) )
890 msg_Dbg( p_aout, "will start to play in %"PRId64" us",
891 (p_sys->start_date - AOUT_PTS_TOLERANCE/4)-mdate());
893 // than wait a short time... before grabbing first frames
894 mwait( p_sys->start_date - AOUT_PTS_TOLERANCE/4 );
896 #define waveout_warn(msg) msg_Warn( p_aout, "aout_OutputNextBuffer no buffer "\
897 "got next_date=%d ms, "\
898 "%d frames to play, %s",\
899 (int)(next_date/(mtime_t)1000), \
900 i_queued_frames, msg);
903 while( !vlc_atomic_get(&p_aout->output.p_sys->abort) )
905 /* Cleanup and find out the current latency */
906 i_queued_frames = WaveOutClearDoneBuffers( p_sys );
908 if( vlc_atomic_get(&p_aout->output.p_sys->abort) ) return NULL;
910 /* Try to fill in as many frame buffers as possible */
911 for( i = 0; i < FRAMES_NUM; i++ )
913 /* Check if frame buf is available */
914 if( p_waveheader[i].dwFlags & WHDR_DONE )
916 // next_date = mdate() + 1000000 * i_queued_frames /
917 // p_aout->output.output.i_rate * p_aout->output.i_nb_samples;
919 // the realtime has got our back-site:) to come in sync
920 if(next_date < mdate())
924 /* Take into account the latency */
925 p_buffer = aout_OutputNextBuffer( p_aout,
932 msg_Dbg( p_aout, "aout_OutputNextBuffer no buffer "
933 "got next_date=%d ms, "
935 (int)(next_date/(mtime_t)1000),
938 // means we are too early to request a new buffer?
939 waveout_warn("waiting...")
940 next_date = aout_FifoFirstDate( &p_aout->output.fifo );
941 mwait( next_date - AOUT_PTS_TOLERANCE/4 );
943 p_buffer = aout_OutputNextBuffer( p_aout, next_date,
947 if( !p_buffer && i_queued_frames )
949 /* We aren't late so no need to play a blank sample */
955 mtime_t buffer_length = p_buffer->i_length;
956 next_date = next_date + buffer_length;
957 i_buffer_length = buffer_length/1000;
960 /* Do the channel reordering */
961 if( p_buffer && p_sys->b_chan_reorder )
963 aout_ChannelReorder( p_buffer->p_buffer,
965 p_sys->waveformat.Format.nChannels,
966 p_sys->pi_chan_table,
967 p_sys->waveformat.Format.wBitsPerSample );
970 PlayWaveOut( p_aout, p_sys->h_waveout,
971 &p_waveheader[i], p_buffer, b_sleek );
977 if( vlc_atomic_get(&p_aout->output.p_sys->abort) ) return NULL;
980 deal with the case that the loop didn't fillup the buffer to the
981 max - instead of waiting that half the buffer is played before
982 fillup the waveout buffers, wait only for the next sample buffer
983 to arrive at the play method...
985 this will also avoid, that the last buffer is play until the
986 end, and then trying to get more data, so it will also
987 work - if the next buffer will arrive some ms before the
988 last buffer is finished.
990 if(i_queued_frames < FRAMES_NUM)
991 WaitForSingleObject( p_sys->new_buffer_event, INFINITE );
993 WaitForSingleObject( p_sys->event, INFINITE );
998 vlc_restorecancel (canc);
1002 static int VolumeSet( aout_instance_t * p_aout, audio_volume_t i_volume,
1006 i_volume = AOUT_VOLUME_MIN;
1008 unsigned long i_waveout_vol = i_volume * 0xFFFF * 2 / AOUT_VOLUME_MAX;
1009 i_waveout_vol |= (i_waveout_vol << 16);
1012 waveOutSetVolume( 0, i_waveout_vol );
1014 waveOutSetVolume( p_aout->output.p_sys->h_waveout, i_waveout_vol );
1021 reload the configuration drop down list, of the Audio Devices
1023 static int ReloadWaveoutDevices( vlc_object_t *p_this, char const *psz_name,
1024 vlc_value_t newval, vlc_value_t oldval, void *data )
1026 VLC_UNUSED( newval ); VLC_UNUSED( oldval ); VLC_UNUSED( data );
1028 module_config_t *p_item = config_FindConfig( p_this, psz_name );
1029 if( !p_item ) return VLC_SUCCESS;
1031 /* Clear-up the current list */
1032 if( p_item->i_list )
1036 /* Keep the first entry */
1037 for( i = 1; i < p_item->i_list; i++ )
1039 free((char *)(p_item->ppsz_list[i]) );
1040 free((char *)(p_item->ppsz_list_text[i]) );
1042 /* TODO: Remove when no more needed */
1043 p_item->ppsz_list[i] = NULL;
1044 p_item->ppsz_list_text[i] = NULL;
1048 int wave_devices = waveOutGetNumDevs();
1050 p_item->ppsz_list = xrealloc( p_item->ppsz_list,
1051 (wave_devices+2) * sizeof(char *) );
1052 p_item->ppsz_list_text = xrealloc( p_item->ppsz_list_text,
1053 (wave_devices+2) * sizeof(char *) );
1056 char sz_dev_name[MAXPNAMELEN+32];
1058 for(int i=0; i<wave_devices; i++)
1060 if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
1061 == MMSYSERR_NOERROR)
1063 sprintf( sz_dev_name, psz_device_name_fmt, caps.szPname,
1067 p_item->ppsz_list[j] = FromLocaleDup( sz_dev_name );
1068 p_item->ppsz_list_text[j] = FromLocaleDup( sz_dev_name );
1074 p_item->ppsz_list[j] = NULL;
1075 p_item->ppsz_list_text[j] = NULL;
1077 /* Signal change to the interface */
1078 p_item->b_dirty = true;
1084 convert devicename to device ID for output
1085 if device not found return WAVE_MAPPER, so let
1086 windows decide which preferred audio device
1089 static uint32_t findDeviceID(char *psz_device_name)
1091 if( !psz_device_name )
1094 uint32_t wave_devices = waveOutGetNumDevs();
1096 char sz_dev_name[MAXPNAMELEN+32];
1098 for( uint32_t i = 0; i < wave_devices; i++ )
1100 if( waveOutGetDevCaps( i, &caps, sizeof(WAVEOUTCAPS) )
1101 == MMSYSERR_NOERROR)
1103 sprintf( sz_dev_name, psz_device_name_fmt, caps.szPname,
1107 char *psz_temp = FromLocaleDup(sz_dev_name);
1109 if( !stricmp(psz_temp, psz_device_name) )
1111 LocaleFree( psz_temp );
1114 LocaleFree( psz_temp );