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 *****************************************************************************/
38 #include <vlc_common.h>
39 #include <vlc_plugin.h>
41 #include <vlc_aout_intf.h>
42 #include <vlc_charset.h> /* FromWide() */
43 #include <vlc_atomic.h>
45 #include "windows_audio_common.h"
47 #define FRAME_SIZE 4096 /* The size is in samples, not in bytes */
49 /*****************************************************************************
51 *****************************************************************************/
52 static int Open ( vlc_object_t * );
53 static void Close ( vlc_object_t * );
54 static void Play ( audio_output_t *, block_t *, mtime_t * );
56 /*****************************************************************************
57 * notification_thread_t: waveOut event thread
58 *****************************************************************************/
60 static void Probe ( audio_output_t * );
61 static int OpenWaveOut ( audio_output_t *, uint32_t,
62 int, int, int, int, bool );
63 static int OpenWaveOutPCM( audio_output_t *, uint32_t,
64 vlc_fourcc_t*, int, int, int, bool );
65 static int PlayWaveOut ( audio_output_t *, HWAVEOUT, WAVEHDR *,
68 static void CALLBACK WaveOutCallback ( HWAVEOUT, UINT, DWORD_PTR, DWORD_PTR, DWORD_PTR );
69 static void* WaveOutThread( void * );
71 static int VolumeSet( audio_output_t *, float );
72 static int MuteSet( audio_output_t *, bool );
74 static int WaveOutClearDoneBuffers(aout_sys_t *p_sys);
76 static int ReloadWaveoutDevices( vlc_object_t *, char const *,
77 vlc_value_t, vlc_value_t, void * );
78 static uint32_t findDeviceID(char *);
80 static const wchar_t device_name_fmt[] = L"%ls ($%x,$%x)";
82 static const char *const ppsz_adev[] = { "wavemapper", };
83 static const char *const ppsz_adev_text[] = { N_("Microsoft Soundmapper") };
85 /*****************************************************************************
86 * aout_sys_t: waveOut audio output method descriptor
87 *****************************************************************************
88 * This structure is part of the audio output thread descriptor.
89 * It describes the waveOut specific properties of an audio device.
90 *****************************************************************************/
94 uint32_t i_wave_device_id; /* ID of selected output device */
96 HWAVEOUT h_waveout; /* handle to waveout instance */
98 WAVEFORMATEXTENSIBLE waveformat; /* audio format */
100 WAVEHDR waveheader[FRAMES_NUM];
105 HANDLE new_buffer_event;
107 // rental from alsa.c to synchronize startup of audiothread
108 int b_playing; /* playing status */
111 int i_repeat_counter;
115 uint8_t *p_silence_buffer; /* buffer we use to play silence */
126 bool b_chan_reorder; /* do we need channel reordering */
127 int pi_chan_table[AOUT_CHAN_MAX];
132 /*****************************************************************************
134 *****************************************************************************/
135 #define DEVICE_TEXT N_("Select Audio Device")
136 #define DEVICE_LONG N_("Select special Audio device, or let windows "\
137 "decide (default), change needs VLC restart "\
139 #define DEFAULT_AUDIO_DEVICE N_("Default Audio Device")
142 set_shortname( "WaveOut" )
143 set_description( N_("Win32 waveOut extension output") )
144 set_capability( "audio output", 50 )
145 set_category( CAT_AUDIO )
146 set_subcategory( SUBCAT_AUDIO_AOUT )
148 add_string( "waveout-audio-device", "wavemapper",
149 DEVICE_TEXT, DEVICE_LONG, false )
150 change_string_list( ppsz_adev, ppsz_adev_text, ReloadWaveoutDevices )
151 change_action_add( ReloadWaveoutDevices, N_("Refresh list") )
154 add_bool( "waveout-float32", true, FLOAT_TEXT, FLOAT_LONGTEXT, true )
156 set_callbacks( Open, Close )
159 /*****************************************************************************
160 * Open: open the audio device
161 *****************************************************************************
162 * This function opens and setups Win32 waveOut
163 *****************************************************************************/
164 static int Open( vlc_object_t *p_this )
166 audio_output_t *p_aout = (audio_output_t *)p_this;
169 /* Allocate structure */
170 p_aout->sys = malloc( sizeof( aout_sys_t ) );
172 if( p_aout->sys == NULL )
175 p_aout->pf_play = Play;
176 p_aout->pf_pause = aout_PacketPause;
177 p_aout->pf_flush = aout_PacketFlush;
180 initialize/update Device selection List
182 ReloadWaveoutDevices( p_this, "waveout-audio-device", val, val, NULL);
185 check for configured audio device!
187 char *psz_waveout_dev = var_CreateGetString( p_aout, "waveout-audio-device");
189 p_aout->sys->i_wave_device_id =
190 findDeviceID( psz_waveout_dev );
192 if(p_aout->sys->i_wave_device_id == WAVE_MAPPER)
194 if(psz_waveout_dev &&
195 stricmp(psz_waveout_dev,"wavemapper"))
197 msg_Warn( p_aout, "configured audio device '%s' not available, "\
198 "use default instead", psz_waveout_dev );
201 free( psz_waveout_dev );
204 WAVEOUTCAPS waveoutcaps;
205 if(waveOutGetDevCaps( p_aout->sys->i_wave_device_id,
207 sizeof(WAVEOUTCAPS)) == MMSYSERR_NOERROR)
209 /* log debug some infos about driver, to know who to blame
210 if it doesn't work */
211 msg_Dbg( p_aout, "Drivername: %ls", waveoutcaps.szPname);
212 msg_Dbg( p_aout, "Driver Version: %d.%d",
213 (waveoutcaps.vDriverVersion>>8)&255,
214 waveoutcaps.vDriverVersion & 255);
215 msg_Dbg( p_aout, "Manufacturer identifier: 0x%x", waveoutcaps.wMid );
216 msg_Dbg( p_aout, "Product identifier: 0x%x", waveoutcaps.wPid );
221 if( var_Type( p_aout, "audio-device" ) == 0 )
226 if( var_Get( p_aout, "audio-device", &val ) < 0 )
228 /* Probe() has failed. */
229 var_Destroy( p_aout, "waveout-audio-device");
235 /* Open the device */
236 if( val.i_int == AOUT_VAR_SPDIF )
238 p_aout->format.i_format = VLC_CODEC_SPDIFL;
240 if( OpenWaveOut( p_aout,
241 p_aout->sys->i_wave_device_id,
243 p_aout->format.i_physical_channels,
244 aout_FormatNbChannels( &p_aout->format ),
245 p_aout->format.i_rate, false )
248 msg_Err( p_aout, "cannot open waveout audio device" );
253 /* Calculate the frame size in bytes */
254 p_aout->format.i_bytes_per_frame = AOUT_SPDIF_SIZE;
255 p_aout->format.i_frame_length = A52_FRAME_NB;
256 p_aout->sys->i_buffer_size =
257 p_aout->format.i_bytes_per_frame;
259 aout_PacketInit( p_aout, &p_aout->sys->packet, A52_FRAME_NB );
260 p_aout->volume_set = NULL;
261 p_aout->mute_set = NULL;
270 p_aout->format.i_physical_channels
271 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
272 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
276 p_aout->format.i_physical_channels
277 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
278 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
281 p_aout->format.i_physical_channels = AOUT_CHAN_CENTER;
284 p_aout->format.i_physical_channels
285 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
288 if( OpenWaveOutPCM( p_aout,
289 p_aout->sys->i_wave_device_id,
290 &p_aout->format.i_format,
291 p_aout->format.i_physical_channels,
292 aout_FormatNbChannels( &p_aout->format ),
293 p_aout->format.i_rate, false )
296 msg_Err( p_aout, "cannot open waveout audio device" );
301 /* Calculate the frame size in bytes */
302 aout_FormatPrepare( &p_aout->format );
303 p_aout->sys->i_buffer_size = FRAME_SIZE *
304 p_aout->format.i_bytes_per_frame;
306 aout_PacketInit( p_aout, &p_aout->sys->packet, FRAME_SIZE );
309 /* Check for hardware volume support */
310 if( waveOutGetDevCaps( (UINT_PTR)p_aout->sys->h_waveout,
311 &wocaps, sizeof(wocaps) ) == MMSYSERR_NOERROR
312 && (wocaps.dwSupport & WAVECAPS_VOLUME) )
314 p_aout->volume_set = VolumeSet;
315 p_aout->mute_set = MuteSet;
316 p_aout->sys->volume = 0xffff.fp0;
317 p_aout->sys->mute = false;
321 aout_SoftVolumeInit( p_aout );
324 waveOutReset( p_aout->sys->h_waveout );
326 /* Allocate silence buffer */
327 p_aout->sys->p_silence_buffer =
328 malloc( p_aout->sys->i_buffer_size );
329 if( p_aout->sys->p_silence_buffer == NULL )
331 aout_PacketDestroy( p_aout );
335 p_aout->sys->i_repeat_counter = 0;
338 /* Zero the buffer. WinCE doesn't have calloc(). */
339 memset( p_aout->sys->p_silence_buffer, 0,
340 p_aout->sys->i_buffer_size );
342 /* Now we need to setup our waveOut play notification structure */
343 p_aout->sys->event = CreateEvent( NULL, FALSE, FALSE, NULL );
344 p_aout->sys->new_buffer_event = CreateEvent( NULL, FALSE, FALSE, NULL );
346 /* define startpoint of playback on first call to play()
347 like alsa does (instead of playing a blank sample) */
348 p_aout->sys->b_playing = 0;
349 p_aout->sys->start_date = 0;
352 /* Then launch the notification thread */
353 vlc_atomic_set( &p_aout->sys->abort, 0);
354 if( vlc_clone( &p_aout->sys->thread,
355 WaveOutThread, p_aout, VLC_THREAD_PRIORITY_OUTPUT ) )
357 msg_Err( p_aout, "cannot create WaveOutThread" );
360 /* We need to kick off the playback in order to have the callback properly
362 for( int i = 0; i < FRAMES_NUM; i++ )
364 p_aout->sys->waveheader[i].dwFlags = WHDR_DONE;
365 p_aout->sys->waveheader[i].dwUser = 0;
371 /*****************************************************************************
372 * Probe: probe the audio device for available formats and channels
373 *****************************************************************************/
374 static void Probe( audio_output_t * p_aout )
376 vlc_value_t val, text;
377 vlc_fourcc_t i_format;
378 unsigned int i_physical_channels;
380 var_Create( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
381 text.psz_string = _("Audio Device");
382 var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
384 /* Test for 5.1 support */
385 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
386 AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
387 AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE;
388 if( p_aout->format.i_physical_channels == i_physical_channels )
390 if( OpenWaveOutPCM( p_aout,
391 p_aout->sys->i_wave_device_id,
393 i_physical_channels, 6,
394 p_aout->format.i_rate, true )
397 val.i_int = AOUT_VAR_5_1;
398 text.psz_string = (char *)_("5.1");
399 var_Change( p_aout, "audio-device",
400 VLC_VAR_ADDCHOICE, &val, &text );
401 msg_Dbg( p_aout, "device supports 5.1 channels" );
405 /* Test for 2 Front 2 Rear support */
406 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
407 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
408 if( ( p_aout->format.i_physical_channels & i_physical_channels )
409 == i_physical_channels )
411 if( OpenWaveOutPCM( p_aout,
412 p_aout->sys->i_wave_device_id,
414 i_physical_channels, 4,
415 p_aout->format.i_rate, true )
418 val.i_int = AOUT_VAR_2F2R;
419 text.psz_string = (char *)_("2 Front 2 Rear");
420 var_Change( p_aout, "audio-device",
421 VLC_VAR_ADDCHOICE, &val, &text );
422 msg_Dbg( p_aout, "device supports 4 channels" );
426 /* Test for stereo support */
427 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
428 if( OpenWaveOutPCM( p_aout,
429 p_aout->sys->i_wave_device_id,
431 i_physical_channels, 2,
432 p_aout->format.i_rate, true )
435 val.i_int = AOUT_VAR_STEREO;
436 text.psz_string = (char *)_("Stereo");
437 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
438 msg_Dbg( p_aout, "device supports 2 channels" );
441 /* Test for mono support */
442 i_physical_channels = AOUT_CHAN_CENTER;
443 if( OpenWaveOutPCM( p_aout,
444 p_aout->sys->i_wave_device_id,
446 i_physical_channels, 1,
447 p_aout->format.i_rate, true )
450 val.i_int = AOUT_VAR_MONO;
451 text.psz_string = (char *)_("Mono");
452 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
453 msg_Dbg( p_aout, "device supports 1 channel" );
456 /* Test for SPDIF support */
457 if ( AOUT_FMT_SPDIF( &p_aout->format ) )
459 if( OpenWaveOut( p_aout,
460 p_aout->sys->i_wave_device_id,
462 p_aout->format.i_physical_channels,
463 aout_FormatNbChannels( &p_aout->format ),
464 p_aout->format.i_rate, true )
467 msg_Dbg( p_aout, "device supports A/52 over S/PDIF" );
468 val.i_int = AOUT_VAR_SPDIF;
469 text.psz_string = (char *)_("A/52 over S/PDIF");
470 var_Change( p_aout, "audio-device",
471 VLC_VAR_ADDCHOICE, &val, &text );
472 if( var_InheritBool( p_aout, "spdif" ) )
473 var_Set( p_aout, "audio-device", val );
477 var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
480 /* Probe() has failed. */
481 var_Destroy( p_aout, "audio-device" );
485 var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
488 /*****************************************************************************
489 * Play: play a sound buffer
490 *****************************************************************************
491 * This doesn't actually play the buffer. This just stores the buffer so it
492 * can be played by the callback thread.
493 *****************************************************************************/
494 static void Play( audio_output_t *_p_aout, block_t *block,
495 mtime_t *restrict drift )
497 if( !_p_aout->sys->b_playing )
499 _p_aout->sys->b_playing = 1;
501 /* get the playing date of the first aout buffer */
502 _p_aout->sys->start_date = block->i_pts;
504 msg_Dbg( _p_aout, "Wakeup sleeping output thread.");
506 /* wake up the audio output thread */
507 SetEvent( _p_aout->sys->event );
509 SetEvent( _p_aout->sys->new_buffer_event );
512 aout_PacketPlay( _p_aout, block, drift );
515 /*****************************************************************************
516 * Close: close the audio device
517 *****************************************************************************/
518 static void Close( vlc_object_t *p_this )
520 audio_output_t *p_aout = (audio_output_t *)p_this;
521 aout_sys_t *p_sys = p_aout->sys;
523 /* Before calling waveOutClose we must reset the device */
524 vlc_atomic_set( &p_sys->abort, 1);
526 /* wake up the audio thread, to recognize that p_aout died */
527 SetEvent( p_sys->event );
528 SetEvent( p_sys->new_buffer_event );
530 vlc_join( p_sys->thread, NULL );
533 kill the real output then - when the feed thread
534 is surely terminated!
535 old code could be too early in case that "feeding"
536 was running on termination
538 at this point now its sure, that there will be no new
539 data send to the driver, and we can cancel the last
542 MMRESULT result = waveOutReset( p_sys->h_waveout );
543 if(result != MMSYSERR_NOERROR)
545 msg_Err( p_aout, "waveOutReset failed 0x%x", result );
547 now we must wait, that all buffers are played
548 because cancel doesn't work in this case...
550 if(result == MMSYSERR_NOTSUPPORTED)
553 clear currently played (done) buffers,
554 if returnvalue > 0 (means some buffer still playing)
555 wait for the driver event callback that one buffer
556 is finished with playing, and check again
557 the timeout of 5000ms is just, an emergency exit
558 of this loop, to avoid deadlock in case of other
559 (currently not known bugs, problems, errors cases?)
562 (WaveOutClearDoneBuffers( p_sys ) > 0)
564 (WaitForSingleObject( p_sys->event, 5000) == WAIT_OBJECT_0)
567 msg_Dbg( p_aout, "Wait for waveout device...");
571 WaveOutClearDoneBuffers( p_sys );
574 /* now we can Close the device */
575 if( waveOutClose( p_sys->h_waveout ) != MMSYSERR_NOERROR )
577 msg_Err( p_aout, "waveOutClose failed" );
581 because so long, the waveout device is playing, the callback
582 could occur and need the events
584 CloseHandle( p_sys->event );
585 CloseHandle( p_sys->new_buffer_event);
587 free( p_sys->p_silence_buffer );
588 aout_PacketDestroy( p_aout );
592 /*****************************************************************************
593 * OpenWaveOut: open the waveout sound device
594 ****************************************************************************/
595 static int OpenWaveOut( audio_output_t *p_aout, uint32_t i_device_id, int i_format,
596 int i_channels, int i_nb_channels, int i_rate,
601 /* Set sound format */
603 #define waveformat p_aout->sys->waveformat
605 waveformat.dwChannelMask = 0;
606 for( unsigned i = 0; pi_vlc_chan_order_wg4[i]; i++ )
607 if( i_channels & pi_vlc_chan_order_wg4[i] )
608 waveformat.dwChannelMask |= pi_channels_in[i];
612 case VLC_CODEC_SPDIFL:
614 /* To prevent channel re-ordering */
615 waveformat.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
616 waveformat.Format.wBitsPerSample = 16;
617 waveformat.Samples.wValidBitsPerSample =
618 waveformat.Format.wBitsPerSample;
619 waveformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
620 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF;
624 waveformat.Format.wBitsPerSample = sizeof(float) * 8;
625 waveformat.Samples.wValidBitsPerSample =
626 waveformat.Format.wBitsPerSample;
627 waveformat.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
628 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
632 waveformat.Format.wBitsPerSample = 16;
633 waveformat.Samples.wValidBitsPerSample =
634 waveformat.Format.wBitsPerSample;
635 waveformat.Format.wFormatTag = WAVE_FORMAT_PCM;
636 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_PCM;
640 waveformat.Format.nChannels = i_nb_channels;
641 waveformat.Format.nSamplesPerSec = i_rate;
642 waveformat.Format.nBlockAlign =
643 waveformat.Format.wBitsPerSample / 8 * i_nb_channels;
644 waveformat.Format.nAvgBytesPerSec =
645 waveformat.Format.nSamplesPerSec * waveformat.Format.nBlockAlign;
647 /* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */
648 if( i_nb_channels <= 2 )
650 waveformat.Format.cbSize = 0;
654 waveformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
655 waveformat.Format.cbSize =
656 sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
660 msg_Dbg( p_aout, "OpenWaveDevice-ID: %u", i_device_id);
661 msg_Dbg( p_aout,"waveformat.Format.cbSize = %d",
662 waveformat.Format.cbSize);
663 msg_Dbg( p_aout,"waveformat.Format.wFormatTag = %u",
664 waveformat.Format.wFormatTag);
665 msg_Dbg( p_aout,"waveformat.Format.nChannels = %u",
666 waveformat.Format.nChannels);
667 msg_Dbg( p_aout,"waveformat.Format.nSamplesPerSec = %d",
668 (int)waveformat.Format.nSamplesPerSec);
669 msg_Dbg( p_aout,"waveformat.Format.nAvgBytesPerSec = %u",
670 (int)waveformat.Format.nAvgBytesPerSec);
671 msg_Dbg( p_aout,"waveformat.Format.nBlockAlign = %d",
672 waveformat.Format.nBlockAlign);
673 msg_Dbg( p_aout,"waveformat.Format.wBitsPerSample = %d",
674 waveformat.Format.wBitsPerSample);
675 msg_Dbg( p_aout,"waveformat.Samples.wValidBitsPerSample = %d",
676 waveformat.Samples.wValidBitsPerSample);
677 msg_Dbg( p_aout,"waveformat.Samples.wSamplesPerBlock = %d",
678 waveformat.Samples.wSamplesPerBlock);
679 msg_Dbg( p_aout,"waveformat.dwChannelMask = %lu",
680 waveformat.dwChannelMask);
683 /* Open the device */
684 result = waveOutOpen( &p_aout->sys->h_waveout, i_device_id,
685 (WAVEFORMATEX *)&waveformat,
686 (DWORD_PTR)WaveOutCallback, (DWORD_PTR)p_aout,
687 CALLBACK_FUNCTION | (b_probe?WAVE_FORMAT_QUERY:0) );
688 if( result == WAVERR_BADFORMAT )
690 msg_Warn( p_aout, "waveOutOpen failed WAVERR_BADFORMAT" );
693 if( result == MMSYSERR_ALLOCATED )
695 msg_Warn( p_aout, "waveOutOpen failed WAVERR_ALLOCATED" );
698 if( result != MMSYSERR_NOERROR )
700 msg_Warn( p_aout, "waveOutOpen failed" );
704 p_aout->sys->b_chan_reorder =
705 aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
706 waveformat.dwChannelMask, i_nb_channels,
707 p_aout->sys->pi_chan_table );
709 if( p_aout->sys->b_chan_reorder )
711 msg_Dbg( p_aout, "channel reordering needed" );
720 /*****************************************************************************
721 * OpenWaveOutPCM: open a PCM waveout sound device
722 ****************************************************************************/
723 static int OpenWaveOutPCM( audio_output_t *p_aout, uint32_t i_device_id,
724 vlc_fourcc_t *i_format,
725 int i_channels, int i_nb_channels, int i_rate,
728 bool b_use_float32 = var_CreateGetBool( p_aout, "waveout-float32");
730 if( !b_use_float32 || OpenWaveOut( p_aout, i_device_id, VLC_CODEC_FL32,
731 i_channels, i_nb_channels, i_rate, b_probe )
734 if ( OpenWaveOut( p_aout, i_device_id, VLC_CODEC_S16L,
735 i_channels, i_nb_channels, i_rate, b_probe )
742 *i_format = VLC_CODEC_S16L;
748 *i_format = VLC_CODEC_FL32;
753 /*****************************************************************************
754 * PlayWaveOut: play a buffer through the WaveOut device
755 *****************************************************************************/
756 static int PlayWaveOut( audio_output_t *p_aout, HWAVEOUT h_waveout,
757 WAVEHDR *p_waveheader, block_t *p_buffer, bool b_spdif)
761 /* Prepare the buffer */
762 if( p_buffer != NULL )
764 p_waveheader->lpData = (LPSTR)p_buffer->p_buffer;
766 copy the buffer to the silence buffer :) so in case we don't
767 get the next buffer fast enough (I will repeat this one a time
768 for AC3 / DTS and SPDIF this will sound better instead of
773 memcpy( p_aout->sys->p_silence_buffer,
775 p_aout->sys->i_buffer_size );
776 p_aout->sys->i_repeat_counter = 2;
779 /* Use silence buffer instead */
780 if(p_aout->sys->i_repeat_counter)
782 p_aout->sys->i_repeat_counter--;
783 if(!p_aout->sys->i_repeat_counter)
785 memset( p_aout->sys->p_silence_buffer,
786 0x00, p_aout->sys->i_buffer_size );
789 p_waveheader->lpData = (LPSTR)p_aout->sys->p_silence_buffer;
792 p_waveheader->dwUser = p_buffer ? (DWORD_PTR)p_buffer : (DWORD_PTR)1;
793 p_waveheader->dwBufferLength = p_aout->sys->i_buffer_size;
794 p_waveheader->dwFlags = 0;
796 result = waveOutPrepareHeader( h_waveout, p_waveheader, sizeof(WAVEHDR) );
797 if( result != MMSYSERR_NOERROR )
799 msg_Err( p_aout, "waveOutPrepareHeader failed" );
803 /* Send the buffer to the waveOut queue */
804 result = waveOutWrite( h_waveout, p_waveheader, sizeof(WAVEHDR) );
805 if( result != MMSYSERR_NOERROR )
807 msg_Err( p_aout, "waveOutWrite failed" );
814 /*****************************************************************************
815 * WaveOutCallback: what to do once WaveOut has played its sound samples
816 *****************************************************************************/
817 static void CALLBACK WaveOutCallback( HWAVEOUT h_waveout, UINT uMsg,
819 DWORD_PTR dwParam1, DWORD_PTR dwParam2 )
821 (void)h_waveout; (void)dwParam1; (void)dwParam2;
822 audio_output_t *p_aout = (audio_output_t *)_p_aout;
823 int i_queued_frames = 0;
825 if( uMsg != WOM_DONE ) return;
827 if( vlc_atomic_get(&p_aout->sys->abort) ) return;
829 /* Find out the current latency */
830 for( int i = 0; i < FRAMES_NUM; i++ )
832 /* Check if frame buf is available */
833 if( !(p_aout->sys->waveheader[i].dwFlags & WHDR_DONE) )
839 /* Don't wake up the thread too much */
840 if( i_queued_frames <= FRAMES_NUM/2 )
841 SetEvent( p_aout->sys->event );
845 /****************************************************************************
846 * WaveOutClearDoneBuffers: Clear all done marked buffers, and free aout_bufer
847 ****************************************************************************
848 * return value is the number of still playing buffers in the queue
849 ****************************************************************************/
850 static int WaveOutClearDoneBuffers(aout_sys_t *p_sys)
852 WAVEHDR *p_waveheader = p_sys->waveheader;
853 int i_queued_frames = 0;
855 for( int i = 0; i < FRAMES_NUM; i++ )
857 if( (p_waveheader[i].dwFlags & WHDR_DONE) &&
858 p_waveheader[i].dwUser )
861 (block_t *)(p_waveheader[i].dwUser);
862 /* Unprepare and free the buffers which has just been played */
863 waveOutUnprepareHeader( p_sys->h_waveout, &p_waveheader[i],
866 if( p_waveheader[i].dwUser != 1 )
867 block_Release( p_buffer );
869 p_waveheader[i].dwUser = 0;
872 /* Check if frame buf is available */
873 if( !(p_waveheader[i].dwFlags & WHDR_DONE) )
878 return i_queued_frames;
881 /*****************************************************************************
882 * WaveOutThread: this thread will capture play notification events.
883 *****************************************************************************
884 * We use this thread to feed new audio samples to the sound card because
885 * we are not authorized to use waveOutWrite() directly in the waveout
887 *****************************************************************************/
888 static void* WaveOutThread( void *data )
890 audio_output_t *p_aout = data;
891 aout_sys_t *p_sys = p_aout->sys;
892 block_t *p_buffer = NULL;
893 WAVEHDR *p_waveheader = p_sys->waveheader;
894 int i, i_queued_frames;
897 int canc = vlc_savecancel ();
899 /* We don't want any resampling when using S/PDIF */
900 b_sleek = p_aout->format.i_format == VLC_CODEC_SPDIFL;
902 // wait for first call to "play()"
903 while( !p_sys->start_date && !vlc_atomic_get(&p_aout->sys->abort) )
904 WaitForSingleObject( p_sys->event, INFINITE );
905 if( vlc_atomic_get(&p_aout->sys->abort) )
908 msg_Dbg( p_aout, "will start to play in %"PRId64" us",
909 (p_sys->start_date - AOUT_MAX_PTS_ADVANCE/4)-mdate());
911 // than wait a short time... before grabbing first frames
912 mwait( p_sys->start_date - AOUT_MAX_PTS_ADVANCE/4 );
914 #define waveout_warn(msg) msg_Warn( p_aout, "aout_PacketNext no buffer "\
915 "got next_date=%d ms, "\
916 "%d frames to play, %s",\
917 (int)(next_date/(mtime_t)1000), \
918 i_queued_frames, msg);
921 while( !vlc_atomic_get(&p_aout->sys->abort) )
923 /* Cleanup and find out the current latency */
924 i_queued_frames = WaveOutClearDoneBuffers( p_sys );
926 if( vlc_atomic_get(&p_aout->sys->abort) ) return NULL;
928 /* Try to fill in as many frame buffers as possible */
929 for( i = 0; i < FRAMES_NUM; i++ )
931 /* Check if frame buf is available */
932 if( p_waveheader[i].dwFlags & WHDR_DONE )
934 // next_date = mdate() + 1000000 * i_queued_frames /
935 // p_aout->format.i_rate * p_aout->i_nb_samples;
937 // the realtime has got our back-site:) to come in sync
938 if(next_date < mdate())
942 /* Take into account the latency */
943 p_buffer = aout_PacketNext( p_aout, next_date );
947 msg_Dbg( p_aout, "aout_PacketNext no buffer got "
948 "next_date=%"PRId64" ms, %d frames to play",
949 next_date/1000, i_queued_frames);
951 // means we are too early to request a new buffer?
952 waveout_warn("waiting...")
953 mwait( next_date - AOUT_MAX_PTS_ADVANCE/4 );
955 p_buffer = aout_PacketNext( p_aout, next_date );
958 if( !p_buffer && i_queued_frames )
960 /* We aren't late so no need to play a blank sample */
966 mtime_t buffer_length = p_buffer->i_length;
967 next_date = next_date + buffer_length;
970 /* Do the channel reordering */
971 if( p_buffer && p_sys->b_chan_reorder )
973 aout_ChannelReorder( p_buffer->p_buffer,
975 p_sys->waveformat.Format.nChannels,
976 p_sys->pi_chan_table,
977 p_sys->waveformat.Format.wBitsPerSample );
980 PlayWaveOut( p_aout, p_sys->h_waveout,
981 &p_waveheader[i], p_buffer, b_sleek );
987 if( vlc_atomic_get(&p_aout->sys->abort) ) return NULL;
990 deal with the case that the loop didn't fillup the buffer to the
991 max - instead of waiting that half the buffer is played before
992 fillup the waveout buffers, wait only for the next sample buffer
993 to arrive at the play method...
995 this will also avoid, that the last buffer is play until the
996 end, and then trying to get more data, so it will also
997 work - if the next buffer will arrive some ms before the
998 last buffer is finished.
1000 if(i_queued_frames < FRAMES_NUM)
1001 WaitForSingleObject( p_sys->new_buffer_event, INFINITE );
1003 WaitForSingleObject( p_sys->event, INFINITE );
1008 vlc_restorecancel (canc);
1013 static int VolumeSet( audio_output_t *aout, float volume )
1015 aout_sys_t *sys = aout->sys;
1016 const HWAVEOUT hwo = sys->h_waveout;
1017 const float full = 0xffff.fp0;
1020 if( volume >= full )
1023 sys->volume = volume;
1027 uint16_t vol = lroundf(volume);
1028 waveOutSetVolume( hwo, vol | (vol << 16) );
1032 static int MuteSet( audio_output_t * p_aout, bool mute )
1034 aout_sys_t *sys = p_aout->sys;
1035 const HWAVEOUT hwo = sys->h_waveout;
1036 uint16_t vol = mute ? 0 : lroundf(sys->volume);
1039 waveOutSetVolume( hwo, vol | (vol << 16) );
1045 reload the configuration drop down list, of the Audio Devices
1047 static int ReloadWaveoutDevices( vlc_object_t *p_this, char const *psz_name,
1048 vlc_value_t newval, vlc_value_t oldval, void *data )
1050 VLC_UNUSED( newval ); VLC_UNUSED( oldval ); VLC_UNUSED( data );
1052 module_config_t *p_item = config_FindConfig( p_this, psz_name );
1053 if( !p_item ) return VLC_SUCCESS;
1055 /* Clear-up the current list */
1056 if( p_item->i_list )
1060 /* Keep the first entry */
1061 for( i = 1; i < p_item->i_list; i++ )
1063 free((char *)(p_item->ppsz_list[i]) );
1064 free((char *)(p_item->ppsz_list_text[i]) );
1066 /* TODO: Remove when no more needed */
1067 p_item->ppsz_list[i] = NULL;
1068 p_item->ppsz_list_text[i] = NULL;
1072 int wave_devices = waveOutGetNumDevs();
1074 p_item->ppsz_list = xrealloc( p_item->ppsz_list,
1075 (wave_devices+2) * sizeof(char *) );
1076 p_item->ppsz_list_text = xrealloc( p_item->ppsz_list_text,
1077 (wave_devices+2) * sizeof(char *) );
1080 for(int i=0; i<wave_devices; i++)
1083 wchar_t dev_name[MAXPNAMELEN+32];
1085 if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
1086 != MMSYSERR_NOERROR)
1089 _snwprintf(dev_name, MAXPNAMELEN + 32, device_name_fmt,
1090 caps.szPname, caps.wMid, caps.wPid);
1091 p_item->ppsz_list[j] = FromWide( dev_name );
1092 p_item->ppsz_list_text[j] = FromWide( dev_name );
1096 p_item->ppsz_list[j] = NULL;
1097 p_item->ppsz_list_text[j] = NULL;
1103 convert devicename to device ID for output
1104 if device not found return WAVE_MAPPER, so let
1105 windows decide which preferred audio device
1108 static uint32_t findDeviceID(char *psz_device_name)
1110 if( !psz_device_name )
1113 uint32_t wave_devices = waveOutGetNumDevs();
1115 for( uint32_t i = 0; i < wave_devices; i++ )
1118 wchar_t dev_name[MAXPNAMELEN+32];
1120 if( waveOutGetDevCaps( i, &caps, sizeof(WAVEOUTCAPS) )
1121 != MMSYSERR_NOERROR )
1124 _snwprintf( dev_name, MAXPNAMELEN + 32, device_name_fmt,
1125 caps.szPname, caps.wMid, caps.wPid );
1126 char *u8 = FromWide(dev_name);
1127 if( !stricmp(u8, psz_device_name) )