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 *, float, 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->sys = malloc( sizeof( aout_sys_t ) );
153 if( p_aout->sys == NULL )
156 p_aout->pf_play = Play;
157 p_aout->pf_pause = NULL;
160 initialize/update Device selection List
162 ReloadWaveoutDevices( p_this, "waveout-audio-device", val, val, NULL);
166 check for configured audio device!
168 char *psz_waveout_dev = var_CreateGetString( p_aout, "waveout-audio-device");
170 p_aout->sys->i_wave_device_id =
171 findDeviceID( psz_waveout_dev );
173 if(p_aout->sys->i_wave_device_id == WAVE_MAPPER)
175 if(psz_waveout_dev &&
176 stricmp(psz_waveout_dev,"wavemapper"))
178 msg_Warn( p_aout, "configured audio device '%s' not available, "\
179 "use default instead", psz_waveout_dev );
182 free( psz_waveout_dev );
185 WAVEOUTCAPS waveoutcaps;
186 if(waveOutGetDevCaps( p_aout->sys->i_wave_device_id,
188 sizeof(WAVEOUTCAPS)) == MMSYSERR_NOERROR)
190 /* log debug some infos about driver, to know who to blame
191 if it doesn't work */
192 msg_Dbg( p_aout, "Drivername: %s", waveoutcaps.szPname);
193 msg_Dbg( p_aout, "Driver Version: %d.%d",
194 (waveoutcaps.vDriverVersion>>8)&255,
195 waveoutcaps.vDriverVersion & 255);
196 msg_Dbg( p_aout, "Manufacturer identifier: 0x%x", waveoutcaps.wMid );
197 msg_Dbg( p_aout, "Product identifier: 0x%x", waveoutcaps.wPid );
202 if( var_Type( p_aout, "audio-device" ) == 0 )
207 if( var_Get( p_aout, "audio-device", &val ) < 0 )
209 /* Probe() has failed. */
210 var_Destroy( p_aout, "waveout-audio-device");
216 /* Open the device */
217 if( val.i_int == AOUT_VAR_SPDIF )
219 p_aout->format.i_format = VLC_CODEC_SPDIFL;
221 if( OpenWaveOut( p_aout,
222 p_aout->sys->i_wave_device_id,
224 p_aout->format.i_physical_channels,
225 aout_FormatNbChannels( &p_aout->format ),
226 p_aout->format.i_rate, false )
229 msg_Err( p_aout, "cannot open waveout audio device" );
234 /* Calculate the frame size in bytes */
235 p_aout->i_nb_samples = A52_FRAME_NB;
236 p_aout->format.i_bytes_per_frame = AOUT_SPDIF_SIZE;
237 p_aout->format.i_frame_length = A52_FRAME_NB;
238 p_aout->sys->i_buffer_size =
239 p_aout->format.i_bytes_per_frame;
241 aout_VolumeNoneInit( p_aout );
250 p_aout->format.i_physical_channels
251 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
252 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
256 p_aout->format.i_physical_channels
257 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
258 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
261 p_aout->format.i_physical_channels = AOUT_CHAN_CENTER;
264 p_aout->format.i_physical_channels
265 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
268 if( OpenWaveOutPCM( p_aout,
269 p_aout->sys->i_wave_device_id,
270 &p_aout->format.i_format,
271 p_aout->format.i_physical_channels,
272 aout_FormatNbChannels( &p_aout->format ),
273 p_aout->format.i_rate, false )
276 msg_Err( p_aout, "cannot open waveout audio device" );
281 /* Calculate the frame size in bytes */
282 p_aout->i_nb_samples = FRAME_SIZE;
283 aout_FormatPrepare( &p_aout->format );
284 p_aout->sys->i_buffer_size = FRAME_SIZE *
285 p_aout->format.i_bytes_per_frame;
287 aout_VolumeSoftInit( p_aout );
289 /* Check for hardware volume support */
290 if( waveOutGetDevCaps( (UINT_PTR)p_aout->sys->h_waveout,
291 &wocaps, sizeof(wocaps) ) == MMSYSERR_NOERROR &&
292 wocaps.dwSupport & WAVECAPS_VOLUME )
295 if( waveOutGetVolume( p_aout->sys->h_waveout, &i_dummy )
296 == MMSYSERR_NOERROR )
298 p_aout->pf_volume_set = VolumeSet;
304 waveOutReset( p_aout->sys->h_waveout );
306 /* Allocate silence buffer */
307 p_aout->sys->p_silence_buffer =
308 malloc( p_aout->sys->i_buffer_size );
309 if( p_aout->sys->p_silence_buffer == NULL )
314 p_aout->sys->i_repeat_counter = 0;
317 /* Zero the buffer. WinCE doesn't have calloc(). */
318 memset( p_aout->sys->p_silence_buffer, 0,
319 p_aout->sys->i_buffer_size );
321 /* Now we need to setup our waveOut play notification structure */
322 p_aout->sys->event = CreateEvent( NULL, FALSE, FALSE, NULL );
323 p_aout->sys->new_buffer_event = CreateEvent( NULL, FALSE, FALSE, NULL );
325 /* define startpoint of playback on first call to play()
326 like alsa does (instead of playing a blank sample) */
327 p_aout->sys->b_playing = 0;
328 p_aout->sys->start_date = 0;
331 /* Then launch the notification thread */
332 vlc_atomic_set( &p_aout->sys->abort, 0);
333 if( vlc_clone( &p_aout->sys->thread,
334 WaveOutThread, p_aout, VLC_THREAD_PRIORITY_OUTPUT ) )
336 msg_Err( p_aout, "cannot create WaveOutThread" );
339 /* We need to kick off the playback in order to have the callback properly
341 for( int i = 0; i < FRAMES_NUM; i++ )
343 p_aout->sys->waveheader[i].dwFlags = WHDR_DONE;
344 p_aout->sys->waveheader[i].dwUser = 0;
350 /*****************************************************************************
351 * Probe: probe the audio device for available formats and channels
352 *****************************************************************************/
353 static void Probe( aout_instance_t * p_aout )
355 vlc_value_t val, text;
356 vlc_fourcc_t i_format;
357 unsigned int i_physical_channels;
359 var_Create( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
360 text.psz_string = _("Audio Device");
361 var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
363 /* Test for 5.1 support */
364 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
365 AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
366 AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE;
367 if( p_aout->format.i_physical_channels == i_physical_channels )
369 if( OpenWaveOutPCM( p_aout,
370 p_aout->sys->i_wave_device_id,
372 i_physical_channels, 6,
373 p_aout->format.i_rate, true )
376 val.i_int = AOUT_VAR_5_1;
377 text.psz_string = (char *)_("5.1");
378 var_Change( p_aout, "audio-device",
379 VLC_VAR_ADDCHOICE, &val, &text );
380 msg_Dbg( p_aout, "device supports 5.1 channels" );
384 /* Test for 2 Front 2 Rear support */
385 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
386 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
387 if( ( p_aout->format.i_physical_channels & i_physical_channels )
388 == i_physical_channels )
390 if( OpenWaveOutPCM( p_aout,
391 p_aout->sys->i_wave_device_id,
393 i_physical_channels, 4,
394 p_aout->format.i_rate, true )
397 val.i_int = AOUT_VAR_2F2R;
398 text.psz_string = (char *)_("2 Front 2 Rear");
399 var_Change( p_aout, "audio-device",
400 VLC_VAR_ADDCHOICE, &val, &text );
401 msg_Dbg( p_aout, "device supports 4 channels" );
405 /* Test for stereo support */
406 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
407 if( OpenWaveOutPCM( p_aout,
408 p_aout->sys->i_wave_device_id,
410 i_physical_channels, 2,
411 p_aout->format.i_rate, true )
414 val.i_int = AOUT_VAR_STEREO;
415 text.psz_string = (char *)_("Stereo");
416 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
417 msg_Dbg( p_aout, "device supports 2 channels" );
420 /* Test for mono support */
421 i_physical_channels = AOUT_CHAN_CENTER;
422 if( OpenWaveOutPCM( p_aout,
423 p_aout->sys->i_wave_device_id,
425 i_physical_channels, 1,
426 p_aout->format.i_rate, true )
429 val.i_int = AOUT_VAR_MONO;
430 text.psz_string = (char *)_("Mono");
431 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
432 msg_Dbg( p_aout, "device supports 1 channel" );
435 /* Test for SPDIF support */
436 if ( AOUT_FMT_NON_LINEAR( &p_aout->format ) )
438 if( OpenWaveOut( p_aout,
439 p_aout->sys->i_wave_device_id,
441 p_aout->format.i_physical_channels,
442 aout_FormatNbChannels( &p_aout->format ),
443 p_aout->format.i_rate, true )
446 msg_Dbg( p_aout, "device supports A/52 over S/PDIF" );
447 val.i_int = AOUT_VAR_SPDIF;
448 text.psz_string = (char *)_("A/52 over S/PDIF");
449 var_Change( p_aout, "audio-device",
450 VLC_VAR_ADDCHOICE, &val, &text );
451 if( var_InheritBool( p_aout, "spdif" ) )
452 var_Set( p_aout, "audio-device", val );
456 var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
459 /* Probe() has failed. */
460 var_Destroy( p_aout, "audio-device" );
464 var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
465 var_TriggerCallback( p_aout, "intf-change" );
468 /*****************************************************************************
469 * Play: play a sound buffer
470 *****************************************************************************
471 * This doesn't actually play the buffer. This just stores the buffer so it
472 * can be played by the callback thread.
473 *****************************************************************************/
474 static void Play( aout_instance_t *_p_aout )
476 if( !_p_aout->sys->b_playing )
478 _p_aout->sys->b_playing = 1;
480 /* get the playing date of the first aout buffer */
481 _p_aout->sys->start_date =
482 aout_FifoFirstDate( &_p_aout->fifo );
484 msg_Dbg( _p_aout, "Wakeup sleeping output thread.");
486 /* wake up the audio output thread */
487 SetEvent( _p_aout->sys->event );
489 SetEvent( _p_aout->sys->new_buffer_event );
493 /*****************************************************************************
494 * Close: close the audio device
495 *****************************************************************************/
496 static void Close( vlc_object_t *p_this )
498 aout_instance_t *p_aout = (aout_instance_t *)p_this;
499 aout_sys_t *p_sys = p_aout->sys;
501 /* Before calling waveOutClose we must reset the device */
502 vlc_atomic_set( &p_sys->abort, 1);
504 /* wake up the audio thread, to recognize that p_aout died */
505 SetEvent( p_sys->event );
506 SetEvent( p_sys->new_buffer_event );
508 vlc_join( p_sys->thread, NULL );
511 kill the real output then - when the feed thread
512 is surely terminated!
513 old code could be too early in case that "feeding"
514 was running on termination
516 at this point now its sure, that there will be no new
517 data send to the driver, and we can cancel the last
520 MMRESULT result = waveOutReset( p_sys->h_waveout );
521 if(result != MMSYSERR_NOERROR)
523 msg_Err( p_aout, "waveOutReset failed 0x%x", result );
525 now we must wait, that all buffers are played
526 because cancel doesn't work in this case...
528 if(result == MMSYSERR_NOTSUPPORTED)
531 clear currently played (done) buffers,
532 if returnvalue > 0 (means some buffer still playing)
533 wait for the driver event callback that one buffer
534 is finished with playing, and check again
535 the timeout of 5000ms is just, an emergency exit
536 of this loop, to avoid deadlock in case of other
537 (currently not known bugs, problems, errors cases?)
540 (WaveOutClearDoneBuffers( p_sys ) > 0)
542 (WaitForSingleObject( p_sys->event, 5000) == WAIT_OBJECT_0)
545 msg_Dbg( p_aout, "Wait for waveout device...");
549 WaveOutClearDoneBuffers( p_sys );
552 /* now we can Close the device */
553 if( waveOutClose( p_sys->h_waveout ) != MMSYSERR_NOERROR )
555 msg_Err( p_aout, "waveOutClose failed" );
559 because so long, the waveout device is playing, the callback
560 could occur and need the events
562 CloseHandle( p_sys->event );
563 CloseHandle( p_sys->new_buffer_event);
565 free( p_sys->p_silence_buffer );
569 /*****************************************************************************
570 * OpenWaveOut: open the waveout sound device
571 ****************************************************************************/
572 static int OpenWaveOut( aout_instance_t *p_aout, uint32_t i_device_id, int i_format,
573 int i_channels, int i_nb_channels, int i_rate,
578 /* Set sound format */
580 #define waveformat p_aout->sys->waveformat
582 waveformat.dwChannelMask = 0;
583 for( unsigned i = 0; i < sizeof(pi_channels_src)/sizeof(uint32_t); i++ )
585 if( i_channels & pi_channels_src[i] )
586 waveformat.dwChannelMask |= pi_channels_in[i];
591 case VLC_CODEC_SPDIFL:
593 /* To prevent channel re-ordering */
594 waveformat.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
595 waveformat.Format.wBitsPerSample = 16;
596 waveformat.Samples.wValidBitsPerSample =
597 waveformat.Format.wBitsPerSample;
598 waveformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
599 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF;
603 waveformat.Format.wBitsPerSample = sizeof(float) * 8;
604 waveformat.Samples.wValidBitsPerSample =
605 waveformat.Format.wBitsPerSample;
606 waveformat.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
607 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
611 waveformat.Format.wBitsPerSample = 16;
612 waveformat.Samples.wValidBitsPerSample =
613 waveformat.Format.wBitsPerSample;
614 waveformat.Format.wFormatTag = WAVE_FORMAT_PCM;
615 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_PCM;
619 waveformat.Format.nChannels = i_nb_channels;
620 waveformat.Format.nSamplesPerSec = i_rate;
621 waveformat.Format.nBlockAlign =
622 waveformat.Format.wBitsPerSample / 8 * i_nb_channels;
623 waveformat.Format.nAvgBytesPerSec =
624 waveformat.Format.nSamplesPerSec * waveformat.Format.nBlockAlign;
626 /* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */
627 if( i_nb_channels <= 2 )
629 waveformat.Format.cbSize = 0;
633 waveformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
634 waveformat.Format.cbSize =
635 sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
639 msg_Dbg( p_aout, "OpenWaveDevice-ID: %u", i_device_id);
640 msg_Dbg( p_aout,"waveformat.Format.cbSize = %d",
641 waveformat.Format.cbSize);
642 msg_Dbg( p_aout,"waveformat.Format.wFormatTag = %u",
643 waveformat.Format.wFormatTag);
644 msg_Dbg( p_aout,"waveformat.Format.nChannels = %u",
645 waveformat.Format.nChannels);
646 msg_Dbg( p_aout,"waveformat.Format.nSamplesPerSec = %d",
647 (int)waveformat.Format.nSamplesPerSec);
648 msg_Dbg( p_aout,"waveformat.Format.nAvgBytesPerSec = %u",
649 (int)waveformat.Format.nAvgBytesPerSec);
650 msg_Dbg( p_aout,"waveformat.Format.nBlockAlign = %d",
651 waveformat.Format.nBlockAlign);
652 msg_Dbg( p_aout,"waveformat.Format.wBitsPerSample = %d",
653 waveformat.Format.wBitsPerSample);
654 msg_Dbg( p_aout,"waveformat.Samples.wValidBitsPerSample = %d",
655 waveformat.Samples.wValidBitsPerSample);
656 msg_Dbg( p_aout,"waveformat.Samples.wSamplesPerBlock = %d",
657 waveformat.Samples.wSamplesPerBlock);
658 msg_Dbg( p_aout,"waveformat.dwChannelMask = %lu",
659 waveformat.dwChannelMask);
662 /* Open the device */
663 result = waveOutOpen( &p_aout->sys->h_waveout, i_device_id,
664 (WAVEFORMATEX *)&waveformat,
665 (DWORD_PTR)WaveOutCallback, (DWORD_PTR)p_aout,
666 CALLBACK_FUNCTION | (b_probe?WAVE_FORMAT_QUERY:0) );
667 if( result == WAVERR_BADFORMAT )
669 msg_Warn( p_aout, "waveOutOpen failed WAVERR_BADFORMAT" );
672 if( result == MMSYSERR_ALLOCATED )
674 msg_Warn( p_aout, "waveOutOpen failed WAVERR_ALLOCATED" );
677 if( result != MMSYSERR_NOERROR )
679 msg_Warn( p_aout, "waveOutOpen failed" );
683 p_aout->sys->b_chan_reorder =
684 aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
685 waveformat.dwChannelMask, i_nb_channels,
686 p_aout->sys->pi_chan_table );
688 if( p_aout->sys->b_chan_reorder )
690 msg_Dbg( p_aout, "channel reordering needed" );
699 /*****************************************************************************
700 * OpenWaveOutPCM: open a PCM waveout sound device
701 ****************************************************************************/
702 static int OpenWaveOutPCM( aout_instance_t *p_aout, uint32_t i_device_id,
703 vlc_fourcc_t *i_format,
704 int i_channels, int i_nb_channels, int i_rate,
707 bool b_use_float32 = var_CreateGetBool( p_aout, "waveout-float32");
709 if( !b_use_float32 || OpenWaveOut( p_aout, i_device_id, VLC_CODEC_FL32,
710 i_channels, i_nb_channels, i_rate, b_probe )
713 if ( OpenWaveOut( p_aout, i_device_id, VLC_CODEC_S16L,
714 i_channels, i_nb_channels, i_rate, b_probe )
721 *i_format = VLC_CODEC_S16L;
727 *i_format = VLC_CODEC_FL32;
732 /*****************************************************************************
733 * PlayWaveOut: play a buffer through the WaveOut device
734 *****************************************************************************/
735 static int PlayWaveOut( aout_instance_t *p_aout, HWAVEOUT h_waveout,
736 WAVEHDR *p_waveheader, aout_buffer_t *p_buffer,
741 /* Prepare the buffer */
742 if( p_buffer != NULL )
744 p_waveheader->lpData = (LPSTR)p_buffer->p_buffer;
746 copy the buffer to the silence buffer :) so in case we don't
747 get the next buffer fast enough (I will repeat this one a time
748 for AC3 / DTS and SPDIF this will sound better instead of
753 vlc_memcpy( p_aout->sys->p_silence_buffer,
755 p_aout->sys->i_buffer_size );
756 p_aout->sys->i_repeat_counter = 2;
759 /* Use silence buffer instead */
760 if(p_aout->sys->i_repeat_counter)
762 p_aout->sys->i_repeat_counter--;
763 if(!p_aout->sys->i_repeat_counter)
765 vlc_memset( p_aout->sys->p_silence_buffer,
766 0x00, p_aout->sys->i_buffer_size );
769 p_waveheader->lpData = (LPSTR)p_aout->sys->p_silence_buffer;
772 p_waveheader->dwUser = p_buffer ? (DWORD_PTR)p_buffer : (DWORD_PTR)1;
773 p_waveheader->dwBufferLength = p_aout->sys->i_buffer_size;
774 p_waveheader->dwFlags = 0;
776 result = waveOutPrepareHeader( h_waveout, p_waveheader, sizeof(WAVEHDR) );
777 if( result != MMSYSERR_NOERROR )
779 msg_Err( p_aout, "waveOutPrepareHeader failed" );
783 /* Send the buffer to the waveOut queue */
784 result = waveOutWrite( h_waveout, p_waveheader, sizeof(WAVEHDR) );
785 if( result != MMSYSERR_NOERROR )
787 msg_Err( p_aout, "waveOutWrite failed" );
794 /*****************************************************************************
795 * WaveOutCallback: what to do once WaveOut has played its sound samples
796 *****************************************************************************/
797 static void CALLBACK WaveOutCallback( HWAVEOUT h_waveout, UINT uMsg,
799 DWORD dwParam1, DWORD dwParam2 )
801 (void)h_waveout; (void)dwParam1; (void)dwParam2;
802 aout_instance_t *p_aout = (aout_instance_t *)_p_aout;
803 int i_queued_frames = 0;
805 if( uMsg != WOM_DONE ) return;
807 if( vlc_atomic_get(&p_aout->sys->abort) ) return;
809 /* Find out the current latency */
810 for( int i = 0; i < FRAMES_NUM; i++ )
812 /* Check if frame buf is available */
813 if( !(p_aout->sys->waveheader[i].dwFlags & WHDR_DONE) )
819 /* Don't wake up the thread too much */
820 if( i_queued_frames <= FRAMES_NUM/2 )
821 SetEvent( p_aout->sys->event );
825 /****************************************************************************
826 * WaveOutClearDoneBuffers: Clear all done marked buffers, and free aout_bufer
827 ****************************************************************************
828 * return value is the number of still playing buffers in the queue
829 ****************************************************************************/
830 static int WaveOutClearDoneBuffers(aout_sys_t *p_sys)
832 WAVEHDR *p_waveheader = p_sys->waveheader;
833 int i_queued_frames = 0;
835 for( int i = 0; i < FRAMES_NUM; i++ )
837 if( (p_waveheader[i].dwFlags & WHDR_DONE) &&
838 p_waveheader[i].dwUser )
840 aout_buffer_t *p_buffer =
841 (aout_buffer_t *)(p_waveheader[i].dwUser);
842 /* Unprepare and free the buffers which has just been played */
843 waveOutUnprepareHeader( p_sys->h_waveout, &p_waveheader[i],
846 if( p_waveheader[i].dwUser != 1 )
847 aout_BufferFree( p_buffer );
849 p_waveheader[i].dwUser = 0;
852 /* Check if frame buf is available */
853 if( !(p_waveheader[i].dwFlags & WHDR_DONE) )
858 return i_queued_frames;
861 /*****************************************************************************
862 * WaveOutThread: this thread will capture play notification events.
863 *****************************************************************************
864 * We use this thread to feed new audio samples to the sound card because
865 * we are not authorized to use waveOutWrite() directly in the waveout
867 *****************************************************************************/
868 static void* WaveOutThread( void *data )
870 aout_instance_t *p_aout = data;
871 aout_sys_t *p_sys = p_aout->sys;
872 aout_buffer_t *p_buffer = NULL;
873 WAVEHDR *p_waveheader = p_sys->waveheader;
874 int i, i_queued_frames;
877 uint32_t i_buffer_length = 64;
878 int canc = vlc_savecancel ();
880 /* We don't want any resampling when using S/PDIF */
881 b_sleek = p_aout->format.i_format == VLC_CODEC_SPDIFL;
883 // wait for first call to "play()"
884 while( !p_sys->start_date && !vlc_atomic_get(&p_aout->sys->abort) )
885 WaitForSingleObject( p_sys->event, INFINITE );
886 if( vlc_atomic_get(&p_aout->sys->abort) )
889 msg_Dbg( p_aout, "will start to play in %"PRId64" us",
890 (p_sys->start_date - AOUT_MAX_PTS_ADVANCE/4)-mdate());
892 // than wait a short time... before grabbing first frames
893 mwait( p_sys->start_date - AOUT_MAX_PTS_ADVANCE/4 );
895 #define waveout_warn(msg) msg_Warn( p_aout, "aout_OutputNextBuffer no buffer "\
896 "got next_date=%d ms, "\
897 "%d frames to play, %s",\
898 (int)(next_date/(mtime_t)1000), \
899 i_queued_frames, msg);
902 while( !vlc_atomic_get(&p_aout->sys->abort) )
904 /* Cleanup and find out the current latency */
905 i_queued_frames = WaveOutClearDoneBuffers( p_sys );
907 if( vlc_atomic_get(&p_aout->sys->abort) ) return NULL;
909 /* Try to fill in as many frame buffers as possible */
910 for( i = 0; i < FRAMES_NUM; i++ )
912 /* Check if frame buf is available */
913 if( p_waveheader[i].dwFlags & WHDR_DONE )
915 // next_date = mdate() + 1000000 * i_queued_frames /
916 // p_aout->format.i_rate * p_aout->i_nb_samples;
918 // the realtime has got our back-site:) to come in sync
919 if(next_date < mdate())
923 /* Take into account the latency */
924 p_buffer = aout_OutputNextBuffer( p_aout,
931 msg_Dbg( p_aout, "aout_OutputNextBuffer no buffer "
932 "got next_date=%d ms, "
934 (int)(next_date/(mtime_t)1000),
937 // means we are too early to request a new buffer?
938 waveout_warn("waiting...")
939 next_date = aout_FifoFirstDate( &p_aout->fifo );
940 mwait( next_date - AOUT_MAX_PTS_ADVANCE/4 );
942 p_buffer = aout_OutputNextBuffer( p_aout, next_date,
946 if( !p_buffer && i_queued_frames )
948 /* We aren't late so no need to play a blank sample */
954 mtime_t buffer_length = p_buffer->i_length;
955 next_date = next_date + buffer_length;
956 i_buffer_length = buffer_length/1000;
959 /* Do the channel reordering */
960 if( p_buffer && p_sys->b_chan_reorder )
962 aout_ChannelReorder( p_buffer->p_buffer,
964 p_sys->waveformat.Format.nChannels,
965 p_sys->pi_chan_table,
966 p_sys->waveformat.Format.wBitsPerSample );
969 PlayWaveOut( p_aout, p_sys->h_waveout,
970 &p_waveheader[i], p_buffer, b_sleek );
976 if( vlc_atomic_get(&p_aout->sys->abort) ) return NULL;
979 deal with the case that the loop didn't fillup the buffer to the
980 max - instead of waiting that half the buffer is played before
981 fillup the waveout buffers, wait only for the next sample buffer
982 to arrive at the play method...
984 this will also avoid, that the last buffer is play until the
985 end, and then trying to get more data, so it will also
986 work - if the next buffer will arrive some ms before the
987 last buffer is finished.
989 if(i_queued_frames < FRAMES_NUM)
990 WaitForSingleObject( p_sys->new_buffer_event, INFINITE );
992 WaitForSingleObject( p_sys->event, INFINITE );
997 vlc_restorecancel (canc);
1001 static int VolumeSet( aout_instance_t * p_aout, float volume, bool mute )
1006 unsigned long i_waveout_vol = volume * 0x7FFF;
1007 i_waveout_vol = (i_waveout_vol << 16) | (i_waveout_vol & 0xFFFF);
1010 waveOutSetVolume( 0, i_waveout_vol );
1012 waveOutSetVolume( p_aout->sys->h_waveout, i_waveout_vol );
1019 reload the configuration drop down list, of the Audio Devices
1021 static int ReloadWaveoutDevices( vlc_object_t *p_this, char const *psz_name,
1022 vlc_value_t newval, vlc_value_t oldval, void *data )
1024 VLC_UNUSED( newval ); VLC_UNUSED( oldval ); VLC_UNUSED( data );
1026 module_config_t *p_item = config_FindConfig( p_this, psz_name );
1027 if( !p_item ) return VLC_SUCCESS;
1029 /* Clear-up the current list */
1030 if( p_item->i_list )
1034 /* Keep the first entry */
1035 for( i = 1; i < p_item->i_list; i++ )
1037 free((char *)(p_item->ppsz_list[i]) );
1038 free((char *)(p_item->ppsz_list_text[i]) );
1040 /* TODO: Remove when no more needed */
1041 p_item->ppsz_list[i] = NULL;
1042 p_item->ppsz_list_text[i] = NULL;
1046 int wave_devices = waveOutGetNumDevs();
1048 p_item->ppsz_list = xrealloc( p_item->ppsz_list,
1049 (wave_devices+2) * sizeof(char *) );
1050 p_item->ppsz_list_text = xrealloc( p_item->ppsz_list_text,
1051 (wave_devices+2) * sizeof(char *) );
1054 char sz_dev_name[MAXPNAMELEN+32];
1056 for(int i=0; i<wave_devices; i++)
1058 if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
1059 == MMSYSERR_NOERROR)
1061 sprintf( sz_dev_name, psz_device_name_fmt, caps.szPname,
1065 p_item->ppsz_list[j] = FromLocaleDup( sz_dev_name );
1066 p_item->ppsz_list_text[j] = FromLocaleDup( sz_dev_name );
1072 p_item->ppsz_list[j] = NULL;
1073 p_item->ppsz_list_text[j] = NULL;
1075 /* Signal change to the interface */
1076 p_item->b_dirty = true;
1082 convert devicename to device ID for output
1083 if device not found return WAVE_MAPPER, so let
1084 windows decide which preferred audio device
1087 static uint32_t findDeviceID(char *psz_device_name)
1089 if( !psz_device_name )
1092 uint32_t wave_devices = waveOutGetNumDevs();
1094 char sz_dev_name[MAXPNAMELEN+32];
1096 for( uint32_t i = 0; i < wave_devices; i++ )
1098 if( waveOutGetDevCaps( i, &caps, sizeof(WAVEOUTCAPS) )
1099 == MMSYSERR_NOERROR)
1101 sprintf( sz_dev_name, psz_device_name_fmt, caps.szPname,
1105 char *psz_temp = FromLocaleDup(sz_dev_name);
1107 if( !stricmp(psz_temp, psz_device_name) )
1109 LocaleFree( psz_temp );
1112 LocaleFree( psz_temp );