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 *, const char *,
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 )
150 add_bool( "waveout-float32", true, FLOAT_TEXT, FLOAT_LONGTEXT, true )
152 set_callbacks( Open, Close )
155 /*****************************************************************************
156 * Open: open the audio device
157 *****************************************************************************
158 * This function opens and setups Win32 waveOut
159 *****************************************************************************/
160 static int Open( vlc_object_t *p_this )
162 audio_output_t *p_aout = (audio_output_t *)p_this;
165 /* Allocate structure */
166 p_aout->sys = malloc( sizeof( aout_sys_t ) );
168 if( p_aout->sys == NULL )
171 p_aout->pf_play = Play;
172 p_aout->pf_pause = aout_PacketPause;
173 p_aout->pf_flush = aout_PacketFlush;
176 check for configured audio device!
178 char *psz_waveout_dev = var_CreateGetString( p_aout, "waveout-audio-device");
180 p_aout->sys->i_wave_device_id =
181 findDeviceID( psz_waveout_dev );
183 if(p_aout->sys->i_wave_device_id == WAVE_MAPPER)
185 if(psz_waveout_dev &&
186 stricmp(psz_waveout_dev,"wavemapper"))
188 msg_Warn( p_aout, "configured audio device '%s' not available, "\
189 "use default instead", psz_waveout_dev );
192 free( psz_waveout_dev );
195 WAVEOUTCAPS waveoutcaps;
196 if(waveOutGetDevCaps( p_aout->sys->i_wave_device_id,
198 sizeof(WAVEOUTCAPS)) == MMSYSERR_NOERROR)
200 /* log debug some infos about driver, to know who to blame
201 if it doesn't work */
202 msg_Dbg( p_aout, "Drivername: %ls", waveoutcaps.szPname);
203 msg_Dbg( p_aout, "Driver Version: %d.%d",
204 (waveoutcaps.vDriverVersion>>8)&255,
205 waveoutcaps.vDriverVersion & 255);
206 msg_Dbg( p_aout, "Manufacturer identifier: 0x%x", waveoutcaps.wMid );
207 msg_Dbg( p_aout, "Product identifier: 0x%x", waveoutcaps.wPid );
212 if( var_Type( p_aout, "audio-device" ) == 0 )
217 if( var_Get( p_aout, "audio-device", &val ) < 0 )
219 /* Probe() has failed. */
220 var_Destroy( p_aout, "waveout-audio-device");
226 /* Open the device */
227 if( val.i_int == AOUT_VAR_SPDIF )
229 p_aout->format.i_format = VLC_CODEC_SPDIFL;
231 if( OpenWaveOut( p_aout,
232 p_aout->sys->i_wave_device_id,
234 p_aout->format.i_physical_channels,
235 aout_FormatNbChannels( &p_aout->format ),
236 p_aout->format.i_rate, false )
239 msg_Err( p_aout, "cannot open waveout audio device" );
244 /* Calculate the frame size in bytes */
245 p_aout->format.i_bytes_per_frame = AOUT_SPDIF_SIZE;
246 p_aout->format.i_frame_length = A52_FRAME_NB;
247 p_aout->sys->i_buffer_size =
248 p_aout->format.i_bytes_per_frame;
250 aout_PacketInit( p_aout, &p_aout->sys->packet, A52_FRAME_NB );
251 p_aout->volume_set = NULL;
252 p_aout->mute_set = NULL;
261 p_aout->format.i_physical_channels
262 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
263 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
267 p_aout->format.i_physical_channels
268 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
269 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
272 p_aout->format.i_physical_channels = AOUT_CHAN_CENTER;
275 p_aout->format.i_physical_channels
276 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
279 if( OpenWaveOutPCM( p_aout,
280 p_aout->sys->i_wave_device_id,
281 &p_aout->format.i_format,
282 p_aout->format.i_physical_channels,
283 aout_FormatNbChannels( &p_aout->format ),
284 p_aout->format.i_rate, false )
287 msg_Err( p_aout, "cannot open waveout audio device" );
292 /* Calculate the frame size in bytes */
293 aout_FormatPrepare( &p_aout->format );
294 p_aout->sys->i_buffer_size = FRAME_SIZE *
295 p_aout->format.i_bytes_per_frame;
297 aout_PacketInit( p_aout, &p_aout->sys->packet, FRAME_SIZE );
300 /* Check for hardware volume support */
301 if( waveOutGetDevCaps( (UINT_PTR)p_aout->sys->h_waveout,
302 &wocaps, sizeof(wocaps) ) == MMSYSERR_NOERROR
303 && (wocaps.dwSupport & WAVECAPS_VOLUME) )
305 p_aout->volume_set = VolumeSet;
306 p_aout->mute_set = MuteSet;
307 p_aout->sys->volume = 0xffff.fp0;
308 p_aout->sys->mute = false;
312 aout_SoftVolumeInit( p_aout );
315 waveOutReset( p_aout->sys->h_waveout );
317 /* Allocate silence buffer */
318 p_aout->sys->p_silence_buffer =
319 malloc( p_aout->sys->i_buffer_size );
320 if( p_aout->sys->p_silence_buffer == NULL )
322 aout_PacketDestroy( p_aout );
326 p_aout->sys->i_repeat_counter = 0;
329 /* Zero the buffer. WinCE doesn't have calloc(). */
330 memset( p_aout->sys->p_silence_buffer, 0,
331 p_aout->sys->i_buffer_size );
333 /* Now we need to setup our waveOut play notification structure */
334 p_aout->sys->event = CreateEvent( NULL, FALSE, FALSE, NULL );
335 p_aout->sys->new_buffer_event = CreateEvent( NULL, FALSE, FALSE, NULL );
337 /* define startpoint of playback on first call to play()
338 like alsa does (instead of playing a blank sample) */
339 p_aout->sys->b_playing = 0;
340 p_aout->sys->start_date = 0;
343 /* Then launch the notification thread */
344 vlc_atomic_set( &p_aout->sys->abort, 0);
345 if( vlc_clone( &p_aout->sys->thread,
346 WaveOutThread, p_aout, VLC_THREAD_PRIORITY_OUTPUT ) )
348 msg_Err( p_aout, "cannot create WaveOutThread" );
351 /* We need to kick off the playback in order to have the callback properly
353 for( int i = 0; i < FRAMES_NUM; i++ )
355 p_aout->sys->waveheader[i].dwFlags = WHDR_DONE;
356 p_aout->sys->waveheader[i].dwUser = 0;
362 /*****************************************************************************
363 * Probe: probe the audio device for available formats and channels
364 *****************************************************************************/
365 static void Probe( audio_output_t * p_aout )
367 vlc_value_t val, text;
368 vlc_fourcc_t i_format;
369 unsigned int i_physical_channels;
371 var_Create( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
372 text.psz_string = _("Audio Device");
373 var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
375 /* Test for 5.1 support */
376 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
377 AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
378 AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE;
379 if( p_aout->format.i_physical_channels == i_physical_channels )
381 if( OpenWaveOutPCM( p_aout,
382 p_aout->sys->i_wave_device_id,
384 i_physical_channels, 6,
385 p_aout->format.i_rate, true )
388 val.i_int = AOUT_VAR_5_1;
389 text.psz_string = (char *)_("5.1");
390 var_Change( p_aout, "audio-device",
391 VLC_VAR_ADDCHOICE, &val, &text );
392 msg_Dbg( p_aout, "device supports 5.1 channels" );
396 /* Test for 2 Front 2 Rear support */
397 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
398 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
399 if( ( p_aout->format.i_physical_channels & i_physical_channels )
400 == i_physical_channels )
402 if( OpenWaveOutPCM( p_aout,
403 p_aout->sys->i_wave_device_id,
405 i_physical_channels, 4,
406 p_aout->format.i_rate, true )
409 val.i_int = AOUT_VAR_2F2R;
410 text.psz_string = (char *)_("2 Front 2 Rear");
411 var_Change( p_aout, "audio-device",
412 VLC_VAR_ADDCHOICE, &val, &text );
413 msg_Dbg( p_aout, "device supports 4 channels" );
417 /* Test for stereo support */
418 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
419 if( OpenWaveOutPCM( p_aout,
420 p_aout->sys->i_wave_device_id,
422 i_physical_channels, 2,
423 p_aout->format.i_rate, true )
426 val.i_int = AOUT_VAR_STEREO;
427 text.psz_string = (char *)_("Stereo");
428 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
429 msg_Dbg( p_aout, "device supports 2 channels" );
432 /* Test for mono support */
433 i_physical_channels = AOUT_CHAN_CENTER;
434 if( OpenWaveOutPCM( p_aout,
435 p_aout->sys->i_wave_device_id,
437 i_physical_channels, 1,
438 p_aout->format.i_rate, true )
441 val.i_int = AOUT_VAR_MONO;
442 text.psz_string = (char *)_("Mono");
443 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
444 msg_Dbg( p_aout, "device supports 1 channel" );
447 /* Test for SPDIF support */
448 if ( AOUT_FMT_SPDIF( &p_aout->format ) )
450 if( OpenWaveOut( p_aout,
451 p_aout->sys->i_wave_device_id,
453 p_aout->format.i_physical_channels,
454 aout_FormatNbChannels( &p_aout->format ),
455 p_aout->format.i_rate, true )
458 msg_Dbg( p_aout, "device supports A/52 over S/PDIF" );
459 val.i_int = AOUT_VAR_SPDIF;
460 text.psz_string = (char *)_("A/52 over S/PDIF");
461 var_Change( p_aout, "audio-device",
462 VLC_VAR_ADDCHOICE, &val, &text );
463 if( var_InheritBool( p_aout, "spdif" ) )
464 var_Set( p_aout, "audio-device", val );
468 var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
471 /* Probe() has failed. */
472 var_Destroy( p_aout, "audio-device" );
476 var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
479 /*****************************************************************************
480 * Play: play a sound buffer
481 *****************************************************************************
482 * This doesn't actually play the buffer. This just stores the buffer so it
483 * can be played by the callback thread.
484 *****************************************************************************/
485 static void Play( audio_output_t *_p_aout, block_t *block,
486 mtime_t *restrict drift )
488 if( !_p_aout->sys->b_playing )
490 _p_aout->sys->b_playing = 1;
492 /* get the playing date of the first aout buffer */
493 _p_aout->sys->start_date = block->i_pts;
495 msg_Dbg( _p_aout, "Wakeup sleeping output thread.");
497 /* wake up the audio output thread */
498 SetEvent( _p_aout->sys->event );
500 SetEvent( _p_aout->sys->new_buffer_event );
503 aout_PacketPlay( _p_aout, block, drift );
506 /*****************************************************************************
507 * Close: close the audio device
508 *****************************************************************************/
509 static void Close( vlc_object_t *p_this )
511 audio_output_t *p_aout = (audio_output_t *)p_this;
512 aout_sys_t *p_sys = p_aout->sys;
514 /* Before calling waveOutClose we must reset the device */
515 vlc_atomic_set( &p_sys->abort, 1);
517 /* wake up the audio thread, to recognize that p_aout died */
518 SetEvent( p_sys->event );
519 SetEvent( p_sys->new_buffer_event );
521 vlc_join( p_sys->thread, NULL );
524 kill the real output then - when the feed thread
525 is surely terminated!
526 old code could be too early in case that "feeding"
527 was running on termination
529 at this point now its sure, that there will be no new
530 data send to the driver, and we can cancel the last
533 MMRESULT result = waveOutReset( p_sys->h_waveout );
534 if(result != MMSYSERR_NOERROR)
536 msg_Err( p_aout, "waveOutReset failed 0x%x", result );
538 now we must wait, that all buffers are played
539 because cancel doesn't work in this case...
541 if(result == MMSYSERR_NOTSUPPORTED)
544 clear currently played (done) buffers,
545 if returnvalue > 0 (means some buffer still playing)
546 wait for the driver event callback that one buffer
547 is finished with playing, and check again
548 the timeout of 5000ms is just, an emergency exit
549 of this loop, to avoid deadlock in case of other
550 (currently not known bugs, problems, errors cases?)
553 (WaveOutClearDoneBuffers( p_sys ) > 0)
555 (WaitForSingleObject( p_sys->event, 5000) == WAIT_OBJECT_0)
558 msg_Dbg( p_aout, "Wait for waveout device...");
562 WaveOutClearDoneBuffers( p_sys );
565 /* now we can Close the device */
566 if( waveOutClose( p_sys->h_waveout ) != MMSYSERR_NOERROR )
568 msg_Err( p_aout, "waveOutClose failed" );
572 because so long, the waveout device is playing, the callback
573 could occur and need the events
575 CloseHandle( p_sys->event );
576 CloseHandle( p_sys->new_buffer_event);
578 free( p_sys->p_silence_buffer );
579 aout_PacketDestroy( p_aout );
583 /*****************************************************************************
584 * OpenWaveOut: open the waveout sound device
585 ****************************************************************************/
586 static int OpenWaveOut( audio_output_t *p_aout, uint32_t i_device_id, int i_format,
587 int i_channels, int i_nb_channels, int i_rate,
592 /* Set sound format */
594 #define waveformat p_aout->sys->waveformat
596 waveformat.dwChannelMask = 0;
597 for( unsigned i = 0; pi_vlc_chan_order_wg4[i]; i++ )
598 if( i_channels & pi_vlc_chan_order_wg4[i] )
599 waveformat.dwChannelMask |= pi_channels_in[i];
603 case VLC_CODEC_SPDIFL:
605 /* To prevent channel re-ordering */
606 waveformat.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
607 waveformat.Format.wBitsPerSample = 16;
608 waveformat.Samples.wValidBitsPerSample =
609 waveformat.Format.wBitsPerSample;
610 waveformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
611 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF;
615 waveformat.Format.wBitsPerSample = sizeof(float) * 8;
616 waveformat.Samples.wValidBitsPerSample =
617 waveformat.Format.wBitsPerSample;
618 waveformat.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
619 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
623 waveformat.Format.wBitsPerSample = 16;
624 waveformat.Samples.wValidBitsPerSample =
625 waveformat.Format.wBitsPerSample;
626 waveformat.Format.wFormatTag = WAVE_FORMAT_PCM;
627 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_PCM;
631 waveformat.Format.nChannels = i_nb_channels;
632 waveformat.Format.nSamplesPerSec = i_rate;
633 waveformat.Format.nBlockAlign =
634 waveformat.Format.wBitsPerSample / 8 * i_nb_channels;
635 waveformat.Format.nAvgBytesPerSec =
636 waveformat.Format.nSamplesPerSec * waveformat.Format.nBlockAlign;
638 /* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */
639 if( i_nb_channels <= 2 )
641 waveformat.Format.cbSize = 0;
645 waveformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
646 waveformat.Format.cbSize =
647 sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
651 msg_Dbg( p_aout, "OpenWaveDevice-ID: %u", i_device_id);
652 msg_Dbg( p_aout,"waveformat.Format.cbSize = %d",
653 waveformat.Format.cbSize);
654 msg_Dbg( p_aout,"waveformat.Format.wFormatTag = %u",
655 waveformat.Format.wFormatTag);
656 msg_Dbg( p_aout,"waveformat.Format.nChannels = %u",
657 waveformat.Format.nChannels);
658 msg_Dbg( p_aout,"waveformat.Format.nSamplesPerSec = %d",
659 (int)waveformat.Format.nSamplesPerSec);
660 msg_Dbg( p_aout,"waveformat.Format.nAvgBytesPerSec = %u",
661 (int)waveformat.Format.nAvgBytesPerSec);
662 msg_Dbg( p_aout,"waveformat.Format.nBlockAlign = %d",
663 waveformat.Format.nBlockAlign);
664 msg_Dbg( p_aout,"waveformat.Format.wBitsPerSample = %d",
665 waveformat.Format.wBitsPerSample);
666 msg_Dbg( p_aout,"waveformat.Samples.wValidBitsPerSample = %d",
667 waveformat.Samples.wValidBitsPerSample);
668 msg_Dbg( p_aout,"waveformat.Samples.wSamplesPerBlock = %d",
669 waveformat.Samples.wSamplesPerBlock);
670 msg_Dbg( p_aout,"waveformat.dwChannelMask = %lu",
671 waveformat.dwChannelMask);
674 /* Open the device */
675 result = waveOutOpen( &p_aout->sys->h_waveout, i_device_id,
676 (WAVEFORMATEX *)&waveformat,
677 (DWORD_PTR)WaveOutCallback, (DWORD_PTR)p_aout,
678 CALLBACK_FUNCTION | (b_probe?WAVE_FORMAT_QUERY:0) );
679 if( result == WAVERR_BADFORMAT )
681 msg_Warn( p_aout, "waveOutOpen failed WAVERR_BADFORMAT" );
684 if( result == MMSYSERR_ALLOCATED )
686 msg_Warn( p_aout, "waveOutOpen failed WAVERR_ALLOCATED" );
689 if( result != MMSYSERR_NOERROR )
691 msg_Warn( p_aout, "waveOutOpen failed" );
695 p_aout->sys->b_chan_reorder =
696 aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
697 waveformat.dwChannelMask, i_nb_channels,
698 p_aout->sys->pi_chan_table );
700 if( p_aout->sys->b_chan_reorder )
702 msg_Dbg( p_aout, "channel reordering needed" );
711 /*****************************************************************************
712 * OpenWaveOutPCM: open a PCM waveout sound device
713 ****************************************************************************/
714 static int OpenWaveOutPCM( audio_output_t *p_aout, uint32_t i_device_id,
715 vlc_fourcc_t *i_format,
716 int i_channels, int i_nb_channels, int i_rate,
719 bool b_use_float32 = var_CreateGetBool( p_aout, "waveout-float32");
721 if( !b_use_float32 || OpenWaveOut( p_aout, i_device_id, VLC_CODEC_FL32,
722 i_channels, i_nb_channels, i_rate, b_probe )
725 if ( OpenWaveOut( p_aout, i_device_id, VLC_CODEC_S16L,
726 i_channels, i_nb_channels, i_rate, b_probe )
733 *i_format = VLC_CODEC_S16L;
739 *i_format = VLC_CODEC_FL32;
744 /*****************************************************************************
745 * PlayWaveOut: play a buffer through the WaveOut device
746 *****************************************************************************/
747 static int PlayWaveOut( audio_output_t *p_aout, HWAVEOUT h_waveout,
748 WAVEHDR *p_waveheader, block_t *p_buffer, bool b_spdif)
752 /* Prepare the buffer */
753 if( p_buffer != NULL )
755 p_waveheader->lpData = (LPSTR)p_buffer->p_buffer;
757 copy the buffer to the silence buffer :) so in case we don't
758 get the next buffer fast enough (I will repeat this one a time
759 for AC3 / DTS and SPDIF this will sound better instead of
764 memcpy( p_aout->sys->p_silence_buffer,
766 p_aout->sys->i_buffer_size );
767 p_aout->sys->i_repeat_counter = 2;
770 /* Use silence buffer instead */
771 if(p_aout->sys->i_repeat_counter)
773 p_aout->sys->i_repeat_counter--;
774 if(!p_aout->sys->i_repeat_counter)
776 memset( p_aout->sys->p_silence_buffer,
777 0x00, p_aout->sys->i_buffer_size );
780 p_waveheader->lpData = (LPSTR)p_aout->sys->p_silence_buffer;
783 p_waveheader->dwUser = p_buffer ? (DWORD_PTR)p_buffer : (DWORD_PTR)1;
784 p_waveheader->dwBufferLength = p_aout->sys->i_buffer_size;
785 p_waveheader->dwFlags = 0;
787 result = waveOutPrepareHeader( h_waveout, p_waveheader, sizeof(WAVEHDR) );
788 if( result != MMSYSERR_NOERROR )
790 msg_Err( p_aout, "waveOutPrepareHeader failed" );
794 /* Send the buffer to the waveOut queue */
795 result = waveOutWrite( h_waveout, p_waveheader, sizeof(WAVEHDR) );
796 if( result != MMSYSERR_NOERROR )
798 msg_Err( p_aout, "waveOutWrite failed" );
805 /*****************************************************************************
806 * WaveOutCallback: what to do once WaveOut has played its sound samples
807 *****************************************************************************/
808 static void CALLBACK WaveOutCallback( HWAVEOUT h_waveout, UINT uMsg,
810 DWORD_PTR dwParam1, DWORD_PTR dwParam2 )
812 (void)h_waveout; (void)dwParam1; (void)dwParam2;
813 audio_output_t *p_aout = (audio_output_t *)_p_aout;
814 int i_queued_frames = 0;
816 if( uMsg != WOM_DONE ) return;
818 if( vlc_atomic_get(&p_aout->sys->abort) ) return;
820 /* Find out the current latency */
821 for( int i = 0; i < FRAMES_NUM; i++ )
823 /* Check if frame buf is available */
824 if( !(p_aout->sys->waveheader[i].dwFlags & WHDR_DONE) )
830 /* Don't wake up the thread too much */
831 if( i_queued_frames <= FRAMES_NUM/2 )
832 SetEvent( p_aout->sys->event );
836 /****************************************************************************
837 * WaveOutClearDoneBuffers: Clear all done marked buffers, and free buffer
838 ****************************************************************************
839 * return value is the number of still playing buffers in the queue
840 ****************************************************************************/
841 static int WaveOutClearDoneBuffers(aout_sys_t *p_sys)
843 WAVEHDR *p_waveheader = p_sys->waveheader;
844 int i_queued_frames = 0;
846 for( int i = 0; i < FRAMES_NUM; i++ )
848 if( (p_waveheader[i].dwFlags & WHDR_DONE) &&
849 p_waveheader[i].dwUser )
852 (block_t *)(p_waveheader[i].dwUser);
853 /* Unprepare and free the buffers which has just been played */
854 waveOutUnprepareHeader( p_sys->h_waveout, &p_waveheader[i],
857 if( p_waveheader[i].dwUser != 1 )
858 block_Release( p_buffer );
860 p_waveheader[i].dwUser = 0;
863 /* Check if frame buf is available */
864 if( !(p_waveheader[i].dwFlags & WHDR_DONE) )
869 return i_queued_frames;
872 /*****************************************************************************
873 * WaveOutThread: this thread will capture play notification events.
874 *****************************************************************************
875 * We use this thread to feed new audio samples to the sound card because
876 * we are not authorized to use waveOutWrite() directly in the waveout
878 *****************************************************************************/
879 static void* WaveOutThread( void *data )
881 audio_output_t *p_aout = data;
882 aout_sys_t *p_sys = p_aout->sys;
883 block_t *p_buffer = NULL;
884 WAVEHDR *p_waveheader = p_sys->waveheader;
885 int i, i_queued_frames;
888 int canc = vlc_savecancel ();
890 /* We don't want any resampling when using S/PDIF */
891 b_sleek = p_aout->format.i_format == VLC_CODEC_SPDIFL;
893 // wait for first call to "play()"
894 while( !p_sys->start_date && !vlc_atomic_get(&p_aout->sys->abort) )
895 WaitForSingleObject( p_sys->event, INFINITE );
896 if( vlc_atomic_get(&p_aout->sys->abort) )
899 msg_Dbg( p_aout, "will start to play in %"PRId64" us",
900 (p_sys->start_date - AOUT_MAX_PTS_ADVANCE/4)-mdate());
902 // than wait a short time... before grabbing first frames
903 mwait( p_sys->start_date - AOUT_MAX_PTS_ADVANCE/4 );
905 #define waveout_warn(msg) msg_Warn( p_aout, "aout_PacketNext no buffer "\
906 "got next_date=%d ms, "\
907 "%d frames to play, %s",\
908 (int)(next_date/(mtime_t)1000), \
909 i_queued_frames, msg);
912 while( !vlc_atomic_get(&p_aout->sys->abort) )
914 /* Cleanup and find out the current latency */
915 i_queued_frames = WaveOutClearDoneBuffers( p_sys );
917 if( vlc_atomic_get(&p_aout->sys->abort) ) return NULL;
919 /* Try to fill in as many frame buffers as possible */
920 for( i = 0; i < FRAMES_NUM; i++ )
922 /* Check if frame buf is available */
923 if( p_waveheader[i].dwFlags & WHDR_DONE )
925 // next_date = mdate() + 1000000 * i_queued_frames /
926 // p_aout->format.i_rate * p_aout->i_nb_samples;
928 // the realtime has got our back-site:) to come in sync
929 if(next_date < mdate())
933 /* Take into account the latency */
934 p_buffer = aout_PacketNext( p_aout, next_date );
938 msg_Dbg( p_aout, "aout_PacketNext no buffer got "
939 "next_date=%"PRId64" ms, %d frames to play",
940 next_date/1000, i_queued_frames);
942 // means we are too early to request a new buffer?
943 waveout_warn("waiting...")
944 mwait( next_date - AOUT_MAX_PTS_ADVANCE/4 );
946 p_buffer = aout_PacketNext( p_aout, next_date );
949 if( !p_buffer && i_queued_frames )
951 /* We aren't late so no need to play a blank sample */
957 mtime_t buffer_length = p_buffer->i_length;
958 next_date = next_date + buffer_length;
961 /* Do the channel reordering */
962 if( p_buffer && p_sys->b_chan_reorder )
964 aout_ChannelReorder( p_buffer->p_buffer,
966 p_sys->waveformat.Format.nChannels,
967 p_sys->pi_chan_table,
968 p_sys->waveformat.Format.wBitsPerSample );
971 PlayWaveOut( p_aout, p_sys->h_waveout,
972 &p_waveheader[i], p_buffer, b_sleek );
978 if( vlc_atomic_get(&p_aout->sys->abort) ) return NULL;
981 deal with the case that the loop didn't fillup the buffer to the
982 max - instead of waiting that half the buffer is played before
983 fillup the waveout buffers, wait only for the next sample buffer
984 to arrive at the play method...
986 this will also avoid, that the last buffer is play until the
987 end, and then trying to get more data, so it will also
988 work - if the next buffer will arrive some ms before the
989 last buffer is finished.
991 if(i_queued_frames < FRAMES_NUM)
992 WaitForSingleObject( p_sys->new_buffer_event, INFINITE );
994 WaitForSingleObject( p_sys->event, INFINITE );
999 vlc_restorecancel (canc);
1004 static int VolumeSet( audio_output_t *aout, float volume )
1006 aout_sys_t *sys = aout->sys;
1007 const HWAVEOUT hwo = sys->h_waveout;
1008 const float full = 0xffff.fp0;
1011 if( volume >= full )
1014 sys->volume = volume;
1018 uint16_t vol = lroundf(volume);
1019 waveOutSetVolume( hwo, vol | (vol << 16) );
1023 static int MuteSet( audio_output_t * p_aout, bool mute )
1025 aout_sys_t *sys = p_aout->sys;
1026 const HWAVEOUT hwo = sys->h_waveout;
1027 uint16_t vol = mute ? 0 : lroundf(sys->volume);
1030 waveOutSetVolume( hwo, vol | (vol << 16) );
1036 reload the configuration drop down list, of the Audio Devices
1038 static int ReloadWaveoutDevices( vlc_object_t *p_this, char const *psz_name,
1039 char ***values, char ***descs )
1041 int n = 0, nb_devices = waveOutGetNumDevs();
1043 VLC_UNUSED( psz_name );
1045 *values = xmalloc( (nb_devices + 1) * sizeof(char *) );
1046 *descs = xmalloc( (nb_devices + 1) * sizeof(char *) );
1048 (*values)[n] = strdup( "wavemapper" );
1049 (*descs)[n] = strdup( _("Microsoft Soundmapper") );
1052 for(int i = 0; i < nb_devices; i++)
1055 wchar_t dev_name[MAXPNAMELEN+32];
1057 if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
1058 != MMSYSERR_NOERROR)
1061 _snwprintf(dev_name, MAXPNAMELEN + 32, device_name_fmt,
1062 caps.szPname, caps.wMid, caps.wPid);
1063 (*values)[n] = FromWide( dev_name );
1064 (*descs)[n] = strdup( (*values)[n] );
1072 convert devicename to device ID for output
1073 if device not found return WAVE_MAPPER, so let
1074 windows decide which preferred audio device
1077 static uint32_t findDeviceID(char *psz_device_name)
1079 if( !psz_device_name )
1082 uint32_t wave_devices = waveOutGetNumDevs();
1084 for( uint32_t i = 0; i < wave_devices; i++ )
1087 wchar_t dev_name[MAXPNAMELEN+32];
1089 if( waveOutGetDevCaps( i, &caps, sizeof(WAVEOUTCAPS) )
1090 != MMSYSERR_NOERROR )
1093 _snwprintf( dev_name, MAXPNAMELEN + 32, device_name_fmt,
1094 caps.szPname, caps.wMid, caps.wPid );
1095 char *u8 = FromWide(dev_name);
1096 if( !stricmp(u8, psz_device_name) )