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 *****************************************************************************/
37 #include <vlc_common.h>
38 #include <vlc_plugin.h>
40 #include <vlc_aout_intf.h>
41 #include <vlc_charset.h> /* FromWide() */
42 #include <vlc_atomic.h>
44 #include "windows_audio_common.h"
46 #define FRAME_SIZE 4096 /* The size is in samples, not in bytes */
48 /*****************************************************************************
50 *****************************************************************************/
51 static int Open ( vlc_object_t * );
52 static void Close ( vlc_object_t * );
53 static void Play ( audio_output_t *, block_t * );
55 /*****************************************************************************
56 * notification_thread_t: waveOut event thread
57 *****************************************************************************/
59 static void Probe ( audio_output_t * );
60 static int OpenWaveOut ( audio_output_t *, uint32_t,
61 int, int, int, int, bool );
62 static int OpenWaveOutPCM( audio_output_t *, uint32_t,
63 vlc_fourcc_t*, int, int, int, bool );
64 static int PlayWaveOut ( audio_output_t *, HWAVEOUT, WAVEHDR *,
65 aout_buffer_t *, bool );
67 static void CALLBACK WaveOutCallback ( HWAVEOUT, UINT, DWORD_PTR, DWORD_PTR, DWORD_PTR );
68 static void* WaveOutThread( void * );
70 static int VolumeSet( audio_output_t *, float, bool );
72 static int WaveOutClearDoneBuffers(aout_sys_t *p_sys);
74 static int ReloadWaveoutDevices( vlc_object_t *, char const *,
75 vlc_value_t, vlc_value_t, void * );
76 static uint32_t findDeviceID(char *);
78 static const wchar_t device_name_fmt[] = L"%ls ($%x,$%x)";
80 static const char *const ppsz_adev[] = { "wavemapper", };
81 static const char *const ppsz_adev_text[] = { N_("Microsoft Soundmapper") };
84 /*****************************************************************************
86 *****************************************************************************/
87 #define DEVICE_TEXT N_("Select Audio Device")
88 #define DEVICE_LONG N_("Select special Audio device, or let windows "\
89 "decide (default), change needs VLC restart "\
91 #define DEFAULT_AUDIO_DEVICE N_("Default Audio Device")
94 set_shortname( "WaveOut" )
95 set_description( N_("Win32 waveOut extension output") )
96 set_capability( "audio output", 50 )
97 set_category( CAT_AUDIO )
98 set_subcategory( SUBCAT_AUDIO_AOUT )
100 add_string( "waveout-audio-device", "wavemapper",
101 DEVICE_TEXT, DEVICE_LONG, false )
102 change_string_list( ppsz_adev, ppsz_adev_text, ReloadWaveoutDevices )
103 change_action_add( ReloadWaveoutDevices, N_("Refresh list") )
105 add_bool( "waveout-float32", true, FLOAT_TEXT, FLOAT_LONGTEXT, true )
107 set_callbacks( Open, Close )
110 /*****************************************************************************
111 * aout_sys_t: waveOut audio output method descriptor
112 *****************************************************************************
113 * This structure is part of the audio output thread descriptor.
114 * It describes the waveOut specific properties of an audio device.
115 *****************************************************************************/
118 aout_packet_t packet;
119 uint32_t i_wave_device_id; /* ID of selected output device */
121 HWAVEOUT h_waveout; /* handle to waveout instance */
123 WAVEFORMATEXTENSIBLE waveformat; /* audio format */
125 WAVEHDR waveheader[FRAMES_NUM];
130 HANDLE new_buffer_event;
132 // rental from alsa.c to synchronize startup of audiothread
133 int b_playing; /* playing status */
136 int i_repeat_counter;
140 uint8_t *p_silence_buffer; /* buffer we use to play silence */
142 bool b_chan_reorder; /* do we need channel reordering */
143 int pi_chan_table[AOUT_CHAN_MAX];
146 /*****************************************************************************
147 * Open: open the audio device
148 *****************************************************************************
149 * This function opens and setups Win32 waveOut
150 *****************************************************************************/
151 static int Open( vlc_object_t *p_this )
153 audio_output_t *p_aout = (audio_output_t *)p_this;
156 /* Allocate structure */
157 p_aout->sys = malloc( sizeof( aout_sys_t ) );
159 if( p_aout->sys == NULL )
162 p_aout->pf_play = Play;
163 p_aout->pf_pause = aout_PacketPause;
164 p_aout->pf_flush = aout_PacketFlush;
167 initialize/update Device selection List
169 ReloadWaveoutDevices( p_this, "waveout-audio-device", val, val, NULL);
173 check for configured audio device!
175 char *psz_waveout_dev = var_CreateGetString( p_aout, "waveout-audio-device");
177 p_aout->sys->i_wave_device_id =
178 findDeviceID( psz_waveout_dev );
180 if(p_aout->sys->i_wave_device_id == WAVE_MAPPER)
182 if(psz_waveout_dev &&
183 stricmp(psz_waveout_dev,"wavemapper"))
185 msg_Warn( p_aout, "configured audio device '%s' not available, "\
186 "use default instead", psz_waveout_dev );
189 free( psz_waveout_dev );
192 WAVEOUTCAPS waveoutcaps;
193 if(waveOutGetDevCaps( p_aout->sys->i_wave_device_id,
195 sizeof(WAVEOUTCAPS)) == MMSYSERR_NOERROR)
197 /* log debug some infos about driver, to know who to blame
198 if it doesn't work */
199 msg_Dbg( p_aout, "Drivername: %ls", waveoutcaps.szPname);
200 msg_Dbg( p_aout, "Driver Version: %d.%d",
201 (waveoutcaps.vDriverVersion>>8)&255,
202 waveoutcaps.vDriverVersion & 255);
203 msg_Dbg( p_aout, "Manufacturer identifier: 0x%x", waveoutcaps.wMid );
204 msg_Dbg( p_aout, "Product identifier: 0x%x", waveoutcaps.wPid );
209 if( var_Type( p_aout, "audio-device" ) == 0 )
214 if( var_Get( p_aout, "audio-device", &val ) < 0 )
216 /* Probe() has failed. */
217 var_Destroy( p_aout, "waveout-audio-device");
223 /* Open the device */
224 if( val.i_int == AOUT_VAR_SPDIF )
226 p_aout->format.i_format = VLC_CODEC_SPDIFL;
228 if( OpenWaveOut( p_aout,
229 p_aout->sys->i_wave_device_id,
231 p_aout->format.i_physical_channels,
232 aout_FormatNbChannels( &p_aout->format ),
233 p_aout->format.i_rate, false )
236 msg_Err( p_aout, "cannot open waveout audio device" );
241 /* Calculate the frame size in bytes */
242 p_aout->format.i_bytes_per_frame = AOUT_SPDIF_SIZE;
243 p_aout->format.i_frame_length = A52_FRAME_NB;
244 p_aout->sys->i_buffer_size =
245 p_aout->format.i_bytes_per_frame;
247 aout_PacketInit( p_aout, &p_aout->sys->packet, A52_FRAME_NB );
248 aout_VolumeNoneInit( p_aout );
257 p_aout->format.i_physical_channels
258 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
259 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
263 p_aout->format.i_physical_channels
264 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
265 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
268 p_aout->format.i_physical_channels = AOUT_CHAN_CENTER;
271 p_aout->format.i_physical_channels
272 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
275 if( OpenWaveOutPCM( p_aout,
276 p_aout->sys->i_wave_device_id,
277 &p_aout->format.i_format,
278 p_aout->format.i_physical_channels,
279 aout_FormatNbChannels( &p_aout->format ),
280 p_aout->format.i_rate, false )
283 msg_Err( p_aout, "cannot open waveout audio device" );
288 /* Calculate the frame size in bytes */
289 aout_FormatPrepare( &p_aout->format );
290 p_aout->sys->i_buffer_size = FRAME_SIZE *
291 p_aout->format.i_bytes_per_frame;
293 aout_PacketInit( p_aout, &p_aout->sys->packet, FRAME_SIZE );
295 /* Check for hardware volume support */
296 if( waveOutGetDevCaps( (UINT_PTR)p_aout->sys->h_waveout,
297 &wocaps, sizeof(wocaps) ) == MMSYSERR_NOERROR
298 && (wocaps.dwSupport & WAVECAPS_VOLUME) )
299 aout_VolumeHardInit( p_aout, VolumeSet, false /* ?? */ );
301 aout_VolumeSoftInit( p_aout );
305 waveOutReset( p_aout->sys->h_waveout );
307 /* Allocate silence buffer */
308 p_aout->sys->p_silence_buffer =
309 malloc( p_aout->sys->i_buffer_size );
310 if( p_aout->sys->p_silence_buffer == NULL )
312 aout_PacketDestroy( p_aout );
316 p_aout->sys->i_repeat_counter = 0;
319 /* Zero the buffer. WinCE doesn't have calloc(). */
320 memset( p_aout->sys->p_silence_buffer, 0,
321 p_aout->sys->i_buffer_size );
323 /* Now we need to setup our waveOut play notification structure */
324 p_aout->sys->event = CreateEvent( NULL, FALSE, FALSE, NULL );
325 p_aout->sys->new_buffer_event = CreateEvent( NULL, FALSE, FALSE, NULL );
327 /* define startpoint of playback on first call to play()
328 like alsa does (instead of playing a blank sample) */
329 p_aout->sys->b_playing = 0;
330 p_aout->sys->start_date = 0;
333 /* Then launch the notification thread */
334 vlc_atomic_set( &p_aout->sys->abort, 0);
335 if( vlc_clone( &p_aout->sys->thread,
336 WaveOutThread, p_aout, VLC_THREAD_PRIORITY_OUTPUT ) )
338 msg_Err( p_aout, "cannot create WaveOutThread" );
341 /* We need to kick off the playback in order to have the callback properly
343 for( int i = 0; i < FRAMES_NUM; i++ )
345 p_aout->sys->waveheader[i].dwFlags = WHDR_DONE;
346 p_aout->sys->waveheader[i].dwUser = 0;
352 /*****************************************************************************
353 * Probe: probe the audio device for available formats and channels
354 *****************************************************************************/
355 static void Probe( audio_output_t * p_aout )
357 vlc_value_t val, text;
358 vlc_fourcc_t i_format;
359 unsigned int i_physical_channels;
361 var_Create( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
362 text.psz_string = _("Audio Device");
363 var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
365 /* Test for 5.1 support */
366 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
367 AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
368 AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE;
369 if( p_aout->format.i_physical_channels == i_physical_channels )
371 if( OpenWaveOutPCM( p_aout,
372 p_aout->sys->i_wave_device_id,
374 i_physical_channels, 6,
375 p_aout->format.i_rate, true )
378 val.i_int = AOUT_VAR_5_1;
379 text.psz_string = (char *)_("5.1");
380 var_Change( p_aout, "audio-device",
381 VLC_VAR_ADDCHOICE, &val, &text );
382 msg_Dbg( p_aout, "device supports 5.1 channels" );
386 /* Test for 2 Front 2 Rear support */
387 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
388 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
389 if( ( p_aout->format.i_physical_channels & i_physical_channels )
390 == i_physical_channels )
392 if( OpenWaveOutPCM( p_aout,
393 p_aout->sys->i_wave_device_id,
395 i_physical_channels, 4,
396 p_aout->format.i_rate, true )
399 val.i_int = AOUT_VAR_2F2R;
400 text.psz_string = (char *)_("2 Front 2 Rear");
401 var_Change( p_aout, "audio-device",
402 VLC_VAR_ADDCHOICE, &val, &text );
403 msg_Dbg( p_aout, "device supports 4 channels" );
407 /* Test for stereo support */
408 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
409 if( OpenWaveOutPCM( p_aout,
410 p_aout->sys->i_wave_device_id,
412 i_physical_channels, 2,
413 p_aout->format.i_rate, true )
416 val.i_int = AOUT_VAR_STEREO;
417 text.psz_string = (char *)_("Stereo");
418 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
419 msg_Dbg( p_aout, "device supports 2 channels" );
422 /* Test for mono support */
423 i_physical_channels = AOUT_CHAN_CENTER;
424 if( OpenWaveOutPCM( p_aout,
425 p_aout->sys->i_wave_device_id,
427 i_physical_channels, 1,
428 p_aout->format.i_rate, true )
431 val.i_int = AOUT_VAR_MONO;
432 text.psz_string = (char *)_("Mono");
433 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
434 msg_Dbg( p_aout, "device supports 1 channel" );
437 /* Test for SPDIF support */
438 if ( AOUT_FMT_SPDIF( &p_aout->format ) )
440 if( OpenWaveOut( p_aout,
441 p_aout->sys->i_wave_device_id,
443 p_aout->format.i_physical_channels,
444 aout_FormatNbChannels( &p_aout->format ),
445 p_aout->format.i_rate, true )
448 msg_Dbg( p_aout, "device supports A/52 over S/PDIF" );
449 val.i_int = AOUT_VAR_SPDIF;
450 text.psz_string = (char *)_("A/52 over S/PDIF");
451 var_Change( p_aout, "audio-device",
452 VLC_VAR_ADDCHOICE, &val, &text );
453 if( var_InheritBool( p_aout, "spdif" ) )
454 var_Set( p_aout, "audio-device", val );
458 var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
461 /* Probe() has failed. */
462 var_Destroy( p_aout, "audio-device" );
466 var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
467 var_TriggerCallback( p_aout, "intf-change" );
470 /*****************************************************************************
471 * Play: play a sound buffer
472 *****************************************************************************
473 * This doesn't actually play the buffer. This just stores the buffer so it
474 * can be played by the callback thread.
475 *****************************************************************************/
476 static void Play( audio_output_t *_p_aout, block_t *block )
478 if( !_p_aout->sys->b_playing )
480 _p_aout->sys->b_playing = 1;
482 /* get the playing date of the first aout buffer */
483 _p_aout->sys->start_date = block->i_pts;
485 msg_Dbg( _p_aout, "Wakeup sleeping output thread.");
487 /* wake up the audio output thread */
488 SetEvent( _p_aout->sys->event );
490 SetEvent( _p_aout->sys->new_buffer_event );
493 aout_PacketPlay( _p_aout, block );
496 /*****************************************************************************
497 * Close: close the audio device
498 *****************************************************************************/
499 static void Close( vlc_object_t *p_this )
501 audio_output_t *p_aout = (audio_output_t *)p_this;
502 aout_sys_t *p_sys = p_aout->sys;
504 /* Before calling waveOutClose we must reset the device */
505 vlc_atomic_set( &p_sys->abort, 1);
507 /* wake up the audio thread, to recognize that p_aout died */
508 SetEvent( p_sys->event );
509 SetEvent( p_sys->new_buffer_event );
511 vlc_join( p_sys->thread, NULL );
514 kill the real output then - when the feed thread
515 is surely terminated!
516 old code could be too early in case that "feeding"
517 was running on termination
519 at this point now its sure, that there will be no new
520 data send to the driver, and we can cancel the last
523 MMRESULT result = waveOutReset( p_sys->h_waveout );
524 if(result != MMSYSERR_NOERROR)
526 msg_Err( p_aout, "waveOutReset failed 0x%x", result );
528 now we must wait, that all buffers are played
529 because cancel doesn't work in this case...
531 if(result == MMSYSERR_NOTSUPPORTED)
534 clear currently played (done) buffers,
535 if returnvalue > 0 (means some buffer still playing)
536 wait for the driver event callback that one buffer
537 is finished with playing, and check again
538 the timeout of 5000ms is just, an emergency exit
539 of this loop, to avoid deadlock in case of other
540 (currently not known bugs, problems, errors cases?)
543 (WaveOutClearDoneBuffers( p_sys ) > 0)
545 (WaitForSingleObject( p_sys->event, 5000) == WAIT_OBJECT_0)
548 msg_Dbg( p_aout, "Wait for waveout device...");
552 WaveOutClearDoneBuffers( p_sys );
555 /* now we can Close the device */
556 if( waveOutClose( p_sys->h_waveout ) != MMSYSERR_NOERROR )
558 msg_Err( p_aout, "waveOutClose failed" );
562 because so long, the waveout device is playing, the callback
563 could occur and need the events
565 CloseHandle( p_sys->event );
566 CloseHandle( p_sys->new_buffer_event);
568 free( p_sys->p_silence_buffer );
569 aout_PacketDestroy( p_aout );
573 /*****************************************************************************
574 * OpenWaveOut: open the waveout sound device
575 ****************************************************************************/
576 static int OpenWaveOut( audio_output_t *p_aout, uint32_t i_device_id, int i_format,
577 int i_channels, int i_nb_channels, int i_rate,
582 /* Set sound format */
584 #define waveformat p_aout->sys->waveformat
586 waveformat.dwChannelMask = 0;
587 for( unsigned i = 0; i < sizeof(pi_channels_src)/sizeof(uint32_t); i++ )
589 if( i_channels & pi_channels_src[i] )
590 waveformat.dwChannelMask |= pi_channels_in[i];
595 case VLC_CODEC_SPDIFL:
597 /* To prevent channel re-ordering */
598 waveformat.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
599 waveformat.Format.wBitsPerSample = 16;
600 waveformat.Samples.wValidBitsPerSample =
601 waveformat.Format.wBitsPerSample;
602 waveformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
603 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF;
607 waveformat.Format.wBitsPerSample = sizeof(float) * 8;
608 waveformat.Samples.wValidBitsPerSample =
609 waveformat.Format.wBitsPerSample;
610 waveformat.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
611 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
615 waveformat.Format.wBitsPerSample = 16;
616 waveformat.Samples.wValidBitsPerSample =
617 waveformat.Format.wBitsPerSample;
618 waveformat.Format.wFormatTag = WAVE_FORMAT_PCM;
619 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_PCM;
623 waveformat.Format.nChannels = i_nb_channels;
624 waveformat.Format.nSamplesPerSec = i_rate;
625 waveformat.Format.nBlockAlign =
626 waveformat.Format.wBitsPerSample / 8 * i_nb_channels;
627 waveformat.Format.nAvgBytesPerSec =
628 waveformat.Format.nSamplesPerSec * waveformat.Format.nBlockAlign;
630 /* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */
631 if( i_nb_channels <= 2 )
633 waveformat.Format.cbSize = 0;
637 waveformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
638 waveformat.Format.cbSize =
639 sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
643 msg_Dbg( p_aout, "OpenWaveDevice-ID: %u", i_device_id);
644 msg_Dbg( p_aout,"waveformat.Format.cbSize = %d",
645 waveformat.Format.cbSize);
646 msg_Dbg( p_aout,"waveformat.Format.wFormatTag = %u",
647 waveformat.Format.wFormatTag);
648 msg_Dbg( p_aout,"waveformat.Format.nChannels = %u",
649 waveformat.Format.nChannels);
650 msg_Dbg( p_aout,"waveformat.Format.nSamplesPerSec = %d",
651 (int)waveformat.Format.nSamplesPerSec);
652 msg_Dbg( p_aout,"waveformat.Format.nAvgBytesPerSec = %u",
653 (int)waveformat.Format.nAvgBytesPerSec);
654 msg_Dbg( p_aout,"waveformat.Format.nBlockAlign = %d",
655 waveformat.Format.nBlockAlign);
656 msg_Dbg( p_aout,"waveformat.Format.wBitsPerSample = %d",
657 waveformat.Format.wBitsPerSample);
658 msg_Dbg( p_aout,"waveformat.Samples.wValidBitsPerSample = %d",
659 waveformat.Samples.wValidBitsPerSample);
660 msg_Dbg( p_aout,"waveformat.Samples.wSamplesPerBlock = %d",
661 waveformat.Samples.wSamplesPerBlock);
662 msg_Dbg( p_aout,"waveformat.dwChannelMask = %lu",
663 waveformat.dwChannelMask);
666 /* Open the device */
667 result = waveOutOpen( &p_aout->sys->h_waveout, i_device_id,
668 (WAVEFORMATEX *)&waveformat,
669 (DWORD_PTR)WaveOutCallback, (DWORD_PTR)p_aout,
670 CALLBACK_FUNCTION | (b_probe?WAVE_FORMAT_QUERY:0) );
671 if( result == WAVERR_BADFORMAT )
673 msg_Warn( p_aout, "waveOutOpen failed WAVERR_BADFORMAT" );
676 if( result == MMSYSERR_ALLOCATED )
678 msg_Warn( p_aout, "waveOutOpen failed WAVERR_ALLOCATED" );
681 if( result != MMSYSERR_NOERROR )
683 msg_Warn( p_aout, "waveOutOpen failed" );
687 p_aout->sys->b_chan_reorder =
688 aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
689 waveformat.dwChannelMask, i_nb_channels,
690 p_aout->sys->pi_chan_table );
692 if( p_aout->sys->b_chan_reorder )
694 msg_Dbg( p_aout, "channel reordering needed" );
703 /*****************************************************************************
704 * OpenWaveOutPCM: open a PCM waveout sound device
705 ****************************************************************************/
706 static int OpenWaveOutPCM( audio_output_t *p_aout, uint32_t i_device_id,
707 vlc_fourcc_t *i_format,
708 int i_channels, int i_nb_channels, int i_rate,
711 bool b_use_float32 = var_CreateGetBool( p_aout, "waveout-float32");
713 if( !b_use_float32 || OpenWaveOut( p_aout, i_device_id, VLC_CODEC_FL32,
714 i_channels, i_nb_channels, i_rate, b_probe )
717 if ( OpenWaveOut( p_aout, i_device_id, VLC_CODEC_S16L,
718 i_channels, i_nb_channels, i_rate, b_probe )
725 *i_format = VLC_CODEC_S16L;
731 *i_format = VLC_CODEC_FL32;
736 /*****************************************************************************
737 * PlayWaveOut: play a buffer through the WaveOut device
738 *****************************************************************************/
739 static int PlayWaveOut( audio_output_t *p_aout, HWAVEOUT h_waveout,
740 WAVEHDR *p_waveheader, aout_buffer_t *p_buffer,
745 /* Prepare the buffer */
746 if( p_buffer != NULL )
748 p_waveheader->lpData = (LPSTR)p_buffer->p_buffer;
750 copy the buffer to the silence buffer :) so in case we don't
751 get the next buffer fast enough (I will repeat this one a time
752 for AC3 / DTS and SPDIF this will sound better instead of
757 vlc_memcpy( p_aout->sys->p_silence_buffer,
759 p_aout->sys->i_buffer_size );
760 p_aout->sys->i_repeat_counter = 2;
763 /* Use silence buffer instead */
764 if(p_aout->sys->i_repeat_counter)
766 p_aout->sys->i_repeat_counter--;
767 if(!p_aout->sys->i_repeat_counter)
769 vlc_memset( p_aout->sys->p_silence_buffer,
770 0x00, p_aout->sys->i_buffer_size );
773 p_waveheader->lpData = (LPSTR)p_aout->sys->p_silence_buffer;
776 p_waveheader->dwUser = p_buffer ? (DWORD_PTR)p_buffer : (DWORD_PTR)1;
777 p_waveheader->dwBufferLength = p_aout->sys->i_buffer_size;
778 p_waveheader->dwFlags = 0;
780 result = waveOutPrepareHeader( h_waveout, p_waveheader, sizeof(WAVEHDR) );
781 if( result != MMSYSERR_NOERROR )
783 msg_Err( p_aout, "waveOutPrepareHeader failed" );
787 /* Send the buffer to the waveOut queue */
788 result = waveOutWrite( h_waveout, p_waveheader, sizeof(WAVEHDR) );
789 if( result != MMSYSERR_NOERROR )
791 msg_Err( p_aout, "waveOutWrite failed" );
798 /*****************************************************************************
799 * WaveOutCallback: what to do once WaveOut has played its sound samples
800 *****************************************************************************/
801 static void CALLBACK WaveOutCallback( HWAVEOUT h_waveout, UINT uMsg,
803 DWORD_PTR dwParam1, DWORD_PTR dwParam2 )
805 (void)h_waveout; (void)dwParam1; (void)dwParam2;
806 audio_output_t *p_aout = (audio_output_t *)_p_aout;
807 int i_queued_frames = 0;
809 if( uMsg != WOM_DONE ) return;
811 if( vlc_atomic_get(&p_aout->sys->abort) ) return;
813 /* Find out the current latency */
814 for( int i = 0; i < FRAMES_NUM; i++ )
816 /* Check if frame buf is available */
817 if( !(p_aout->sys->waveheader[i].dwFlags & WHDR_DONE) )
823 /* Don't wake up the thread too much */
824 if( i_queued_frames <= FRAMES_NUM/2 )
825 SetEvent( p_aout->sys->event );
829 /****************************************************************************
830 * WaveOutClearDoneBuffers: Clear all done marked buffers, and free aout_bufer
831 ****************************************************************************
832 * return value is the number of still playing buffers in the queue
833 ****************************************************************************/
834 static int WaveOutClearDoneBuffers(aout_sys_t *p_sys)
836 WAVEHDR *p_waveheader = p_sys->waveheader;
837 int i_queued_frames = 0;
839 for( int i = 0; i < FRAMES_NUM; i++ )
841 if( (p_waveheader[i].dwFlags & WHDR_DONE) &&
842 p_waveheader[i].dwUser )
844 aout_buffer_t *p_buffer =
845 (aout_buffer_t *)(p_waveheader[i].dwUser);
846 /* Unprepare and free the buffers which has just been played */
847 waveOutUnprepareHeader( p_sys->h_waveout, &p_waveheader[i],
850 if( p_waveheader[i].dwUser != 1 )
851 aout_BufferFree( p_buffer );
853 p_waveheader[i].dwUser = 0;
856 /* Check if frame buf is available */
857 if( !(p_waveheader[i].dwFlags & WHDR_DONE) )
862 return i_queued_frames;
865 /*****************************************************************************
866 * WaveOutThread: this thread will capture play notification events.
867 *****************************************************************************
868 * We use this thread to feed new audio samples to the sound card because
869 * we are not authorized to use waveOutWrite() directly in the waveout
871 *****************************************************************************/
872 static void* WaveOutThread( void *data )
874 audio_output_t *p_aout = data;
875 aout_sys_t *p_sys = p_aout->sys;
876 aout_buffer_t *p_buffer = NULL;
877 WAVEHDR *p_waveheader = p_sys->waveheader;
878 int i, i_queued_frames;
881 int canc = vlc_savecancel ();
883 /* We don't want any resampling when using S/PDIF */
884 b_sleek = p_aout->format.i_format == VLC_CODEC_SPDIFL;
886 // wait for first call to "play()"
887 while( !p_sys->start_date && !vlc_atomic_get(&p_aout->sys->abort) )
888 WaitForSingleObject( p_sys->event, INFINITE );
889 if( vlc_atomic_get(&p_aout->sys->abort) )
892 msg_Dbg( p_aout, "will start to play in %"PRId64" us",
893 (p_sys->start_date - AOUT_MAX_PTS_ADVANCE/4)-mdate());
895 // than wait a short time... before grabbing first frames
896 mwait( p_sys->start_date - AOUT_MAX_PTS_ADVANCE/4 );
898 #define waveout_warn(msg) msg_Warn( p_aout, "aout_PacketNext no buffer "\
899 "got next_date=%d ms, "\
900 "%d frames to play, %s",\
901 (int)(next_date/(mtime_t)1000), \
902 i_queued_frames, msg);
905 while( !vlc_atomic_get(&p_aout->sys->abort) )
907 /* Cleanup and find out the current latency */
908 i_queued_frames = WaveOutClearDoneBuffers( p_sys );
910 if( vlc_atomic_get(&p_aout->sys->abort) ) return NULL;
912 /* Try to fill in as many frame buffers as possible */
913 for( i = 0; i < FRAMES_NUM; i++ )
915 /* Check if frame buf is available */
916 if( p_waveheader[i].dwFlags & WHDR_DONE )
918 // next_date = mdate() + 1000000 * i_queued_frames /
919 // p_aout->format.i_rate * p_aout->i_nb_samples;
921 // the realtime has got our back-site:) to come in sync
922 if(next_date < mdate())
926 /* Take into account the latency */
927 p_buffer = aout_PacketNext( p_aout, next_date );
931 msg_Dbg( p_aout, "aout_PacketNext no buffer got "
932 "next_date=%"PRId64" ms, %d frames to play",
933 next_date/1000, i_queued_frames);
935 // means we are too early to request a new buffer?
936 waveout_warn("waiting...")
937 mwait( next_date - AOUT_MAX_PTS_ADVANCE/4 );
939 p_buffer = aout_PacketNext( p_aout, next_date );
942 if( !p_buffer && i_queued_frames )
944 /* We aren't late so no need to play a blank sample */
950 mtime_t buffer_length = p_buffer->i_length;
951 next_date = next_date + buffer_length;
954 /* Do the channel reordering */
955 if( p_buffer && p_sys->b_chan_reorder )
957 aout_ChannelReorder( p_buffer->p_buffer,
959 p_sys->waveformat.Format.nChannels,
960 p_sys->pi_chan_table,
961 p_sys->waveformat.Format.wBitsPerSample );
964 PlayWaveOut( p_aout, p_sys->h_waveout,
965 &p_waveheader[i], p_buffer, b_sleek );
971 if( vlc_atomic_get(&p_aout->sys->abort) ) return NULL;
974 deal with the case that the loop didn't fillup the buffer to the
975 max - instead of waiting that half the buffer is played before
976 fillup the waveout buffers, wait only for the next sample buffer
977 to arrive at the play method...
979 this will also avoid, that the last buffer is play until the
980 end, and then trying to get more data, so it will also
981 work - if the next buffer will arrive some ms before the
982 last buffer is finished.
984 if(i_queued_frames < FRAMES_NUM)
985 WaitForSingleObject( p_sys->new_buffer_event, INFINITE );
987 WaitForSingleObject( p_sys->event, INFINITE );
992 vlc_restorecancel (canc);
996 static int VolumeSet( audio_output_t * p_aout, float volume, bool mute )
1001 unsigned long i_waveout_vol = volume
1002 * (0xFFFF * AOUT_VOLUME_DEFAULT / AOUT_VOLUME_MAX);
1004 if( i_waveout_vol <= 0xFFFF )
1005 i_waveout_vol |= i_waveout_vol << 16;
1007 i_waveout_vol = 0xFFFFFFFF;
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 for(int i=0; i<wave_devices; i++)
1057 wchar_t dev_name[MAXPNAMELEN+32];
1059 if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
1060 != MMSYSERR_NOERROR)
1063 _snwprintf(dev_name, MAXPNAMELEN + 32, device_name_fmt,
1064 caps.szPname, caps.wMid, caps.wPid);
1065 p_item->ppsz_list[j] = FromWide( dev_name );
1066 p_item->ppsz_list_text[j] = FromWide( dev_name );
1070 p_item->ppsz_list[j] = NULL;
1071 p_item->ppsz_list_text[j] = NULL;
1077 convert devicename to device ID for output
1078 if device not found return WAVE_MAPPER, so let
1079 windows decide which preferred audio device
1082 static uint32_t findDeviceID(char *psz_device_name)
1084 if( !psz_device_name )
1087 uint32_t wave_devices = waveOutGetNumDevs();
1089 for( uint32_t i = 0; i < wave_devices; i++ )
1092 wchar_t dev_name[MAXPNAMELEN+32];
1094 if( waveOutGetDevCaps( i, &caps, sizeof(WAVEOUTCAPS) )
1095 != MMSYSERR_NOERROR )
1098 _snwprintf( dev_name, MAXPNAMELEN + 32, device_name_fmt,
1099 caps.szPname, caps.wMid, caps.wPid );
1100 char *u8 = FromWide(dev_name);
1101 if( !stricmp(u8, psz_device_name) )