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 );
294 aout_VolumeSoftInit( p_aout );
296 /* Check for hardware volume support */
297 if( waveOutGetDevCaps( (UINT_PTR)p_aout->sys->h_waveout,
298 &wocaps, sizeof(wocaps) ) == MMSYSERR_NOERROR &&
299 wocaps.dwSupport & WAVECAPS_VOLUME )
302 if( waveOutGetVolume( p_aout->sys->h_waveout, &i_dummy )
303 == MMSYSERR_NOERROR )
305 p_aout->pf_volume_set = VolumeSet;
311 waveOutReset( p_aout->sys->h_waveout );
313 /* Allocate silence buffer */
314 p_aout->sys->p_silence_buffer =
315 malloc( p_aout->sys->i_buffer_size );
316 if( p_aout->sys->p_silence_buffer == NULL )
318 aout_PacketDestroy( p_aout );
322 p_aout->sys->i_repeat_counter = 0;
325 /* Zero the buffer. WinCE doesn't have calloc(). */
326 memset( p_aout->sys->p_silence_buffer, 0,
327 p_aout->sys->i_buffer_size );
329 /* Now we need to setup our waveOut play notification structure */
330 p_aout->sys->event = CreateEvent( NULL, FALSE, FALSE, NULL );
331 p_aout->sys->new_buffer_event = CreateEvent( NULL, FALSE, FALSE, NULL );
333 /* define startpoint of playback on first call to play()
334 like alsa does (instead of playing a blank sample) */
335 p_aout->sys->b_playing = 0;
336 p_aout->sys->start_date = 0;
339 /* Then launch the notification thread */
340 vlc_atomic_set( &p_aout->sys->abort, 0);
341 if( vlc_clone( &p_aout->sys->thread,
342 WaveOutThread, p_aout, VLC_THREAD_PRIORITY_OUTPUT ) )
344 msg_Err( p_aout, "cannot create WaveOutThread" );
347 /* We need to kick off the playback in order to have the callback properly
349 for( int i = 0; i < FRAMES_NUM; i++ )
351 p_aout->sys->waveheader[i].dwFlags = WHDR_DONE;
352 p_aout->sys->waveheader[i].dwUser = 0;
358 /*****************************************************************************
359 * Probe: probe the audio device for available formats and channels
360 *****************************************************************************/
361 static void Probe( audio_output_t * p_aout )
363 vlc_value_t val, text;
364 vlc_fourcc_t i_format;
365 unsigned int i_physical_channels;
367 var_Create( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
368 text.psz_string = _("Audio Device");
369 var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
371 /* Test for 5.1 support */
372 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
373 AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
374 AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE;
375 if( p_aout->format.i_physical_channels == i_physical_channels )
377 if( OpenWaveOutPCM( p_aout,
378 p_aout->sys->i_wave_device_id,
380 i_physical_channels, 6,
381 p_aout->format.i_rate, true )
384 val.i_int = AOUT_VAR_5_1;
385 text.psz_string = (char *)_("5.1");
386 var_Change( p_aout, "audio-device",
387 VLC_VAR_ADDCHOICE, &val, &text );
388 msg_Dbg( p_aout, "device supports 5.1 channels" );
392 /* Test for 2 Front 2 Rear support */
393 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
394 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
395 if( ( p_aout->format.i_physical_channels & i_physical_channels )
396 == i_physical_channels )
398 if( OpenWaveOutPCM( p_aout,
399 p_aout->sys->i_wave_device_id,
401 i_physical_channels, 4,
402 p_aout->format.i_rate, true )
405 val.i_int = AOUT_VAR_2F2R;
406 text.psz_string = (char *)_("2 Front 2 Rear");
407 var_Change( p_aout, "audio-device",
408 VLC_VAR_ADDCHOICE, &val, &text );
409 msg_Dbg( p_aout, "device supports 4 channels" );
413 /* Test for stereo support */
414 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
415 if( OpenWaveOutPCM( p_aout,
416 p_aout->sys->i_wave_device_id,
418 i_physical_channels, 2,
419 p_aout->format.i_rate, true )
422 val.i_int = AOUT_VAR_STEREO;
423 text.psz_string = (char *)_("Stereo");
424 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
425 msg_Dbg( p_aout, "device supports 2 channels" );
428 /* Test for mono support */
429 i_physical_channels = AOUT_CHAN_CENTER;
430 if( OpenWaveOutPCM( p_aout,
431 p_aout->sys->i_wave_device_id,
433 i_physical_channels, 1,
434 p_aout->format.i_rate, true )
437 val.i_int = AOUT_VAR_MONO;
438 text.psz_string = (char *)_("Mono");
439 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
440 msg_Dbg( p_aout, "device supports 1 channel" );
443 /* Test for SPDIF support */
444 if ( AOUT_FMT_SPDIF( &p_aout->format ) )
446 if( OpenWaveOut( p_aout,
447 p_aout->sys->i_wave_device_id,
449 p_aout->format.i_physical_channels,
450 aout_FormatNbChannels( &p_aout->format ),
451 p_aout->format.i_rate, true )
454 msg_Dbg( p_aout, "device supports A/52 over S/PDIF" );
455 val.i_int = AOUT_VAR_SPDIF;
456 text.psz_string = (char *)_("A/52 over S/PDIF");
457 var_Change( p_aout, "audio-device",
458 VLC_VAR_ADDCHOICE, &val, &text );
459 if( var_InheritBool( p_aout, "spdif" ) )
460 var_Set( p_aout, "audio-device", val );
464 var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
467 /* Probe() has failed. */
468 var_Destroy( p_aout, "audio-device" );
472 var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
473 var_TriggerCallback( p_aout, "intf-change" );
476 /*****************************************************************************
477 * Play: play a sound buffer
478 *****************************************************************************
479 * This doesn't actually play the buffer. This just stores the buffer so it
480 * can be played by the callback thread.
481 *****************************************************************************/
482 static void Play( audio_output_t *_p_aout, block_t *block )
484 if( !_p_aout->sys->b_playing )
486 _p_aout->sys->b_playing = 1;
488 /* get the playing date of the first aout buffer */
489 _p_aout->sys->start_date = block->i_pts;
491 msg_Dbg( _p_aout, "Wakeup sleeping output thread.");
493 /* wake up the audio output thread */
494 SetEvent( _p_aout->sys->event );
496 SetEvent( _p_aout->sys->new_buffer_event );
499 aout_PacketPlay( _p_aout, block );
502 /*****************************************************************************
503 * Close: close the audio device
504 *****************************************************************************/
505 static void Close( vlc_object_t *p_this )
507 audio_output_t *p_aout = (audio_output_t *)p_this;
508 aout_sys_t *p_sys = p_aout->sys;
510 /* Before calling waveOutClose we must reset the device */
511 vlc_atomic_set( &p_sys->abort, 1);
513 /* wake up the audio thread, to recognize that p_aout died */
514 SetEvent( p_sys->event );
515 SetEvent( p_sys->new_buffer_event );
517 vlc_join( p_sys->thread, NULL );
520 kill the real output then - when the feed thread
521 is surely terminated!
522 old code could be too early in case that "feeding"
523 was running on termination
525 at this point now its sure, that there will be no new
526 data send to the driver, and we can cancel the last
529 MMRESULT result = waveOutReset( p_sys->h_waveout );
530 if(result != MMSYSERR_NOERROR)
532 msg_Err( p_aout, "waveOutReset failed 0x%x", result );
534 now we must wait, that all buffers are played
535 because cancel doesn't work in this case...
537 if(result == MMSYSERR_NOTSUPPORTED)
540 clear currently played (done) buffers,
541 if returnvalue > 0 (means some buffer still playing)
542 wait for the driver event callback that one buffer
543 is finished with playing, and check again
544 the timeout of 5000ms is just, an emergency exit
545 of this loop, to avoid deadlock in case of other
546 (currently not known bugs, problems, errors cases?)
549 (WaveOutClearDoneBuffers( p_sys ) > 0)
551 (WaitForSingleObject( p_sys->event, 5000) == WAIT_OBJECT_0)
554 msg_Dbg( p_aout, "Wait for waveout device...");
558 WaveOutClearDoneBuffers( p_sys );
561 /* now we can Close the device */
562 if( waveOutClose( p_sys->h_waveout ) != MMSYSERR_NOERROR )
564 msg_Err( p_aout, "waveOutClose failed" );
568 because so long, the waveout device is playing, the callback
569 could occur and need the events
571 CloseHandle( p_sys->event );
572 CloseHandle( p_sys->new_buffer_event);
574 free( p_sys->p_silence_buffer );
575 aout_PacketDestroy( p_aout );
579 /*****************************************************************************
580 * OpenWaveOut: open the waveout sound device
581 ****************************************************************************/
582 static int OpenWaveOut( audio_output_t *p_aout, uint32_t i_device_id, int i_format,
583 int i_channels, int i_nb_channels, int i_rate,
588 /* Set sound format */
590 #define waveformat p_aout->sys->waveformat
592 waveformat.dwChannelMask = 0;
593 for( unsigned i = 0; i < sizeof(pi_channels_src)/sizeof(uint32_t); i++ )
595 if( i_channels & pi_channels_src[i] )
596 waveformat.dwChannelMask |= pi_channels_in[i];
601 case VLC_CODEC_SPDIFL:
603 /* To prevent channel re-ordering */
604 waveformat.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
605 waveformat.Format.wBitsPerSample = 16;
606 waveformat.Samples.wValidBitsPerSample =
607 waveformat.Format.wBitsPerSample;
608 waveformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
609 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF;
613 waveformat.Format.wBitsPerSample = sizeof(float) * 8;
614 waveformat.Samples.wValidBitsPerSample =
615 waveformat.Format.wBitsPerSample;
616 waveformat.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
617 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
621 waveformat.Format.wBitsPerSample = 16;
622 waveformat.Samples.wValidBitsPerSample =
623 waveformat.Format.wBitsPerSample;
624 waveformat.Format.wFormatTag = WAVE_FORMAT_PCM;
625 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_PCM;
629 waveformat.Format.nChannels = i_nb_channels;
630 waveformat.Format.nSamplesPerSec = i_rate;
631 waveformat.Format.nBlockAlign =
632 waveformat.Format.wBitsPerSample / 8 * i_nb_channels;
633 waveformat.Format.nAvgBytesPerSec =
634 waveformat.Format.nSamplesPerSec * waveformat.Format.nBlockAlign;
636 /* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */
637 if( i_nb_channels <= 2 )
639 waveformat.Format.cbSize = 0;
643 waveformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
644 waveformat.Format.cbSize =
645 sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
649 msg_Dbg( p_aout, "OpenWaveDevice-ID: %u", i_device_id);
650 msg_Dbg( p_aout,"waveformat.Format.cbSize = %d",
651 waveformat.Format.cbSize);
652 msg_Dbg( p_aout,"waveformat.Format.wFormatTag = %u",
653 waveformat.Format.wFormatTag);
654 msg_Dbg( p_aout,"waveformat.Format.nChannels = %u",
655 waveformat.Format.nChannels);
656 msg_Dbg( p_aout,"waveformat.Format.nSamplesPerSec = %d",
657 (int)waveformat.Format.nSamplesPerSec);
658 msg_Dbg( p_aout,"waveformat.Format.nAvgBytesPerSec = %u",
659 (int)waveformat.Format.nAvgBytesPerSec);
660 msg_Dbg( p_aout,"waveformat.Format.nBlockAlign = %d",
661 waveformat.Format.nBlockAlign);
662 msg_Dbg( p_aout,"waveformat.Format.wBitsPerSample = %d",
663 waveformat.Format.wBitsPerSample);
664 msg_Dbg( p_aout,"waveformat.Samples.wValidBitsPerSample = %d",
665 waveformat.Samples.wValidBitsPerSample);
666 msg_Dbg( p_aout,"waveformat.Samples.wSamplesPerBlock = %d",
667 waveformat.Samples.wSamplesPerBlock);
668 msg_Dbg( p_aout,"waveformat.dwChannelMask = %lu",
669 waveformat.dwChannelMask);
672 /* Open the device */
673 result = waveOutOpen( &p_aout->sys->h_waveout, i_device_id,
674 (WAVEFORMATEX *)&waveformat,
675 (DWORD_PTR)WaveOutCallback, (DWORD_PTR)p_aout,
676 CALLBACK_FUNCTION | (b_probe?WAVE_FORMAT_QUERY:0) );
677 if( result == WAVERR_BADFORMAT )
679 msg_Warn( p_aout, "waveOutOpen failed WAVERR_BADFORMAT" );
682 if( result == MMSYSERR_ALLOCATED )
684 msg_Warn( p_aout, "waveOutOpen failed WAVERR_ALLOCATED" );
687 if( result != MMSYSERR_NOERROR )
689 msg_Warn( p_aout, "waveOutOpen failed" );
693 p_aout->sys->b_chan_reorder =
694 aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
695 waveformat.dwChannelMask, i_nb_channels,
696 p_aout->sys->pi_chan_table );
698 if( p_aout->sys->b_chan_reorder )
700 msg_Dbg( p_aout, "channel reordering needed" );
709 /*****************************************************************************
710 * OpenWaveOutPCM: open a PCM waveout sound device
711 ****************************************************************************/
712 static int OpenWaveOutPCM( audio_output_t *p_aout, uint32_t i_device_id,
713 vlc_fourcc_t *i_format,
714 int i_channels, int i_nb_channels, int i_rate,
717 bool b_use_float32 = var_CreateGetBool( p_aout, "waveout-float32");
719 if( !b_use_float32 || OpenWaveOut( p_aout, i_device_id, VLC_CODEC_FL32,
720 i_channels, i_nb_channels, i_rate, b_probe )
723 if ( OpenWaveOut( p_aout, i_device_id, VLC_CODEC_S16L,
724 i_channels, i_nb_channels, i_rate, b_probe )
731 *i_format = VLC_CODEC_S16L;
737 *i_format = VLC_CODEC_FL32;
742 /*****************************************************************************
743 * PlayWaveOut: play a buffer through the WaveOut device
744 *****************************************************************************/
745 static int PlayWaveOut( audio_output_t *p_aout, HWAVEOUT h_waveout,
746 WAVEHDR *p_waveheader, aout_buffer_t *p_buffer,
751 /* Prepare the buffer */
752 if( p_buffer != NULL )
754 p_waveheader->lpData = (LPSTR)p_buffer->p_buffer;
756 copy the buffer to the silence buffer :) so in case we don't
757 get the next buffer fast enough (I will repeat this one a time
758 for AC3 / DTS and SPDIF this will sound better instead of
763 vlc_memcpy( p_aout->sys->p_silence_buffer,
765 p_aout->sys->i_buffer_size );
766 p_aout->sys->i_repeat_counter = 2;
769 /* Use silence buffer instead */
770 if(p_aout->sys->i_repeat_counter)
772 p_aout->sys->i_repeat_counter--;
773 if(!p_aout->sys->i_repeat_counter)
775 vlc_memset( p_aout->sys->p_silence_buffer,
776 0x00, p_aout->sys->i_buffer_size );
779 p_waveheader->lpData = (LPSTR)p_aout->sys->p_silence_buffer;
782 p_waveheader->dwUser = p_buffer ? (DWORD_PTR)p_buffer : (DWORD_PTR)1;
783 p_waveheader->dwBufferLength = p_aout->sys->i_buffer_size;
784 p_waveheader->dwFlags = 0;
786 result = waveOutPrepareHeader( h_waveout, p_waveheader, sizeof(WAVEHDR) );
787 if( result != MMSYSERR_NOERROR )
789 msg_Err( p_aout, "waveOutPrepareHeader failed" );
793 /* Send the buffer to the waveOut queue */
794 result = waveOutWrite( h_waveout, p_waveheader, sizeof(WAVEHDR) );
795 if( result != MMSYSERR_NOERROR )
797 msg_Err( p_aout, "waveOutWrite failed" );
804 /*****************************************************************************
805 * WaveOutCallback: what to do once WaveOut has played its sound samples
806 *****************************************************************************/
807 static void CALLBACK WaveOutCallback( HWAVEOUT h_waveout, UINT uMsg,
809 DWORD_PTR dwParam1, DWORD_PTR dwParam2 )
811 (void)h_waveout; (void)dwParam1; (void)dwParam2;
812 audio_output_t *p_aout = (audio_output_t *)_p_aout;
813 int i_queued_frames = 0;
815 if( uMsg != WOM_DONE ) return;
817 if( vlc_atomic_get(&p_aout->sys->abort) ) return;
819 /* Find out the current latency */
820 for( int i = 0; i < FRAMES_NUM; i++ )
822 /* Check if frame buf is available */
823 if( !(p_aout->sys->waveheader[i].dwFlags & WHDR_DONE) )
829 /* Don't wake up the thread too much */
830 if( i_queued_frames <= FRAMES_NUM/2 )
831 SetEvent( p_aout->sys->event );
835 /****************************************************************************
836 * WaveOutClearDoneBuffers: Clear all done marked buffers, and free aout_bufer
837 ****************************************************************************
838 * return value is the number of still playing buffers in the queue
839 ****************************************************************************/
840 static int WaveOutClearDoneBuffers(aout_sys_t *p_sys)
842 WAVEHDR *p_waveheader = p_sys->waveheader;
843 int i_queued_frames = 0;
845 for( int i = 0; i < FRAMES_NUM; i++ )
847 if( (p_waveheader[i].dwFlags & WHDR_DONE) &&
848 p_waveheader[i].dwUser )
850 aout_buffer_t *p_buffer =
851 (aout_buffer_t *)(p_waveheader[i].dwUser);
852 /* Unprepare and free the buffers which has just been played */
853 waveOutUnprepareHeader( p_sys->h_waveout, &p_waveheader[i],
856 if( p_waveheader[i].dwUser != 1 )
857 aout_BufferFree( p_buffer );
859 p_waveheader[i].dwUser = 0;
862 /* Check if frame buf is available */
863 if( !(p_waveheader[i].dwFlags & WHDR_DONE) )
868 return i_queued_frames;
871 /*****************************************************************************
872 * WaveOutThread: this thread will capture play notification events.
873 *****************************************************************************
874 * We use this thread to feed new audio samples to the sound card because
875 * we are not authorized to use waveOutWrite() directly in the waveout
877 *****************************************************************************/
878 static void* WaveOutThread( void *data )
880 audio_output_t *p_aout = data;
881 aout_sys_t *p_sys = p_aout->sys;
882 aout_buffer_t *p_buffer = NULL;
883 WAVEHDR *p_waveheader = p_sys->waveheader;
884 int i, i_queued_frames;
887 int canc = vlc_savecancel ();
889 /* We don't want any resampling when using S/PDIF */
890 b_sleek = p_aout->format.i_format == VLC_CODEC_SPDIFL;
892 // wait for first call to "play()"
893 while( !p_sys->start_date && !vlc_atomic_get(&p_aout->sys->abort) )
894 WaitForSingleObject( p_sys->event, INFINITE );
895 if( vlc_atomic_get(&p_aout->sys->abort) )
898 msg_Dbg( p_aout, "will start to play in %"PRId64" us",
899 (p_sys->start_date - AOUT_MAX_PTS_ADVANCE/4)-mdate());
901 // than wait a short time... before grabbing first frames
902 mwait( p_sys->start_date - AOUT_MAX_PTS_ADVANCE/4 );
904 #define waveout_warn(msg) msg_Warn( p_aout, "aout_PacketNext no buffer "\
905 "got next_date=%d ms, "\
906 "%d frames to play, %s",\
907 (int)(next_date/(mtime_t)1000), \
908 i_queued_frames, msg);
911 while( !vlc_atomic_get(&p_aout->sys->abort) )
913 /* Cleanup and find out the current latency */
914 i_queued_frames = WaveOutClearDoneBuffers( p_sys );
916 if( vlc_atomic_get(&p_aout->sys->abort) ) return NULL;
918 /* Try to fill in as many frame buffers as possible */
919 for( i = 0; i < FRAMES_NUM; i++ )
921 /* Check if frame buf is available */
922 if( p_waveheader[i].dwFlags & WHDR_DONE )
924 // next_date = mdate() + 1000000 * i_queued_frames /
925 // p_aout->format.i_rate * p_aout->i_nb_samples;
927 // the realtime has got our back-site:) to come in sync
928 if(next_date < mdate())
932 /* Take into account the latency */
933 p_buffer = aout_PacketNext( p_aout, next_date );
937 msg_Dbg( p_aout, "aout_PacketNext no buffer got "
938 "next_date=%"PRId64" ms, %d frames to play",
939 next_date/1000, i_queued_frames);
941 // means we are too early to request a new buffer?
942 waveout_warn("waiting...")
943 mwait( next_date - AOUT_MAX_PTS_ADVANCE/4 );
945 p_buffer = aout_PacketNext( p_aout, next_date );
948 if( !p_buffer && i_queued_frames )
950 /* We aren't late so no need to play a blank sample */
956 mtime_t buffer_length = p_buffer->i_length;
957 next_date = next_date + buffer_length;
960 /* Do the channel reordering */
961 if( p_buffer && p_sys->b_chan_reorder )
963 aout_ChannelReorder( p_buffer->p_buffer,
965 p_sys->waveformat.Format.nChannels,
966 p_sys->pi_chan_table,
967 p_sys->waveformat.Format.wBitsPerSample );
970 PlayWaveOut( p_aout, p_sys->h_waveout,
971 &p_waveheader[i], p_buffer, b_sleek );
977 if( vlc_atomic_get(&p_aout->sys->abort) ) return NULL;
980 deal with the case that the loop didn't fillup the buffer to the
981 max - instead of waiting that half the buffer is played before
982 fillup the waveout buffers, wait only for the next sample buffer
983 to arrive at the play method...
985 this will also avoid, that the last buffer is play until the
986 end, and then trying to get more data, so it will also
987 work - if the next buffer will arrive some ms before the
988 last buffer is finished.
990 if(i_queued_frames < FRAMES_NUM)
991 WaitForSingleObject( p_sys->new_buffer_event, INFINITE );
993 WaitForSingleObject( p_sys->event, INFINITE );
998 vlc_restorecancel (canc);
1002 static int VolumeSet( audio_output_t * p_aout, float volume, bool mute )
1007 unsigned long i_waveout_vol = volume
1008 * (0xFFFF * AOUT_VOLUME_DEFAULT / AOUT_VOLUME_MAX);
1010 if( i_waveout_vol <= 0xFFFF )
1011 i_waveout_vol |= i_waveout_vol << 16;
1013 i_waveout_vol = 0xFFFFFFFF;
1016 waveOutSetVolume( 0, i_waveout_vol );
1018 waveOutSetVolume( p_aout->sys->h_waveout, i_waveout_vol );
1025 reload the configuration drop down list, of the Audio Devices
1027 static int ReloadWaveoutDevices( vlc_object_t *p_this, char const *psz_name,
1028 vlc_value_t newval, vlc_value_t oldval, void *data )
1030 VLC_UNUSED( newval ); VLC_UNUSED( oldval ); VLC_UNUSED( data );
1032 module_config_t *p_item = config_FindConfig( p_this, psz_name );
1033 if( !p_item ) return VLC_SUCCESS;
1035 /* Clear-up the current list */
1036 if( p_item->i_list )
1040 /* Keep the first entry */
1041 for( i = 1; i < p_item->i_list; i++ )
1043 free((char *)(p_item->ppsz_list[i]) );
1044 free((char *)(p_item->ppsz_list_text[i]) );
1046 /* TODO: Remove when no more needed */
1047 p_item->ppsz_list[i] = NULL;
1048 p_item->ppsz_list_text[i] = NULL;
1052 int wave_devices = waveOutGetNumDevs();
1054 p_item->ppsz_list = xrealloc( p_item->ppsz_list,
1055 (wave_devices+2) * sizeof(char *) );
1056 p_item->ppsz_list_text = xrealloc( p_item->ppsz_list_text,
1057 (wave_devices+2) * sizeof(char *) );
1060 for(int i=0; i<wave_devices; i++)
1063 wchar_t dev_name[MAXPNAMELEN+32];
1065 if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
1066 != MMSYSERR_NOERROR)
1069 _snwprintf(dev_name, MAXPNAMELEN + 32, device_name_fmt,
1070 caps.szPname, caps.wMid, caps.wPid);
1071 p_item->ppsz_list[j] = FromWide( dev_name );
1072 p_item->ppsz_list_text[j] = FromWide( dev_name );
1076 p_item->ppsz_list[j] = NULL;
1077 p_item->ppsz_list_text[j] = NULL;
1083 convert devicename to device ID for output
1084 if device not found return WAVE_MAPPER, so let
1085 windows decide which preferred audio device
1088 static uint32_t findDeviceID(char *psz_device_name)
1090 if( !psz_device_name )
1093 uint32_t wave_devices = waveOutGetNumDevs();
1095 for( uint32_t i = 0; i < wave_devices; i++ )
1098 wchar_t dev_name[MAXPNAMELEN+32];
1100 if( waveOutGetDevCaps( i, &caps, sizeof(WAVEOUTCAPS) )
1101 != MMSYSERR_NOERROR )
1104 _snwprintf( dev_name, MAXPNAMELEN + 32, device_name_fmt,
1105 caps.szPname, caps.wMid, caps.wPid );
1106 char *u8 = FromWide(dev_name);
1107 if( !stricmp(u8, psz_device_name) )