1 /*****************************************************************************
2 * waveout.c : Windows waveOut plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2001-2009 the VideoLAN team
7 * Authors: Gildas Bazin <gbazin@videolan.org>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
36 #include <vlc_aout_intf.h>
37 #include <vlc_charset.h> /* FromLocaleDup, LocaleFree */
38 #include <vlc_atomic.h>
40 #include "windows_audio_common.h"
42 #define FRAME_SIZE 4096 /* The size is in samples, not in bytes */
44 /*****************************************************************************
46 *****************************************************************************/
47 static int Open ( vlc_object_t * );
48 static void Close ( vlc_object_t * );
49 static void Play ( audio_output_t *, block_t * );
51 /*****************************************************************************
52 * notification_thread_t: waveOut event thread
53 *****************************************************************************/
55 static void Probe ( audio_output_t * );
56 static int OpenWaveOut ( audio_output_t *, uint32_t,
57 int, int, int, int, bool );
58 static int OpenWaveOutPCM( audio_output_t *, uint32_t,
59 vlc_fourcc_t*, int, int, int, bool );
60 static int PlayWaveOut ( audio_output_t *, HWAVEOUT, WAVEHDR *,
61 aout_buffer_t *, bool );
63 static void CALLBACK WaveOutCallback ( HWAVEOUT, UINT, DWORD_PTR, DWORD_PTR, DWORD_PTR );
64 static void* WaveOutThread( void * );
66 static int VolumeSet( audio_output_t *, float, bool );
68 static int WaveOutClearDoneBuffers(aout_sys_t *p_sys);
70 static int ReloadWaveoutDevices( vlc_object_t *, char const *,
71 vlc_value_t, vlc_value_t, void * );
72 static uint32_t findDeviceID(char *);
74 static const char psz_device_name_fmt[] = "%s ($%x,$%x)";
76 static const char *const ppsz_adev[] = { "wavemapper", };
77 static const char *const ppsz_adev_text[] = { N_("Microsoft Soundmapper") };
80 /*****************************************************************************
82 *****************************************************************************/
83 #define DEVICE_TEXT N_("Select Audio Device")
84 #define DEVICE_LONG N_("Select special Audio device, or let windows "\
85 "decide (default), change needs VLC restart "\
87 #define DEFAULT_AUDIO_DEVICE N_("Default Audio Device")
90 set_shortname( "WaveOut" )
91 set_description( N_("Win32 waveOut extension output") )
92 set_capability( "audio output", 50 )
93 set_category( CAT_AUDIO )
94 set_subcategory( SUBCAT_AUDIO_AOUT )
96 add_string( "waveout-audio-device", "wavemapper",
97 DEVICE_TEXT, DEVICE_LONG, false )
98 change_string_list( ppsz_adev, ppsz_adev_text, ReloadWaveoutDevices )
99 change_action_add( ReloadWaveoutDevices, N_("Refresh list") )
101 add_bool( "waveout-float32", true, FLOAT_TEXT, FLOAT_LONGTEXT, true )
103 set_callbacks( Open, Close )
106 /*****************************************************************************
107 * aout_sys_t: waveOut audio output method descriptor
108 *****************************************************************************
109 * This structure is part of the audio output thread descriptor.
110 * It describes the waveOut specific properties of an audio device.
111 *****************************************************************************/
114 aout_packet_t packet;
115 uint32_t i_wave_device_id; /* ID of selected output device */
117 HWAVEOUT h_waveout; /* handle to waveout instance */
119 WAVEFORMATEXTENSIBLE waveformat; /* audio format */
121 WAVEHDR waveheader[FRAMES_NUM];
126 HANDLE new_buffer_event;
128 // rental from alsa.c to synchronize startup of audiothread
129 int b_playing; /* playing status */
132 int i_repeat_counter;
136 uint8_t *p_silence_buffer; /* buffer we use to play silence */
138 bool b_chan_reorder; /* do we need channel reordering */
139 int pi_chan_table[AOUT_CHAN_MAX];
142 /*****************************************************************************
143 * Open: open the audio device
144 *****************************************************************************
145 * This function opens and setups Win32 waveOut
146 *****************************************************************************/
147 static int Open( vlc_object_t *p_this )
149 audio_output_t *p_aout = (audio_output_t *)p_this;
152 /* Allocate structure */
153 p_aout->sys = malloc( sizeof( aout_sys_t ) );
155 if( p_aout->sys == NULL )
158 p_aout->pf_play = Play;
159 p_aout->pf_pause = aout_PacketPause;
160 p_aout->pf_flush = aout_PacketFlush;
163 initialize/update Device selection List
165 ReloadWaveoutDevices( p_this, "waveout-audio-device", val, val, NULL);
169 check for configured audio device!
171 char *psz_waveout_dev = var_CreateGetString( p_aout, "waveout-audio-device");
173 p_aout->sys->i_wave_device_id =
174 findDeviceID( psz_waveout_dev );
176 if(p_aout->sys->i_wave_device_id == WAVE_MAPPER)
178 if(psz_waveout_dev &&
179 stricmp(psz_waveout_dev,"wavemapper"))
181 msg_Warn( p_aout, "configured audio device '%s' not available, "\
182 "use default instead", psz_waveout_dev );
185 free( psz_waveout_dev );
188 WAVEOUTCAPS waveoutcaps;
189 if(waveOutGetDevCaps( p_aout->sys->i_wave_device_id,
191 sizeof(WAVEOUTCAPS)) == MMSYSERR_NOERROR)
193 /* log debug some infos about driver, to know who to blame
194 if it doesn't work */
195 msg_Dbg( p_aout, "Drivername: %s", waveoutcaps.szPname);
196 msg_Dbg( p_aout, "Driver Version: %d.%d",
197 (waveoutcaps.vDriverVersion>>8)&255,
198 waveoutcaps.vDriverVersion & 255);
199 msg_Dbg( p_aout, "Manufacturer identifier: 0x%x", waveoutcaps.wMid );
200 msg_Dbg( p_aout, "Product identifier: 0x%x", waveoutcaps.wPid );
205 if( var_Type( p_aout, "audio-device" ) == 0 )
210 if( var_Get( p_aout, "audio-device", &val ) < 0 )
212 /* Probe() has failed. */
213 var_Destroy( p_aout, "waveout-audio-device");
219 /* Open the device */
220 if( val.i_int == AOUT_VAR_SPDIF )
222 p_aout->format.i_format = VLC_CODEC_SPDIFL;
224 if( OpenWaveOut( p_aout,
225 p_aout->sys->i_wave_device_id,
227 p_aout->format.i_physical_channels,
228 aout_FormatNbChannels( &p_aout->format ),
229 p_aout->format.i_rate, false )
232 msg_Err( p_aout, "cannot open waveout audio device" );
237 /* Calculate the frame size in bytes */
238 p_aout->format.i_bytes_per_frame = AOUT_SPDIF_SIZE;
239 p_aout->format.i_frame_length = A52_FRAME_NB;
240 p_aout->sys->i_buffer_size =
241 p_aout->format.i_bytes_per_frame;
243 aout_PacketInit( p_aout, &p_aout->sys->packet, A52_FRAME_NB );
244 aout_VolumeNoneInit( p_aout );
253 p_aout->format.i_physical_channels
254 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
255 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
259 p_aout->format.i_physical_channels
260 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
261 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
264 p_aout->format.i_physical_channels = AOUT_CHAN_CENTER;
267 p_aout->format.i_physical_channels
268 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
271 if( OpenWaveOutPCM( p_aout,
272 p_aout->sys->i_wave_device_id,
273 &p_aout->format.i_format,
274 p_aout->format.i_physical_channels,
275 aout_FormatNbChannels( &p_aout->format ),
276 p_aout->format.i_rate, false )
279 msg_Err( p_aout, "cannot open waveout audio device" );
284 /* Calculate the frame size in bytes */
285 aout_FormatPrepare( &p_aout->format );
286 p_aout->sys->i_buffer_size = FRAME_SIZE *
287 p_aout->format.i_bytes_per_frame;
289 aout_PacketInit( p_aout, &p_aout->sys->packet, FRAME_SIZE );
290 aout_VolumeSoftInit( p_aout );
292 /* Check for hardware volume support */
293 if( waveOutGetDevCaps( (UINT_PTR)p_aout->sys->h_waveout,
294 &wocaps, sizeof(wocaps) ) == MMSYSERR_NOERROR &&
295 wocaps.dwSupport & WAVECAPS_VOLUME )
298 if( waveOutGetVolume( p_aout->sys->h_waveout, &i_dummy )
299 == MMSYSERR_NOERROR )
301 p_aout->pf_volume_set = VolumeSet;
307 waveOutReset( p_aout->sys->h_waveout );
309 /* Allocate silence buffer */
310 p_aout->sys->p_silence_buffer =
311 malloc( p_aout->sys->i_buffer_size );
312 if( p_aout->sys->p_silence_buffer == NULL )
314 aout_PacketDestroy( p_aout );
318 p_aout->sys->i_repeat_counter = 0;
321 /* Zero the buffer. WinCE doesn't have calloc(). */
322 memset( p_aout->sys->p_silence_buffer, 0,
323 p_aout->sys->i_buffer_size );
325 /* Now we need to setup our waveOut play notification structure */
326 p_aout->sys->event = CreateEvent( NULL, FALSE, FALSE, NULL );
327 p_aout->sys->new_buffer_event = CreateEvent( NULL, FALSE, FALSE, NULL );
329 /* define startpoint of playback on first call to play()
330 like alsa does (instead of playing a blank sample) */
331 p_aout->sys->b_playing = 0;
332 p_aout->sys->start_date = 0;
335 /* Then launch the notification thread */
336 vlc_atomic_set( &p_aout->sys->abort, 0);
337 if( vlc_clone( &p_aout->sys->thread,
338 WaveOutThread, p_aout, VLC_THREAD_PRIORITY_OUTPUT ) )
340 msg_Err( p_aout, "cannot create WaveOutThread" );
343 /* We need to kick off the playback in order to have the callback properly
345 for( int i = 0; i < FRAMES_NUM; i++ )
347 p_aout->sys->waveheader[i].dwFlags = WHDR_DONE;
348 p_aout->sys->waveheader[i].dwUser = 0;
354 /*****************************************************************************
355 * Probe: probe the audio device for available formats and channels
356 *****************************************************************************/
357 static void Probe( audio_output_t * p_aout )
359 vlc_value_t val, text;
360 vlc_fourcc_t i_format;
361 unsigned int i_physical_channels;
363 var_Create( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
364 text.psz_string = _("Audio Device");
365 var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
367 /* Test for 5.1 support */
368 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
369 AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
370 AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE;
371 if( p_aout->format.i_physical_channels == i_physical_channels )
373 if( OpenWaveOutPCM( p_aout,
374 p_aout->sys->i_wave_device_id,
376 i_physical_channels, 6,
377 p_aout->format.i_rate, true )
380 val.i_int = AOUT_VAR_5_1;
381 text.psz_string = (char *)_("5.1");
382 var_Change( p_aout, "audio-device",
383 VLC_VAR_ADDCHOICE, &val, &text );
384 msg_Dbg( p_aout, "device supports 5.1 channels" );
388 /* Test for 2 Front 2 Rear support */
389 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
390 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
391 if( ( p_aout->format.i_physical_channels & i_physical_channels )
392 == i_physical_channels )
394 if( OpenWaveOutPCM( p_aout,
395 p_aout->sys->i_wave_device_id,
397 i_physical_channels, 4,
398 p_aout->format.i_rate, true )
401 val.i_int = AOUT_VAR_2F2R;
402 text.psz_string = (char *)_("2 Front 2 Rear");
403 var_Change( p_aout, "audio-device",
404 VLC_VAR_ADDCHOICE, &val, &text );
405 msg_Dbg( p_aout, "device supports 4 channels" );
409 /* Test for stereo support */
410 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
411 if( OpenWaveOutPCM( p_aout,
412 p_aout->sys->i_wave_device_id,
414 i_physical_channels, 2,
415 p_aout->format.i_rate, true )
418 val.i_int = AOUT_VAR_STEREO;
419 text.psz_string = (char *)_("Stereo");
420 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
421 msg_Dbg( p_aout, "device supports 2 channels" );
424 /* Test for mono support */
425 i_physical_channels = AOUT_CHAN_CENTER;
426 if( OpenWaveOutPCM( p_aout,
427 p_aout->sys->i_wave_device_id,
429 i_physical_channels, 1,
430 p_aout->format.i_rate, true )
433 val.i_int = AOUT_VAR_MONO;
434 text.psz_string = (char *)_("Mono");
435 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
436 msg_Dbg( p_aout, "device supports 1 channel" );
439 /* Test for SPDIF support */
440 if ( AOUT_FMT_SPDIF( &p_aout->format ) )
442 if( OpenWaveOut( p_aout,
443 p_aout->sys->i_wave_device_id,
445 p_aout->format.i_physical_channels,
446 aout_FormatNbChannels( &p_aout->format ),
447 p_aout->format.i_rate, true )
450 msg_Dbg( p_aout, "device supports A/52 over S/PDIF" );
451 val.i_int = AOUT_VAR_SPDIF;
452 text.psz_string = (char *)_("A/52 over S/PDIF");
453 var_Change( p_aout, "audio-device",
454 VLC_VAR_ADDCHOICE, &val, &text );
455 if( var_InheritBool( p_aout, "spdif" ) )
456 var_Set( p_aout, "audio-device", val );
460 var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
463 /* Probe() has failed. */
464 var_Destroy( p_aout, "audio-device" );
468 var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
469 var_TriggerCallback( p_aout, "intf-change" );
472 /*****************************************************************************
473 * Play: play a sound buffer
474 *****************************************************************************
475 * This doesn't actually play the buffer. This just stores the buffer so it
476 * can be played by the callback thread.
477 *****************************************************************************/
478 static void Play( audio_output_t *_p_aout, block_t *block )
480 if( !_p_aout->sys->b_playing )
482 _p_aout->sys->b_playing = 1;
484 /* get the playing date of the first aout buffer */
485 _p_aout->sys->start_date = block->i_pts;
487 msg_Dbg( _p_aout, "Wakeup sleeping output thread.");
489 /* wake up the audio output thread */
490 SetEvent( _p_aout->sys->event );
492 SetEvent( _p_aout->sys->new_buffer_event );
495 aout_PacketPlay( _p_aout, block );
498 /*****************************************************************************
499 * Close: close the audio device
500 *****************************************************************************/
501 static void Close( vlc_object_t *p_this )
503 audio_output_t *p_aout = (audio_output_t *)p_this;
504 aout_sys_t *p_sys = p_aout->sys;
506 /* Before calling waveOutClose we must reset the device */
507 vlc_atomic_set( &p_sys->abort, 1);
509 /* wake up the audio thread, to recognize that p_aout died */
510 SetEvent( p_sys->event );
511 SetEvent( p_sys->new_buffer_event );
513 vlc_join( p_sys->thread, NULL );
516 kill the real output then - when the feed thread
517 is surely terminated!
518 old code could be too early in case that "feeding"
519 was running on termination
521 at this point now its sure, that there will be no new
522 data send to the driver, and we can cancel the last
525 MMRESULT result = waveOutReset( p_sys->h_waveout );
526 if(result != MMSYSERR_NOERROR)
528 msg_Err( p_aout, "waveOutReset failed 0x%x", result );
530 now we must wait, that all buffers are played
531 because cancel doesn't work in this case...
533 if(result == MMSYSERR_NOTSUPPORTED)
536 clear currently played (done) buffers,
537 if returnvalue > 0 (means some buffer still playing)
538 wait for the driver event callback that one buffer
539 is finished with playing, and check again
540 the timeout of 5000ms is just, an emergency exit
541 of this loop, to avoid deadlock in case of other
542 (currently not known bugs, problems, errors cases?)
545 (WaveOutClearDoneBuffers( p_sys ) > 0)
547 (WaitForSingleObject( p_sys->event, 5000) == WAIT_OBJECT_0)
550 msg_Dbg( p_aout, "Wait for waveout device...");
554 WaveOutClearDoneBuffers( p_sys );
557 /* now we can Close the device */
558 if( waveOutClose( p_sys->h_waveout ) != MMSYSERR_NOERROR )
560 msg_Err( p_aout, "waveOutClose failed" );
564 because so long, the waveout device is playing, the callback
565 could occur and need the events
567 CloseHandle( p_sys->event );
568 CloseHandle( p_sys->new_buffer_event);
570 free( p_sys->p_silence_buffer );
571 aout_PacketDestroy( p_aout );
575 /*****************************************************************************
576 * OpenWaveOut: open the waveout sound device
577 ****************************************************************************/
578 static int OpenWaveOut( audio_output_t *p_aout, uint32_t i_device_id, int i_format,
579 int i_channels, int i_nb_channels, int i_rate,
584 /* Set sound format */
586 #define waveformat p_aout->sys->waveformat
588 waveformat.dwChannelMask = 0;
589 for( unsigned i = 0; i < sizeof(pi_channels_src)/sizeof(uint32_t); i++ )
591 if( i_channels & pi_channels_src[i] )
592 waveformat.dwChannelMask |= pi_channels_in[i];
597 case VLC_CODEC_SPDIFL:
599 /* To prevent channel re-ordering */
600 waveformat.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
601 waveformat.Format.wBitsPerSample = 16;
602 waveformat.Samples.wValidBitsPerSample =
603 waveformat.Format.wBitsPerSample;
604 waveformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
605 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF;
609 waveformat.Format.wBitsPerSample = sizeof(float) * 8;
610 waveformat.Samples.wValidBitsPerSample =
611 waveformat.Format.wBitsPerSample;
612 waveformat.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
613 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
617 waveformat.Format.wBitsPerSample = 16;
618 waveformat.Samples.wValidBitsPerSample =
619 waveformat.Format.wBitsPerSample;
620 waveformat.Format.wFormatTag = WAVE_FORMAT_PCM;
621 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_PCM;
625 waveformat.Format.nChannels = i_nb_channels;
626 waveformat.Format.nSamplesPerSec = i_rate;
627 waveformat.Format.nBlockAlign =
628 waveformat.Format.wBitsPerSample / 8 * i_nb_channels;
629 waveformat.Format.nAvgBytesPerSec =
630 waveformat.Format.nSamplesPerSec * waveformat.Format.nBlockAlign;
632 /* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */
633 if( i_nb_channels <= 2 )
635 waveformat.Format.cbSize = 0;
639 waveformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
640 waveformat.Format.cbSize =
641 sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
645 msg_Dbg( p_aout, "OpenWaveDevice-ID: %u", i_device_id);
646 msg_Dbg( p_aout,"waveformat.Format.cbSize = %d",
647 waveformat.Format.cbSize);
648 msg_Dbg( p_aout,"waveformat.Format.wFormatTag = %u",
649 waveformat.Format.wFormatTag);
650 msg_Dbg( p_aout,"waveformat.Format.nChannels = %u",
651 waveformat.Format.nChannels);
652 msg_Dbg( p_aout,"waveformat.Format.nSamplesPerSec = %d",
653 (int)waveformat.Format.nSamplesPerSec);
654 msg_Dbg( p_aout,"waveformat.Format.nAvgBytesPerSec = %u",
655 (int)waveformat.Format.nAvgBytesPerSec);
656 msg_Dbg( p_aout,"waveformat.Format.nBlockAlign = %d",
657 waveformat.Format.nBlockAlign);
658 msg_Dbg( p_aout,"waveformat.Format.wBitsPerSample = %d",
659 waveformat.Format.wBitsPerSample);
660 msg_Dbg( p_aout,"waveformat.Samples.wValidBitsPerSample = %d",
661 waveformat.Samples.wValidBitsPerSample);
662 msg_Dbg( p_aout,"waveformat.Samples.wSamplesPerBlock = %d",
663 waveformat.Samples.wSamplesPerBlock);
664 msg_Dbg( p_aout,"waveformat.dwChannelMask = %lu",
665 waveformat.dwChannelMask);
668 /* Open the device */
669 result = waveOutOpen( &p_aout->sys->h_waveout, i_device_id,
670 (WAVEFORMATEX *)&waveformat,
671 (DWORD_PTR)WaveOutCallback, (DWORD_PTR)p_aout,
672 CALLBACK_FUNCTION | (b_probe?WAVE_FORMAT_QUERY:0) );
673 if( result == WAVERR_BADFORMAT )
675 msg_Warn( p_aout, "waveOutOpen failed WAVERR_BADFORMAT" );
678 if( result == MMSYSERR_ALLOCATED )
680 msg_Warn( p_aout, "waveOutOpen failed WAVERR_ALLOCATED" );
683 if( result != MMSYSERR_NOERROR )
685 msg_Warn( p_aout, "waveOutOpen failed" );
689 p_aout->sys->b_chan_reorder =
690 aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
691 waveformat.dwChannelMask, i_nb_channels,
692 p_aout->sys->pi_chan_table );
694 if( p_aout->sys->b_chan_reorder )
696 msg_Dbg( p_aout, "channel reordering needed" );
705 /*****************************************************************************
706 * OpenWaveOutPCM: open a PCM waveout sound device
707 ****************************************************************************/
708 static int OpenWaveOutPCM( audio_output_t *p_aout, uint32_t i_device_id,
709 vlc_fourcc_t *i_format,
710 int i_channels, int i_nb_channels, int i_rate,
713 bool b_use_float32 = var_CreateGetBool( p_aout, "waveout-float32");
715 if( !b_use_float32 || OpenWaveOut( p_aout, i_device_id, VLC_CODEC_FL32,
716 i_channels, i_nb_channels, i_rate, b_probe )
719 if ( OpenWaveOut( p_aout, i_device_id, VLC_CODEC_S16L,
720 i_channels, i_nb_channels, i_rate, b_probe )
727 *i_format = VLC_CODEC_S16L;
733 *i_format = VLC_CODEC_FL32;
738 /*****************************************************************************
739 * PlayWaveOut: play a buffer through the WaveOut device
740 *****************************************************************************/
741 static int PlayWaveOut( audio_output_t *p_aout, HWAVEOUT h_waveout,
742 WAVEHDR *p_waveheader, aout_buffer_t *p_buffer,
747 /* Prepare the buffer */
748 if( p_buffer != NULL )
750 p_waveheader->lpData = (LPSTR)p_buffer->p_buffer;
752 copy the buffer to the silence buffer :) so in case we don't
753 get the next buffer fast enough (I will repeat this one a time
754 for AC3 / DTS and SPDIF this will sound better instead of
759 vlc_memcpy( p_aout->sys->p_silence_buffer,
761 p_aout->sys->i_buffer_size );
762 p_aout->sys->i_repeat_counter = 2;
765 /* Use silence buffer instead */
766 if(p_aout->sys->i_repeat_counter)
768 p_aout->sys->i_repeat_counter--;
769 if(!p_aout->sys->i_repeat_counter)
771 vlc_memset( p_aout->sys->p_silence_buffer,
772 0x00, p_aout->sys->i_buffer_size );
775 p_waveheader->lpData = (LPSTR)p_aout->sys->p_silence_buffer;
778 p_waveheader->dwUser = p_buffer ? (DWORD_PTR)p_buffer : (DWORD_PTR)1;
779 p_waveheader->dwBufferLength = p_aout->sys->i_buffer_size;
780 p_waveheader->dwFlags = 0;
782 result = waveOutPrepareHeader( h_waveout, p_waveheader, sizeof(WAVEHDR) );
783 if( result != MMSYSERR_NOERROR )
785 msg_Err( p_aout, "waveOutPrepareHeader failed" );
789 /* Send the buffer to the waveOut queue */
790 result = waveOutWrite( h_waveout, p_waveheader, sizeof(WAVEHDR) );
791 if( result != MMSYSERR_NOERROR )
793 msg_Err( p_aout, "waveOutWrite failed" );
800 /*****************************************************************************
801 * WaveOutCallback: what to do once WaveOut has played its sound samples
802 *****************************************************************************/
803 static void CALLBACK WaveOutCallback( HWAVEOUT h_waveout, UINT uMsg,
805 DWORD_PTR dwParam1, DWORD_PTR dwParam2 )
807 (void)h_waveout; (void)dwParam1; (void)dwParam2;
808 audio_output_t *p_aout = (audio_output_t *)_p_aout;
809 int i_queued_frames = 0;
811 if( uMsg != WOM_DONE ) return;
813 if( vlc_atomic_get(&p_aout->sys->abort) ) return;
815 /* Find out the current latency */
816 for( int i = 0; i < FRAMES_NUM; i++ )
818 /* Check if frame buf is available */
819 if( !(p_aout->sys->waveheader[i].dwFlags & WHDR_DONE) )
825 /* Don't wake up the thread too much */
826 if( i_queued_frames <= FRAMES_NUM/2 )
827 SetEvent( p_aout->sys->event );
831 /****************************************************************************
832 * WaveOutClearDoneBuffers: Clear all done marked buffers, and free aout_bufer
833 ****************************************************************************
834 * return value is the number of still playing buffers in the queue
835 ****************************************************************************/
836 static int WaveOutClearDoneBuffers(aout_sys_t *p_sys)
838 WAVEHDR *p_waveheader = p_sys->waveheader;
839 int i_queued_frames = 0;
841 for( int i = 0; i < FRAMES_NUM; i++ )
843 if( (p_waveheader[i].dwFlags & WHDR_DONE) &&
844 p_waveheader[i].dwUser )
846 aout_buffer_t *p_buffer =
847 (aout_buffer_t *)(p_waveheader[i].dwUser);
848 /* Unprepare and free the buffers which has just been played */
849 waveOutUnprepareHeader( p_sys->h_waveout, &p_waveheader[i],
852 if( p_waveheader[i].dwUser != 1 )
853 aout_BufferFree( p_buffer );
855 p_waveheader[i].dwUser = 0;
858 /* Check if frame buf is available */
859 if( !(p_waveheader[i].dwFlags & WHDR_DONE) )
864 return i_queued_frames;
867 /*****************************************************************************
868 * WaveOutThread: this thread will capture play notification events.
869 *****************************************************************************
870 * We use this thread to feed new audio samples to the sound card because
871 * we are not authorized to use waveOutWrite() directly in the waveout
873 *****************************************************************************/
874 static void* WaveOutThread( void *data )
876 audio_output_t *p_aout = data;
877 aout_sys_t *p_sys = p_aout->sys;
878 aout_buffer_t *p_buffer = NULL;
879 WAVEHDR *p_waveheader = p_sys->waveheader;
880 int i, i_queued_frames;
883 uint32_t i_buffer_length = 64;
884 int canc = vlc_savecancel ();
886 /* We don't want any resampling when using S/PDIF */
887 b_sleek = p_aout->format.i_format == VLC_CODEC_SPDIFL;
889 // wait for first call to "play()"
890 while( !p_sys->start_date && !vlc_atomic_get(&p_aout->sys->abort) )
891 WaitForSingleObject( p_sys->event, INFINITE );
892 if( vlc_atomic_get(&p_aout->sys->abort) )
895 msg_Dbg( p_aout, "will start to play in %"PRId64" us",
896 (p_sys->start_date - AOUT_MAX_PTS_ADVANCE/4)-mdate());
898 // than wait a short time... before grabbing first frames
899 mwait( p_sys->start_date - AOUT_MAX_PTS_ADVANCE/4 );
901 #define waveout_warn(msg) msg_Warn( p_aout, "aout_PacketNext no buffer "\
902 "got next_date=%d ms, "\
903 "%d frames to play, %s",\
904 (int)(next_date/(mtime_t)1000), \
905 i_queued_frames, msg);
908 while( !vlc_atomic_get(&p_aout->sys->abort) )
910 /* Cleanup and find out the current latency */
911 i_queued_frames = WaveOutClearDoneBuffers( p_sys );
913 if( vlc_atomic_get(&p_aout->sys->abort) ) return NULL;
915 /* Try to fill in as many frame buffers as possible */
916 for( i = 0; i < FRAMES_NUM; i++ )
918 /* Check if frame buf is available */
919 if( p_waveheader[i].dwFlags & WHDR_DONE )
921 // next_date = mdate() + 1000000 * i_queued_frames /
922 // p_aout->format.i_rate * p_aout->i_nb_samples;
924 // the realtime has got our back-site:) to come in sync
925 if(next_date < mdate())
929 /* Take into account the latency */
930 p_buffer = aout_PacketNext( p_aout, next_date );
934 msg_Dbg( p_aout, "aout_PacketNext no buffer got "
935 "next_date=%"PRId64" ms, %d frames to play",
936 next_date/1000, i_queued_frames);
938 // means we are too early to request a new buffer?
939 waveout_warn("waiting...")
940 mwait( next_date - AOUT_MAX_PTS_ADVANCE/4 );
942 p_buffer = aout_PacketNext( p_aout, next_date );
945 if( !p_buffer && i_queued_frames )
947 /* We aren't late so no need to play a blank sample */
953 mtime_t buffer_length = p_buffer->i_length;
954 next_date = next_date + buffer_length;
955 i_buffer_length = buffer_length/1000;
958 /* Do the channel reordering */
959 if( p_buffer && p_sys->b_chan_reorder )
961 aout_ChannelReorder( p_buffer->p_buffer,
963 p_sys->waveformat.Format.nChannels,
964 p_sys->pi_chan_table,
965 p_sys->waveformat.Format.wBitsPerSample );
968 PlayWaveOut( p_aout, p_sys->h_waveout,
969 &p_waveheader[i], p_buffer, b_sleek );
975 if( vlc_atomic_get(&p_aout->sys->abort) ) return NULL;
978 deal with the case that the loop didn't fillup the buffer to the
979 max - instead of waiting that half the buffer is played before
980 fillup the waveout buffers, wait only for the next sample buffer
981 to arrive at the play method...
983 this will also avoid, that the last buffer is play until the
984 end, and then trying to get more data, so it will also
985 work - if the next buffer will arrive some ms before the
986 last buffer is finished.
988 if(i_queued_frames < FRAMES_NUM)
989 WaitForSingleObject( p_sys->new_buffer_event, INFINITE );
991 WaitForSingleObject( p_sys->event, INFINITE );
996 vlc_restorecancel (canc);
1000 static int VolumeSet( audio_output_t * p_aout, float volume, bool mute )
1005 unsigned long i_waveout_vol = volume
1006 * (0xFFFF * AOUT_VOLUME_DEFAULT / AOUT_VOLUME_MAX);
1008 if( i_waveout_vol <= 0xFFFF )
1009 i_waveout_vol |= i_waveout_vol << 16;
1011 i_waveout_vol = 0xFFFFFFFF;
1014 waveOutSetVolume( 0, i_waveout_vol );
1016 waveOutSetVolume( p_aout->sys->h_waveout, i_waveout_vol );
1023 reload the configuration drop down list, of the Audio Devices
1025 static int ReloadWaveoutDevices( vlc_object_t *p_this, char const *psz_name,
1026 vlc_value_t newval, vlc_value_t oldval, void *data )
1028 VLC_UNUSED( newval ); VLC_UNUSED( oldval ); VLC_UNUSED( data );
1030 module_config_t *p_item = config_FindConfig( p_this, psz_name );
1031 if( !p_item ) return VLC_SUCCESS;
1033 /* Clear-up the current list */
1034 if( p_item->i_list )
1038 /* Keep the first entry */
1039 for( i = 1; i < p_item->i_list; i++ )
1041 free((char *)(p_item->ppsz_list[i]) );
1042 free((char *)(p_item->ppsz_list_text[i]) );
1044 /* TODO: Remove when no more needed */
1045 p_item->ppsz_list[i] = NULL;
1046 p_item->ppsz_list_text[i] = NULL;
1050 int wave_devices = waveOutGetNumDevs();
1052 p_item->ppsz_list = xrealloc( p_item->ppsz_list,
1053 (wave_devices+2) * sizeof(char *) );
1054 p_item->ppsz_list_text = xrealloc( p_item->ppsz_list_text,
1055 (wave_devices+2) * sizeof(char *) );
1058 char sz_dev_name[MAXPNAMELEN+32];
1060 for(int i=0; i<wave_devices; i++)
1062 if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
1063 == MMSYSERR_NOERROR)
1065 sprintf( sz_dev_name, psz_device_name_fmt, caps.szPname,
1069 p_item->ppsz_list[j] = FromLocaleDup( sz_dev_name );
1070 p_item->ppsz_list_text[j] = FromLocaleDup( sz_dev_name );
1076 p_item->ppsz_list[j] = NULL;
1077 p_item->ppsz_list_text[j] = NULL;
1079 /* Signal change to the interface */
1080 p_item->b_dirty = true;
1086 convert devicename to device ID for output
1087 if device not found return WAVE_MAPPER, so let
1088 windows decide which preferred audio device
1091 static uint32_t findDeviceID(char *psz_device_name)
1093 if( !psz_device_name )
1096 uint32_t wave_devices = waveOutGetNumDevs();
1098 char sz_dev_name[MAXPNAMELEN+32];
1100 for( uint32_t i = 0; i < wave_devices; i++ )
1102 if( waveOutGetDevCaps( i, &caps, sizeof(WAVEOUTCAPS) )
1103 == MMSYSERR_NOERROR)
1105 sprintf( sz_dev_name, psz_device_name_fmt, caps.szPname,
1109 char *psz_temp = FromLocaleDup(sz_dev_name);
1111 if( !stricmp(psz_temp, psz_device_name) )
1113 LocaleFree( psz_temp );
1116 LocaleFree( psz_temp );