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 /*****************************************************************************
83 * aout_sys_t: waveOut audio output method descriptor
84 *****************************************************************************
85 * This structure is part of the audio output thread descriptor.
86 * It describes the waveOut specific properties of an audio device.
87 *****************************************************************************/
91 uint32_t i_wave_device_id; /* ID of selected output device */
93 HWAVEOUT h_waveout; /* handle to waveout instance */
95 WAVEFORMATEXTENSIBLE waveformat; /* audio format */
97 WAVEHDR waveheader[FRAMES_NUM];
102 HANDLE new_buffer_event;
104 // rental from alsa.c to synchronize startup of audiothread
105 int b_playing; /* playing status */
108 int i_repeat_counter;
112 uint8_t *p_silence_buffer; /* buffer we use to play silence */
123 bool b_chan_reorder; /* do we need channel reordering */
124 int pi_chan_table[AOUT_CHAN_MAX];
129 /*****************************************************************************
131 *****************************************************************************/
132 #define DEVICE_TEXT N_("Select Audio Device")
133 #define DEVICE_LONG N_("Select special Audio device, or let windows "\
134 "decide (default), change needs VLC restart "\
136 #define DEFAULT_AUDIO_DEVICE N_("Default Audio Device")
139 set_shortname( "WaveOut" )
140 set_description( N_("Win32 waveOut extension output") )
141 set_capability( "audio output", 50 )
142 set_category( CAT_AUDIO )
143 set_subcategory( SUBCAT_AUDIO_AOUT )
145 add_string( "waveout-audio-device", "wavemapper",
146 DEVICE_TEXT, DEVICE_LONG, false )
147 change_string_cb( ReloadWaveoutDevices )
148 change_action_add( ReloadWaveoutDevices, N_("Refresh list") )
151 add_bool( "waveout-float32", true, FLOAT_TEXT, FLOAT_LONGTEXT, true )
153 set_callbacks( Open, Close )
156 /*****************************************************************************
157 * Open: open the audio device
158 *****************************************************************************
159 * This function opens and setups Win32 waveOut
160 *****************************************************************************/
161 static int Open( vlc_object_t *p_this )
163 audio_output_t *p_aout = (audio_output_t *)p_this;
166 /* Allocate structure */
167 p_aout->sys = malloc( sizeof( aout_sys_t ) );
169 if( p_aout->sys == NULL )
172 p_aout->pf_play = Play;
173 p_aout->pf_pause = aout_PacketPause;
174 p_aout->pf_flush = aout_PacketFlush;
177 initialize/update Device selection List
179 ReloadWaveoutDevices( p_this, "waveout-audio-device", val, val, NULL);
182 check for configured audio device!
184 char *psz_waveout_dev = var_CreateGetString( p_aout, "waveout-audio-device");
186 p_aout->sys->i_wave_device_id =
187 findDeviceID( psz_waveout_dev );
189 if(p_aout->sys->i_wave_device_id == WAVE_MAPPER)
191 if(psz_waveout_dev &&
192 stricmp(psz_waveout_dev,"wavemapper"))
194 msg_Warn( p_aout, "configured audio device '%s' not available, "\
195 "use default instead", psz_waveout_dev );
198 free( psz_waveout_dev );
201 WAVEOUTCAPS waveoutcaps;
202 if(waveOutGetDevCaps( p_aout->sys->i_wave_device_id,
204 sizeof(WAVEOUTCAPS)) == MMSYSERR_NOERROR)
206 /* log debug some infos about driver, to know who to blame
207 if it doesn't work */
208 msg_Dbg( p_aout, "Drivername: %ls", waveoutcaps.szPname);
209 msg_Dbg( p_aout, "Driver Version: %d.%d",
210 (waveoutcaps.vDriverVersion>>8)&255,
211 waveoutcaps.vDriverVersion & 255);
212 msg_Dbg( p_aout, "Manufacturer identifier: 0x%x", waveoutcaps.wMid );
213 msg_Dbg( p_aout, "Product identifier: 0x%x", waveoutcaps.wPid );
218 if( var_Type( p_aout, "audio-device" ) == 0 )
223 if( var_Get( p_aout, "audio-device", &val ) < 0 )
225 /* Probe() has failed. */
226 var_Destroy( p_aout, "waveout-audio-device");
232 /* Open the device */
233 if( val.i_int == AOUT_VAR_SPDIF )
235 p_aout->format.i_format = VLC_CODEC_SPDIFL;
237 if( OpenWaveOut( p_aout,
238 p_aout->sys->i_wave_device_id,
240 p_aout->format.i_physical_channels,
241 aout_FormatNbChannels( &p_aout->format ),
242 p_aout->format.i_rate, false )
245 msg_Err( p_aout, "cannot open waveout audio device" );
250 /* Calculate the frame size in bytes */
251 p_aout->format.i_bytes_per_frame = AOUT_SPDIF_SIZE;
252 p_aout->format.i_frame_length = A52_FRAME_NB;
253 p_aout->sys->i_buffer_size =
254 p_aout->format.i_bytes_per_frame;
256 aout_PacketInit( p_aout, &p_aout->sys->packet, A52_FRAME_NB );
257 p_aout->volume_set = NULL;
258 p_aout->mute_set = NULL;
267 p_aout->format.i_physical_channels
268 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
269 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
273 p_aout->format.i_physical_channels
274 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
275 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
278 p_aout->format.i_physical_channels = AOUT_CHAN_CENTER;
281 p_aout->format.i_physical_channels
282 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
285 if( OpenWaveOutPCM( p_aout,
286 p_aout->sys->i_wave_device_id,
287 &p_aout->format.i_format,
288 p_aout->format.i_physical_channels,
289 aout_FormatNbChannels( &p_aout->format ),
290 p_aout->format.i_rate, false )
293 msg_Err( p_aout, "cannot open waveout audio device" );
298 /* Calculate the frame size in bytes */
299 aout_FormatPrepare( &p_aout->format );
300 p_aout->sys->i_buffer_size = FRAME_SIZE *
301 p_aout->format.i_bytes_per_frame;
303 aout_PacketInit( p_aout, &p_aout->sys->packet, FRAME_SIZE );
306 /* Check for hardware volume support */
307 if( waveOutGetDevCaps( (UINT_PTR)p_aout->sys->h_waveout,
308 &wocaps, sizeof(wocaps) ) == MMSYSERR_NOERROR
309 && (wocaps.dwSupport & WAVECAPS_VOLUME) )
311 p_aout->volume_set = VolumeSet;
312 p_aout->mute_set = MuteSet;
313 p_aout->sys->volume = 0xffff.fp0;
314 p_aout->sys->mute = false;
318 aout_SoftVolumeInit( p_aout );
321 waveOutReset( p_aout->sys->h_waveout );
323 /* Allocate silence buffer */
324 p_aout->sys->p_silence_buffer =
325 malloc( p_aout->sys->i_buffer_size );
326 if( p_aout->sys->p_silence_buffer == NULL )
328 aout_PacketDestroy( p_aout );
332 p_aout->sys->i_repeat_counter = 0;
335 /* Zero the buffer. WinCE doesn't have calloc(). */
336 memset( p_aout->sys->p_silence_buffer, 0,
337 p_aout->sys->i_buffer_size );
339 /* Now we need to setup our waveOut play notification structure */
340 p_aout->sys->event = CreateEvent( NULL, FALSE, FALSE, NULL );
341 p_aout->sys->new_buffer_event = CreateEvent( NULL, FALSE, FALSE, NULL );
343 /* define startpoint of playback on first call to play()
344 like alsa does (instead of playing a blank sample) */
345 p_aout->sys->b_playing = 0;
346 p_aout->sys->start_date = 0;
349 /* Then launch the notification thread */
350 vlc_atomic_set( &p_aout->sys->abort, 0);
351 if( vlc_clone( &p_aout->sys->thread,
352 WaveOutThread, p_aout, VLC_THREAD_PRIORITY_OUTPUT ) )
354 msg_Err( p_aout, "cannot create WaveOutThread" );
357 /* We need to kick off the playback in order to have the callback properly
359 for( int i = 0; i < FRAMES_NUM; i++ )
361 p_aout->sys->waveheader[i].dwFlags = WHDR_DONE;
362 p_aout->sys->waveheader[i].dwUser = 0;
368 /*****************************************************************************
369 * Probe: probe the audio device for available formats and channels
370 *****************************************************************************/
371 static void Probe( audio_output_t * p_aout )
373 vlc_value_t val, text;
374 vlc_fourcc_t i_format;
375 unsigned int i_physical_channels;
377 var_Create( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
378 text.psz_string = _("Audio Device");
379 var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
381 /* Test for 5.1 support */
382 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
383 AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
384 AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE;
385 if( p_aout->format.i_physical_channels == i_physical_channels )
387 if( OpenWaveOutPCM( p_aout,
388 p_aout->sys->i_wave_device_id,
390 i_physical_channels, 6,
391 p_aout->format.i_rate, true )
394 val.i_int = AOUT_VAR_5_1;
395 text.psz_string = (char *)_("5.1");
396 var_Change( p_aout, "audio-device",
397 VLC_VAR_ADDCHOICE, &val, &text );
398 msg_Dbg( p_aout, "device supports 5.1 channels" );
402 /* Test for 2 Front 2 Rear support */
403 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
404 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
405 if( ( p_aout->format.i_physical_channels & i_physical_channels )
406 == i_physical_channels )
408 if( OpenWaveOutPCM( p_aout,
409 p_aout->sys->i_wave_device_id,
411 i_physical_channels, 4,
412 p_aout->format.i_rate, true )
415 val.i_int = AOUT_VAR_2F2R;
416 text.psz_string = (char *)_("2 Front 2 Rear");
417 var_Change( p_aout, "audio-device",
418 VLC_VAR_ADDCHOICE, &val, &text );
419 msg_Dbg( p_aout, "device supports 4 channels" );
423 /* Test for stereo support */
424 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
425 if( OpenWaveOutPCM( p_aout,
426 p_aout->sys->i_wave_device_id,
428 i_physical_channels, 2,
429 p_aout->format.i_rate, true )
432 val.i_int = AOUT_VAR_STEREO;
433 text.psz_string = (char *)_("Stereo");
434 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
435 msg_Dbg( p_aout, "device supports 2 channels" );
438 /* Test for mono support */
439 i_physical_channels = AOUT_CHAN_CENTER;
440 if( OpenWaveOutPCM( p_aout,
441 p_aout->sys->i_wave_device_id,
443 i_physical_channels, 1,
444 p_aout->format.i_rate, true )
447 val.i_int = AOUT_VAR_MONO;
448 text.psz_string = (char *)_("Mono");
449 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
450 msg_Dbg( p_aout, "device supports 1 channel" );
453 /* Test for SPDIF support */
454 if ( AOUT_FMT_SPDIF( &p_aout->format ) )
456 if( OpenWaveOut( p_aout,
457 p_aout->sys->i_wave_device_id,
459 p_aout->format.i_physical_channels,
460 aout_FormatNbChannels( &p_aout->format ),
461 p_aout->format.i_rate, true )
464 msg_Dbg( p_aout, "device supports A/52 over S/PDIF" );
465 val.i_int = AOUT_VAR_SPDIF;
466 text.psz_string = (char *)_("A/52 over S/PDIF");
467 var_Change( p_aout, "audio-device",
468 VLC_VAR_ADDCHOICE, &val, &text );
469 if( var_InheritBool( p_aout, "spdif" ) )
470 var_Set( p_aout, "audio-device", val );
474 var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
477 /* Probe() has failed. */
478 var_Destroy( p_aout, "audio-device" );
482 var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
485 /*****************************************************************************
486 * Play: play a sound buffer
487 *****************************************************************************
488 * This doesn't actually play the buffer. This just stores the buffer so it
489 * can be played by the callback thread.
490 *****************************************************************************/
491 static void Play( audio_output_t *_p_aout, block_t *block,
492 mtime_t *restrict drift )
494 if( !_p_aout->sys->b_playing )
496 _p_aout->sys->b_playing = 1;
498 /* get the playing date of the first aout buffer */
499 _p_aout->sys->start_date = block->i_pts;
501 msg_Dbg( _p_aout, "Wakeup sleeping output thread.");
503 /* wake up the audio output thread */
504 SetEvent( _p_aout->sys->event );
506 SetEvent( _p_aout->sys->new_buffer_event );
509 aout_PacketPlay( _p_aout, block, drift );
512 /*****************************************************************************
513 * Close: close the audio device
514 *****************************************************************************/
515 static void Close( vlc_object_t *p_this )
517 audio_output_t *p_aout = (audio_output_t *)p_this;
518 aout_sys_t *p_sys = p_aout->sys;
520 /* Before calling waveOutClose we must reset the device */
521 vlc_atomic_set( &p_sys->abort, 1);
523 /* wake up the audio thread, to recognize that p_aout died */
524 SetEvent( p_sys->event );
525 SetEvent( p_sys->new_buffer_event );
527 vlc_join( p_sys->thread, NULL );
530 kill the real output then - when the feed thread
531 is surely terminated!
532 old code could be too early in case that "feeding"
533 was running on termination
535 at this point now its sure, that there will be no new
536 data send to the driver, and we can cancel the last
539 MMRESULT result = waveOutReset( p_sys->h_waveout );
540 if(result != MMSYSERR_NOERROR)
542 msg_Err( p_aout, "waveOutReset failed 0x%x", result );
544 now we must wait, that all buffers are played
545 because cancel doesn't work in this case...
547 if(result == MMSYSERR_NOTSUPPORTED)
550 clear currently played (done) buffers,
551 if returnvalue > 0 (means some buffer still playing)
552 wait for the driver event callback that one buffer
553 is finished with playing, and check again
554 the timeout of 5000ms is just, an emergency exit
555 of this loop, to avoid deadlock in case of other
556 (currently not known bugs, problems, errors cases?)
559 (WaveOutClearDoneBuffers( p_sys ) > 0)
561 (WaitForSingleObject( p_sys->event, 5000) == WAIT_OBJECT_0)
564 msg_Dbg( p_aout, "Wait for waveout device...");
568 WaveOutClearDoneBuffers( p_sys );
571 /* now we can Close the device */
572 if( waveOutClose( p_sys->h_waveout ) != MMSYSERR_NOERROR )
574 msg_Err( p_aout, "waveOutClose failed" );
578 because so long, the waveout device is playing, the callback
579 could occur and need the events
581 CloseHandle( p_sys->event );
582 CloseHandle( p_sys->new_buffer_event);
584 free( p_sys->p_silence_buffer );
585 aout_PacketDestroy( p_aout );
589 /*****************************************************************************
590 * OpenWaveOut: open the waveout sound device
591 ****************************************************************************/
592 static int OpenWaveOut( audio_output_t *p_aout, uint32_t i_device_id, int i_format,
593 int i_channels, int i_nb_channels, int i_rate,
598 /* Set sound format */
600 #define waveformat p_aout->sys->waveformat
602 waveformat.dwChannelMask = 0;
603 for( unsigned i = 0; pi_vlc_chan_order_wg4[i]; i++ )
604 if( i_channels & pi_vlc_chan_order_wg4[i] )
605 waveformat.dwChannelMask |= pi_channels_in[i];
609 case VLC_CODEC_SPDIFL:
611 /* To prevent channel re-ordering */
612 waveformat.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
613 waveformat.Format.wBitsPerSample = 16;
614 waveformat.Samples.wValidBitsPerSample =
615 waveformat.Format.wBitsPerSample;
616 waveformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
617 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF;
621 waveformat.Format.wBitsPerSample = sizeof(float) * 8;
622 waveformat.Samples.wValidBitsPerSample =
623 waveformat.Format.wBitsPerSample;
624 waveformat.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
625 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
629 waveformat.Format.wBitsPerSample = 16;
630 waveformat.Samples.wValidBitsPerSample =
631 waveformat.Format.wBitsPerSample;
632 waveformat.Format.wFormatTag = WAVE_FORMAT_PCM;
633 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_PCM;
637 waveformat.Format.nChannels = i_nb_channels;
638 waveformat.Format.nSamplesPerSec = i_rate;
639 waveformat.Format.nBlockAlign =
640 waveformat.Format.wBitsPerSample / 8 * i_nb_channels;
641 waveformat.Format.nAvgBytesPerSec =
642 waveformat.Format.nSamplesPerSec * waveformat.Format.nBlockAlign;
644 /* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */
645 if( i_nb_channels <= 2 )
647 waveformat.Format.cbSize = 0;
651 waveformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
652 waveformat.Format.cbSize =
653 sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
657 msg_Dbg( p_aout, "OpenWaveDevice-ID: %u", i_device_id);
658 msg_Dbg( p_aout,"waveformat.Format.cbSize = %d",
659 waveformat.Format.cbSize);
660 msg_Dbg( p_aout,"waveformat.Format.wFormatTag = %u",
661 waveformat.Format.wFormatTag);
662 msg_Dbg( p_aout,"waveformat.Format.nChannels = %u",
663 waveformat.Format.nChannels);
664 msg_Dbg( p_aout,"waveformat.Format.nSamplesPerSec = %d",
665 (int)waveformat.Format.nSamplesPerSec);
666 msg_Dbg( p_aout,"waveformat.Format.nAvgBytesPerSec = %u",
667 (int)waveformat.Format.nAvgBytesPerSec);
668 msg_Dbg( p_aout,"waveformat.Format.nBlockAlign = %d",
669 waveformat.Format.nBlockAlign);
670 msg_Dbg( p_aout,"waveformat.Format.wBitsPerSample = %d",
671 waveformat.Format.wBitsPerSample);
672 msg_Dbg( p_aout,"waveformat.Samples.wValidBitsPerSample = %d",
673 waveformat.Samples.wValidBitsPerSample);
674 msg_Dbg( p_aout,"waveformat.Samples.wSamplesPerBlock = %d",
675 waveformat.Samples.wSamplesPerBlock);
676 msg_Dbg( p_aout,"waveformat.dwChannelMask = %lu",
677 waveformat.dwChannelMask);
680 /* Open the device */
681 result = waveOutOpen( &p_aout->sys->h_waveout, i_device_id,
682 (WAVEFORMATEX *)&waveformat,
683 (DWORD_PTR)WaveOutCallback, (DWORD_PTR)p_aout,
684 CALLBACK_FUNCTION | (b_probe?WAVE_FORMAT_QUERY:0) );
685 if( result == WAVERR_BADFORMAT )
687 msg_Warn( p_aout, "waveOutOpen failed WAVERR_BADFORMAT" );
690 if( result == MMSYSERR_ALLOCATED )
692 msg_Warn( p_aout, "waveOutOpen failed WAVERR_ALLOCATED" );
695 if( result != MMSYSERR_NOERROR )
697 msg_Warn( p_aout, "waveOutOpen failed" );
701 p_aout->sys->b_chan_reorder =
702 aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
703 waveformat.dwChannelMask, i_nb_channels,
704 p_aout->sys->pi_chan_table );
706 if( p_aout->sys->b_chan_reorder )
708 msg_Dbg( p_aout, "channel reordering needed" );
717 /*****************************************************************************
718 * OpenWaveOutPCM: open a PCM waveout sound device
719 ****************************************************************************/
720 static int OpenWaveOutPCM( audio_output_t *p_aout, uint32_t i_device_id,
721 vlc_fourcc_t *i_format,
722 int i_channels, int i_nb_channels, int i_rate,
725 bool b_use_float32 = var_CreateGetBool( p_aout, "waveout-float32");
727 if( !b_use_float32 || OpenWaveOut( p_aout, i_device_id, VLC_CODEC_FL32,
728 i_channels, i_nb_channels, i_rate, b_probe )
731 if ( OpenWaveOut( p_aout, i_device_id, VLC_CODEC_S16L,
732 i_channels, i_nb_channels, i_rate, b_probe )
739 *i_format = VLC_CODEC_S16L;
745 *i_format = VLC_CODEC_FL32;
750 /*****************************************************************************
751 * PlayWaveOut: play a buffer through the WaveOut device
752 *****************************************************************************/
753 static int PlayWaveOut( audio_output_t *p_aout, HWAVEOUT h_waveout,
754 WAVEHDR *p_waveheader, block_t *p_buffer, bool b_spdif)
758 /* Prepare the buffer */
759 if( p_buffer != NULL )
761 p_waveheader->lpData = (LPSTR)p_buffer->p_buffer;
763 copy the buffer to the silence buffer :) so in case we don't
764 get the next buffer fast enough (I will repeat this one a time
765 for AC3 / DTS and SPDIF this will sound better instead of
770 memcpy( p_aout->sys->p_silence_buffer,
772 p_aout->sys->i_buffer_size );
773 p_aout->sys->i_repeat_counter = 2;
776 /* Use silence buffer instead */
777 if(p_aout->sys->i_repeat_counter)
779 p_aout->sys->i_repeat_counter--;
780 if(!p_aout->sys->i_repeat_counter)
782 memset( p_aout->sys->p_silence_buffer,
783 0x00, p_aout->sys->i_buffer_size );
786 p_waveheader->lpData = (LPSTR)p_aout->sys->p_silence_buffer;
789 p_waveheader->dwUser = p_buffer ? (DWORD_PTR)p_buffer : (DWORD_PTR)1;
790 p_waveheader->dwBufferLength = p_aout->sys->i_buffer_size;
791 p_waveheader->dwFlags = 0;
793 result = waveOutPrepareHeader( h_waveout, p_waveheader, sizeof(WAVEHDR) );
794 if( result != MMSYSERR_NOERROR )
796 msg_Err( p_aout, "waveOutPrepareHeader failed" );
800 /* Send the buffer to the waveOut queue */
801 result = waveOutWrite( h_waveout, p_waveheader, sizeof(WAVEHDR) );
802 if( result != MMSYSERR_NOERROR )
804 msg_Err( p_aout, "waveOutWrite failed" );
811 /*****************************************************************************
812 * WaveOutCallback: what to do once WaveOut has played its sound samples
813 *****************************************************************************/
814 static void CALLBACK WaveOutCallback( HWAVEOUT h_waveout, UINT uMsg,
816 DWORD_PTR dwParam1, DWORD_PTR dwParam2 )
818 (void)h_waveout; (void)dwParam1; (void)dwParam2;
819 audio_output_t *p_aout = (audio_output_t *)_p_aout;
820 int i_queued_frames = 0;
822 if( uMsg != WOM_DONE ) return;
824 if( vlc_atomic_get(&p_aout->sys->abort) ) return;
826 /* Find out the current latency */
827 for( int i = 0; i < FRAMES_NUM; i++ )
829 /* Check if frame buf is available */
830 if( !(p_aout->sys->waveheader[i].dwFlags & WHDR_DONE) )
836 /* Don't wake up the thread too much */
837 if( i_queued_frames <= FRAMES_NUM/2 )
838 SetEvent( p_aout->sys->event );
842 /****************************************************************************
843 * WaveOutClearDoneBuffers: Clear all done marked buffers, and free buffer
844 ****************************************************************************
845 * return value is the number of still playing buffers in the queue
846 ****************************************************************************/
847 static int WaveOutClearDoneBuffers(aout_sys_t *p_sys)
849 WAVEHDR *p_waveheader = p_sys->waveheader;
850 int i_queued_frames = 0;
852 for( int i = 0; i < FRAMES_NUM; i++ )
854 if( (p_waveheader[i].dwFlags & WHDR_DONE) &&
855 p_waveheader[i].dwUser )
858 (block_t *)(p_waveheader[i].dwUser);
859 /* Unprepare and free the buffers which has just been played */
860 waveOutUnprepareHeader( p_sys->h_waveout, &p_waveheader[i],
863 if( p_waveheader[i].dwUser != 1 )
864 block_Release( p_buffer );
866 p_waveheader[i].dwUser = 0;
869 /* Check if frame buf is available */
870 if( !(p_waveheader[i].dwFlags & WHDR_DONE) )
875 return i_queued_frames;
878 /*****************************************************************************
879 * WaveOutThread: this thread will capture play notification events.
880 *****************************************************************************
881 * We use this thread to feed new audio samples to the sound card because
882 * we are not authorized to use waveOutWrite() directly in the waveout
884 *****************************************************************************/
885 static void* WaveOutThread( void *data )
887 audio_output_t *p_aout = data;
888 aout_sys_t *p_sys = p_aout->sys;
889 block_t *p_buffer = NULL;
890 WAVEHDR *p_waveheader = p_sys->waveheader;
891 int i, i_queued_frames;
894 int canc = vlc_savecancel ();
896 /* We don't want any resampling when using S/PDIF */
897 b_sleek = p_aout->format.i_format == VLC_CODEC_SPDIFL;
899 // wait for first call to "play()"
900 while( !p_sys->start_date && !vlc_atomic_get(&p_aout->sys->abort) )
901 WaitForSingleObject( p_sys->event, INFINITE );
902 if( vlc_atomic_get(&p_aout->sys->abort) )
905 msg_Dbg( p_aout, "will start to play in %"PRId64" us",
906 (p_sys->start_date - AOUT_MAX_PTS_ADVANCE/4)-mdate());
908 // than wait a short time... before grabbing first frames
909 mwait( p_sys->start_date - AOUT_MAX_PTS_ADVANCE/4 );
911 #define waveout_warn(msg) msg_Warn( p_aout, "aout_PacketNext no buffer "\
912 "got next_date=%d ms, "\
913 "%d frames to play, %s",\
914 (int)(next_date/(mtime_t)1000), \
915 i_queued_frames, msg);
918 while( !vlc_atomic_get(&p_aout->sys->abort) )
920 /* Cleanup and find out the current latency */
921 i_queued_frames = WaveOutClearDoneBuffers( p_sys );
923 if( vlc_atomic_get(&p_aout->sys->abort) ) return NULL;
925 /* Try to fill in as many frame buffers as possible */
926 for( i = 0; i < FRAMES_NUM; i++ )
928 /* Check if frame buf is available */
929 if( p_waveheader[i].dwFlags & WHDR_DONE )
931 // next_date = mdate() + 1000000 * i_queued_frames /
932 // p_aout->format.i_rate * p_aout->i_nb_samples;
934 // the realtime has got our back-site:) to come in sync
935 if(next_date < mdate())
939 /* Take into account the latency */
940 p_buffer = aout_PacketNext( p_aout, next_date );
944 msg_Dbg( p_aout, "aout_PacketNext no buffer got "
945 "next_date=%"PRId64" ms, %d frames to play",
946 next_date/1000, i_queued_frames);
948 // means we are too early to request a new buffer?
949 waveout_warn("waiting...")
950 mwait( next_date - AOUT_MAX_PTS_ADVANCE/4 );
952 p_buffer = aout_PacketNext( p_aout, next_date );
955 if( !p_buffer && i_queued_frames )
957 /* We aren't late so no need to play a blank sample */
963 mtime_t buffer_length = p_buffer->i_length;
964 next_date = next_date + buffer_length;
967 /* Do the channel reordering */
968 if( p_buffer && p_sys->b_chan_reorder )
970 aout_ChannelReorder( p_buffer->p_buffer,
972 p_sys->waveformat.Format.nChannels,
973 p_sys->pi_chan_table,
974 p_sys->waveformat.Format.wBitsPerSample );
977 PlayWaveOut( p_aout, p_sys->h_waveout,
978 &p_waveheader[i], p_buffer, b_sleek );
984 if( vlc_atomic_get(&p_aout->sys->abort) ) return NULL;
987 deal with the case that the loop didn't fillup the buffer to the
988 max - instead of waiting that half the buffer is played before
989 fillup the waveout buffers, wait only for the next sample buffer
990 to arrive at the play method...
992 this will also avoid, that the last buffer is play until the
993 end, and then trying to get more data, so it will also
994 work - if the next buffer will arrive some ms before the
995 last buffer is finished.
997 if(i_queued_frames < FRAMES_NUM)
998 WaitForSingleObject( p_sys->new_buffer_event, INFINITE );
1000 WaitForSingleObject( p_sys->event, INFINITE );
1005 vlc_restorecancel (canc);
1010 static int VolumeSet( audio_output_t *aout, float volume )
1012 aout_sys_t *sys = aout->sys;
1013 const HWAVEOUT hwo = sys->h_waveout;
1014 const float full = 0xffff.fp0;
1017 if( volume >= full )
1020 sys->volume = volume;
1024 uint16_t vol = lroundf(volume);
1025 waveOutSetVolume( hwo, vol | (vol << 16) );
1029 static int MuteSet( audio_output_t * p_aout, bool mute )
1031 aout_sys_t *sys = p_aout->sys;
1032 const HWAVEOUT hwo = sys->h_waveout;
1033 uint16_t vol = mute ? 0 : lroundf(sys->volume);
1036 waveOutSetVolume( hwo, vol | (vol << 16) );
1042 reload the configuration drop down list, of the Audio Devices
1044 static int ReloadWaveoutDevices( vlc_object_t *p_this, char const *psz_name,
1045 vlc_value_t newval, vlc_value_t oldval, void *data )
1047 VLC_UNUSED( newval ); VLC_UNUSED( oldval ); VLC_UNUSED( data );
1049 module_config_t *p_item = config_FindConfig( p_this, psz_name );
1050 if( !p_item ) return VLC_SUCCESS;
1052 /* Clear-up the current list */
1053 if( p_item->i_list )
1057 /* Keep the first entry */
1058 for( i = 1; i < p_item->i_list; i++ )
1060 free((char *)(p_item->ppsz_list[i]) );
1061 free((char *)(p_item->ppsz_list_text[i]) );
1063 /* TODO: Remove when no more needed */
1064 p_item->ppsz_list[i] = NULL;
1065 p_item->ppsz_list_text[i] = NULL;
1069 int wave_devices = waveOutGetNumDevs();
1071 p_item->ppsz_list = xrealloc( p_item->ppsz_list,
1072 (wave_devices+2) * sizeof(char *) );
1073 p_item->ppsz_list_text = xrealloc( p_item->ppsz_list_text,
1074 (wave_devices+2) * sizeof(char *) );
1077 for(int i=0; i<wave_devices; i++)
1080 wchar_t dev_name[MAXPNAMELEN+32];
1082 if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
1083 != MMSYSERR_NOERROR)
1086 _snwprintf(dev_name, MAXPNAMELEN + 32, device_name_fmt,
1087 caps.szPname, caps.wMid, caps.wPid);
1088 p_item->ppsz_list[j] = FromWide( dev_name );
1089 p_item->ppsz_list_text[j] = FromWide( dev_name );
1093 p_item->ppsz_list[j] = NULL;
1094 p_item->ppsz_list_text[j] = NULL;
1100 convert devicename to device ID for output
1101 if device not found return WAVE_MAPPER, so let
1102 windows decide which preferred audio device
1105 static uint32_t findDeviceID(char *psz_device_name)
1107 if( !psz_device_name )
1110 uint32_t wave_devices = waveOutGetNumDevs();
1112 for( uint32_t i = 0; i < wave_devices; i++ )
1115 wchar_t dev_name[MAXPNAMELEN+32];
1117 if( waveOutGetDevCaps( i, &caps, sizeof(WAVEOUTCAPS) )
1118 != MMSYSERR_NOERROR )
1121 _snwprintf( dev_name, MAXPNAMELEN + 32, device_name_fmt,
1122 caps.szPname, caps.wMid, caps.wPid );
1123 char *u8 = FromWide(dev_name);
1124 if( !stricmp(u8, psz_device_name) )