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 );
299 /* Check for hardware volume support */
300 if( waveOutGetDevCaps( (UINT_PTR)p_aout->sys->h_waveout,
301 &wocaps, sizeof(wocaps) ) == MMSYSERR_NOERROR
302 && (wocaps.dwSupport & WAVECAPS_VOLUME) )
304 p_aout->volume_set = VolumeSet;
305 p_aout->mute_set = MuteSet;
306 p_aout->sys->volume = 0xffff.fp0;
307 p_aout->sys->mute = false;
310 aout_SoftVolumeInit( p_aout );
313 waveOutReset( p_aout->sys->h_waveout );
315 /* Allocate silence buffer */
316 p_aout->sys->p_silence_buffer =
317 malloc( p_aout->sys->i_buffer_size );
318 if( p_aout->sys->p_silence_buffer == NULL )
320 aout_PacketDestroy( p_aout );
324 p_aout->sys->i_repeat_counter = 0;
327 /* Zero the buffer. WinCE doesn't have calloc(). */
328 memset( p_aout->sys->p_silence_buffer, 0,
329 p_aout->sys->i_buffer_size );
331 /* Now we need to setup our waveOut play notification structure */
332 p_aout->sys->event = CreateEvent( NULL, FALSE, FALSE, NULL );
333 p_aout->sys->new_buffer_event = CreateEvent( NULL, FALSE, FALSE, NULL );
335 /* define startpoint of playback on first call to play()
336 like alsa does (instead of playing a blank sample) */
337 p_aout->sys->b_playing = 0;
338 p_aout->sys->start_date = 0;
341 /* Then launch the notification thread */
342 vlc_atomic_set( &p_aout->sys->abort, 0);
343 if( vlc_clone( &p_aout->sys->thread,
344 WaveOutThread, p_aout, VLC_THREAD_PRIORITY_OUTPUT ) )
346 msg_Err( p_aout, "cannot create WaveOutThread" );
349 /* We need to kick off the playback in order to have the callback properly
351 for( int i = 0; i < FRAMES_NUM; i++ )
353 p_aout->sys->waveheader[i].dwFlags = WHDR_DONE;
354 p_aout->sys->waveheader[i].dwUser = 0;
360 /*****************************************************************************
361 * Probe: probe the audio device for available formats and channels
362 *****************************************************************************/
363 static void Probe( audio_output_t * p_aout )
365 vlc_value_t val, text;
366 vlc_fourcc_t i_format;
367 unsigned int i_physical_channels;
369 var_Create( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
370 text.psz_string = _("Audio Device");
371 var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
373 /* Test for 5.1 support */
374 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
375 AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
376 AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE;
377 if( p_aout->format.i_physical_channels == i_physical_channels )
379 if( OpenWaveOutPCM( p_aout,
380 p_aout->sys->i_wave_device_id,
382 i_physical_channels, 6,
383 p_aout->format.i_rate, true )
386 val.i_int = AOUT_VAR_5_1;
387 text.psz_string = (char *)_("5.1");
388 var_Change( p_aout, "audio-device",
389 VLC_VAR_ADDCHOICE, &val, &text );
390 msg_Dbg( p_aout, "device supports 5.1 channels" );
394 /* Test for 2 Front 2 Rear support */
395 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
396 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
397 if( ( p_aout->format.i_physical_channels & i_physical_channels )
398 == i_physical_channels )
400 if( OpenWaveOutPCM( p_aout,
401 p_aout->sys->i_wave_device_id,
403 i_physical_channels, 4,
404 p_aout->format.i_rate, true )
407 val.i_int = AOUT_VAR_2F2R;
408 text.psz_string = (char *)_("2 Front 2 Rear");
409 var_Change( p_aout, "audio-device",
410 VLC_VAR_ADDCHOICE, &val, &text );
411 msg_Dbg( p_aout, "device supports 4 channels" );
415 /* Test for stereo support */
416 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
417 if( OpenWaveOutPCM( p_aout,
418 p_aout->sys->i_wave_device_id,
420 i_physical_channels, 2,
421 p_aout->format.i_rate, true )
424 val.i_int = AOUT_VAR_STEREO;
425 text.psz_string = (char *)_("Stereo");
426 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
427 msg_Dbg( p_aout, "device supports 2 channels" );
430 /* Test for mono support */
431 i_physical_channels = AOUT_CHAN_CENTER;
432 if( OpenWaveOutPCM( p_aout,
433 p_aout->sys->i_wave_device_id,
435 i_physical_channels, 1,
436 p_aout->format.i_rate, true )
439 val.i_int = AOUT_VAR_MONO;
440 text.psz_string = (char *)_("Mono");
441 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
442 msg_Dbg( p_aout, "device supports 1 channel" );
445 /* Test for SPDIF support */
446 if ( AOUT_FMT_SPDIF( &p_aout->format ) )
448 if( OpenWaveOut( p_aout,
449 p_aout->sys->i_wave_device_id,
451 p_aout->format.i_physical_channels,
452 aout_FormatNbChannels( &p_aout->format ),
453 p_aout->format.i_rate, true )
456 msg_Dbg( p_aout, "device supports A/52 over S/PDIF" );
457 val.i_int = AOUT_VAR_SPDIF;
458 text.psz_string = (char *)_("A/52 over S/PDIF");
459 var_Change( p_aout, "audio-device",
460 VLC_VAR_ADDCHOICE, &val, &text );
461 if( var_InheritBool( p_aout, "spdif" ) )
462 var_Set( p_aout, "audio-device", val );
466 var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
469 /* Probe() has failed. */
470 var_Destroy( p_aout, "audio-device" );
474 var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
477 /*****************************************************************************
478 * Play: play a sound buffer
479 *****************************************************************************
480 * This doesn't actually play the buffer. This just stores the buffer so it
481 * can be played by the callback thread.
482 *****************************************************************************/
483 static void Play( audio_output_t *_p_aout, block_t *block,
484 mtime_t *restrict drift )
486 if( !_p_aout->sys->b_playing )
488 _p_aout->sys->b_playing = 1;
490 /* get the playing date of the first aout buffer */
491 _p_aout->sys->start_date = block->i_pts;
493 msg_Dbg( _p_aout, "Wakeup sleeping output thread.");
495 /* wake up the audio output thread */
496 SetEvent( _p_aout->sys->event );
498 SetEvent( _p_aout->sys->new_buffer_event );
501 aout_PacketPlay( _p_aout, block, drift );
504 /*****************************************************************************
505 * Close: close the audio device
506 *****************************************************************************/
507 static void Close( vlc_object_t *p_this )
509 audio_output_t *p_aout = (audio_output_t *)p_this;
510 aout_sys_t *p_sys = p_aout->sys;
512 /* Before calling waveOutClose we must reset the device */
513 vlc_atomic_set( &p_sys->abort, 1);
515 /* wake up the audio thread, to recognize that p_aout died */
516 SetEvent( p_sys->event );
517 SetEvent( p_sys->new_buffer_event );
519 vlc_join( p_sys->thread, NULL );
522 kill the real output then - when the feed thread
523 is surely terminated!
524 old code could be too early in case that "feeding"
525 was running on termination
527 at this point now its sure, that there will be no new
528 data send to the driver, and we can cancel the last
531 MMRESULT result = waveOutReset( p_sys->h_waveout );
532 if(result != MMSYSERR_NOERROR)
534 msg_Err( p_aout, "waveOutReset failed 0x%x", result );
536 now we must wait, that all buffers are played
537 because cancel doesn't work in this case...
539 if(result == MMSYSERR_NOTSUPPORTED)
542 clear currently played (done) buffers,
543 if returnvalue > 0 (means some buffer still playing)
544 wait for the driver event callback that one buffer
545 is finished with playing, and check again
546 the timeout of 5000ms is just, an emergency exit
547 of this loop, to avoid deadlock in case of other
548 (currently not known bugs, problems, errors cases?)
551 (WaveOutClearDoneBuffers( p_sys ) > 0)
553 (WaitForSingleObject( p_sys->event, 5000) == WAIT_OBJECT_0)
556 msg_Dbg( p_aout, "Wait for waveout device...");
560 WaveOutClearDoneBuffers( p_sys );
563 /* now we can Close the device */
564 if( waveOutClose( p_sys->h_waveout ) != MMSYSERR_NOERROR )
566 msg_Err( p_aout, "waveOutClose failed" );
570 because so long, the waveout device is playing, the callback
571 could occur and need the events
573 CloseHandle( p_sys->event );
574 CloseHandle( p_sys->new_buffer_event);
576 free( p_sys->p_silence_buffer );
577 aout_PacketDestroy( p_aout );
581 /*****************************************************************************
582 * OpenWaveOut: open the waveout sound device
583 ****************************************************************************/
584 static int OpenWaveOut( audio_output_t *p_aout, uint32_t i_device_id, int i_format,
585 int i_channels, int i_nb_channels, int i_rate,
590 /* Set sound format */
592 #define waveformat p_aout->sys->waveformat
594 waveformat.dwChannelMask = 0;
595 for( unsigned i = 0; pi_vlc_chan_order_wg4[i]; i++ )
596 if( i_channels & pi_vlc_chan_order_wg4[i] )
597 waveformat.dwChannelMask |= pi_channels_in[i];
601 case VLC_CODEC_SPDIFL:
603 /* To prevent channel re-ordering */
604 waveformat.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
605 waveformat.Format.wBitsPerSample = 16;
606 waveformat.Samples.wValidBitsPerSample =
607 waveformat.Format.wBitsPerSample;
608 waveformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
609 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF;
613 waveformat.Format.wBitsPerSample = sizeof(float) * 8;
614 waveformat.Samples.wValidBitsPerSample =
615 waveformat.Format.wBitsPerSample;
616 waveformat.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
617 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
621 waveformat.Format.wBitsPerSample = 16;
622 waveformat.Samples.wValidBitsPerSample =
623 waveformat.Format.wBitsPerSample;
624 waveformat.Format.wFormatTag = WAVE_FORMAT_PCM;
625 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_PCM;
629 waveformat.Format.nChannels = i_nb_channels;
630 waveformat.Format.nSamplesPerSec = i_rate;
631 waveformat.Format.nBlockAlign =
632 waveformat.Format.wBitsPerSample / 8 * i_nb_channels;
633 waveformat.Format.nAvgBytesPerSec =
634 waveformat.Format.nSamplesPerSec * waveformat.Format.nBlockAlign;
636 /* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */
637 if( i_nb_channels <= 2 )
639 waveformat.Format.cbSize = 0;
643 waveformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
644 waveformat.Format.cbSize =
645 sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
649 msg_Dbg( p_aout, "OpenWaveDevice-ID: %u", i_device_id);
650 msg_Dbg( p_aout,"waveformat.Format.cbSize = %d",
651 waveformat.Format.cbSize);
652 msg_Dbg( p_aout,"waveformat.Format.wFormatTag = %u",
653 waveformat.Format.wFormatTag);
654 msg_Dbg( p_aout,"waveformat.Format.nChannels = %u",
655 waveformat.Format.nChannels);
656 msg_Dbg( p_aout,"waveformat.Format.nSamplesPerSec = %d",
657 (int)waveformat.Format.nSamplesPerSec);
658 msg_Dbg( p_aout,"waveformat.Format.nAvgBytesPerSec = %u",
659 (int)waveformat.Format.nAvgBytesPerSec);
660 msg_Dbg( p_aout,"waveformat.Format.nBlockAlign = %d",
661 waveformat.Format.nBlockAlign);
662 msg_Dbg( p_aout,"waveformat.Format.wBitsPerSample = %d",
663 waveformat.Format.wBitsPerSample);
664 msg_Dbg( p_aout,"waveformat.Samples.wValidBitsPerSample = %d",
665 waveformat.Samples.wValidBitsPerSample);
666 msg_Dbg( p_aout,"waveformat.Samples.wSamplesPerBlock = %d",
667 waveformat.Samples.wSamplesPerBlock);
668 msg_Dbg( p_aout,"waveformat.dwChannelMask = %lu",
669 waveformat.dwChannelMask);
672 /* Open the device */
673 result = waveOutOpen( &p_aout->sys->h_waveout, i_device_id,
674 (WAVEFORMATEX *)&waveformat,
675 (DWORD_PTR)WaveOutCallback, (DWORD_PTR)p_aout,
676 CALLBACK_FUNCTION | (b_probe?WAVE_FORMAT_QUERY:0) );
677 if( result == WAVERR_BADFORMAT )
679 msg_Warn( p_aout, "waveOutOpen failed WAVERR_BADFORMAT" );
682 if( result == MMSYSERR_ALLOCATED )
684 msg_Warn( p_aout, "waveOutOpen failed WAVERR_ALLOCATED" );
687 if( result != MMSYSERR_NOERROR )
689 msg_Warn( p_aout, "waveOutOpen failed" );
693 p_aout->sys->b_chan_reorder =
694 aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
695 waveformat.dwChannelMask, i_nb_channels,
696 p_aout->sys->pi_chan_table );
698 if( p_aout->sys->b_chan_reorder )
700 msg_Dbg( p_aout, "channel reordering needed" );
709 /*****************************************************************************
710 * OpenWaveOutPCM: open a PCM waveout sound device
711 ****************************************************************************/
712 static int OpenWaveOutPCM( audio_output_t *p_aout, uint32_t i_device_id,
713 vlc_fourcc_t *i_format,
714 int i_channels, int i_nb_channels, int i_rate,
717 bool b_use_float32 = var_CreateGetBool( p_aout, "waveout-float32");
719 if( !b_use_float32 || OpenWaveOut( p_aout, i_device_id, VLC_CODEC_FL32,
720 i_channels, i_nb_channels, i_rate, b_probe )
723 if ( OpenWaveOut( p_aout, i_device_id, VLC_CODEC_S16L,
724 i_channels, i_nb_channels, i_rate, b_probe )
731 *i_format = VLC_CODEC_S16L;
737 *i_format = VLC_CODEC_FL32;
742 /*****************************************************************************
743 * PlayWaveOut: play a buffer through the WaveOut device
744 *****************************************************************************/
745 static int PlayWaveOut( audio_output_t *p_aout, HWAVEOUT h_waveout,
746 WAVEHDR *p_waveheader, block_t *p_buffer, bool b_spdif)
750 /* Prepare the buffer */
751 if( p_buffer != NULL )
753 p_waveheader->lpData = (LPSTR)p_buffer->p_buffer;
755 copy the buffer to the silence buffer :) so in case we don't
756 get the next buffer fast enough (I will repeat this one a time
757 for AC3 / DTS and SPDIF this will sound better instead of
762 memcpy( p_aout->sys->p_silence_buffer,
764 p_aout->sys->i_buffer_size );
765 p_aout->sys->i_repeat_counter = 2;
768 /* Use silence buffer instead */
769 if(p_aout->sys->i_repeat_counter)
771 p_aout->sys->i_repeat_counter--;
772 if(!p_aout->sys->i_repeat_counter)
774 memset( p_aout->sys->p_silence_buffer,
775 0x00, p_aout->sys->i_buffer_size );
778 p_waveheader->lpData = (LPSTR)p_aout->sys->p_silence_buffer;
781 p_waveheader->dwUser = p_buffer ? (DWORD_PTR)p_buffer : (DWORD_PTR)1;
782 p_waveheader->dwBufferLength = p_aout->sys->i_buffer_size;
783 p_waveheader->dwFlags = 0;
785 result = waveOutPrepareHeader( h_waveout, p_waveheader, sizeof(WAVEHDR) );
786 if( result != MMSYSERR_NOERROR )
788 msg_Err( p_aout, "waveOutPrepareHeader failed" );
792 /* Send the buffer to the waveOut queue */
793 result = waveOutWrite( h_waveout, p_waveheader, sizeof(WAVEHDR) );
794 if( result != MMSYSERR_NOERROR )
796 msg_Err( p_aout, "waveOutWrite failed" );
803 /*****************************************************************************
804 * WaveOutCallback: what to do once WaveOut has played its sound samples
805 *****************************************************************************/
806 static void CALLBACK WaveOutCallback( HWAVEOUT h_waveout, UINT uMsg,
808 DWORD_PTR dwParam1, DWORD_PTR dwParam2 )
810 (void)h_waveout; (void)dwParam1; (void)dwParam2;
811 audio_output_t *p_aout = (audio_output_t *)_p_aout;
812 int i_queued_frames = 0;
814 if( uMsg != WOM_DONE ) return;
816 if( vlc_atomic_get(&p_aout->sys->abort) ) return;
818 /* Find out the current latency */
819 for( int i = 0; i < FRAMES_NUM; i++ )
821 /* Check if frame buf is available */
822 if( !(p_aout->sys->waveheader[i].dwFlags & WHDR_DONE) )
828 /* Don't wake up the thread too much */
829 if( i_queued_frames <= FRAMES_NUM/2 )
830 SetEvent( p_aout->sys->event );
834 /****************************************************************************
835 * WaveOutClearDoneBuffers: Clear all done marked buffers, and free buffer
836 ****************************************************************************
837 * return value is the number of still playing buffers in the queue
838 ****************************************************************************/
839 static int WaveOutClearDoneBuffers(aout_sys_t *p_sys)
841 WAVEHDR *p_waveheader = p_sys->waveheader;
842 int i_queued_frames = 0;
844 for( int i = 0; i < FRAMES_NUM; i++ )
846 if( (p_waveheader[i].dwFlags & WHDR_DONE) &&
847 p_waveheader[i].dwUser )
850 (block_t *)(p_waveheader[i].dwUser);
851 /* Unprepare and free the buffers which has just been played */
852 waveOutUnprepareHeader( p_sys->h_waveout, &p_waveheader[i],
855 if( p_waveheader[i].dwUser != 1 )
856 block_Release( p_buffer );
858 p_waveheader[i].dwUser = 0;
861 /* Check if frame buf is available */
862 if( !(p_waveheader[i].dwFlags & WHDR_DONE) )
867 return i_queued_frames;
870 /*****************************************************************************
871 * WaveOutThread: this thread will capture play notification events.
872 *****************************************************************************
873 * We use this thread to feed new audio samples to the sound card because
874 * we are not authorized to use waveOutWrite() directly in the waveout
876 *****************************************************************************/
877 static void* WaveOutThread( void *data )
879 audio_output_t *p_aout = data;
880 aout_sys_t *p_sys = p_aout->sys;
881 block_t *p_buffer = NULL;
882 WAVEHDR *p_waveheader = p_sys->waveheader;
883 int i, i_queued_frames;
886 int canc = vlc_savecancel ();
888 /* We don't want any resampling when using S/PDIF */
889 b_sleek = p_aout->format.i_format == VLC_CODEC_SPDIFL;
891 // wait for first call to "play()"
892 while( !p_sys->start_date && !vlc_atomic_get(&p_aout->sys->abort) )
893 WaitForSingleObject( p_sys->event, INFINITE );
894 if( vlc_atomic_get(&p_aout->sys->abort) )
897 msg_Dbg( p_aout, "will start to play in %"PRId64" us",
898 (p_sys->start_date - AOUT_MAX_PTS_ADVANCE/4)-mdate());
900 // than wait a short time... before grabbing first frames
901 mwait( p_sys->start_date - AOUT_MAX_PTS_ADVANCE/4 );
903 #define waveout_warn(msg) msg_Warn( p_aout, "aout_PacketNext no buffer "\
904 "got next_date=%d ms, "\
905 "%d frames to play, %s",\
906 (int)(next_date/(mtime_t)1000), \
907 i_queued_frames, msg);
910 while( !vlc_atomic_get(&p_aout->sys->abort) )
912 /* Cleanup and find out the current latency */
913 i_queued_frames = WaveOutClearDoneBuffers( p_sys );
915 if( vlc_atomic_get(&p_aout->sys->abort) ) return NULL;
917 /* Try to fill in as many frame buffers as possible */
918 for( i = 0; i < FRAMES_NUM; i++ )
920 /* Check if frame buf is available */
921 if( p_waveheader[i].dwFlags & WHDR_DONE )
923 // next_date = mdate() + 1000000 * i_queued_frames /
924 // p_aout->format.i_rate * p_aout->i_nb_samples;
926 // the realtime has got our back-site:) to come in sync
927 if(next_date < mdate())
931 /* Take into account the latency */
932 p_buffer = aout_PacketNext( p_aout, next_date );
936 msg_Dbg( p_aout, "aout_PacketNext no buffer got "
937 "next_date=%"PRId64" ms, %d frames to play",
938 next_date/1000, i_queued_frames);
940 // means we are too early to request a new buffer?
941 waveout_warn("waiting...")
942 mwait( next_date - AOUT_MAX_PTS_ADVANCE/4 );
944 p_buffer = aout_PacketNext( p_aout, next_date );
947 if( !p_buffer && i_queued_frames )
949 /* We aren't late so no need to play a blank sample */
955 mtime_t buffer_length = p_buffer->i_length;
956 next_date = next_date + buffer_length;
959 /* Do the channel reordering */
960 if( p_buffer && p_sys->b_chan_reorder )
962 aout_ChannelReorder( p_buffer->p_buffer,
964 p_sys->waveformat.Format.nChannels,
965 p_sys->pi_chan_table,
966 p_sys->waveformat.Format.wBitsPerSample );
969 PlayWaveOut( p_aout, p_sys->h_waveout,
970 &p_waveheader[i], p_buffer, b_sleek );
976 if( vlc_atomic_get(&p_aout->sys->abort) ) return NULL;
979 deal with the case that the loop didn't fillup the buffer to the
980 max - instead of waiting that half the buffer is played before
981 fillup the waveout buffers, wait only for the next sample buffer
982 to arrive at the play method...
984 this will also avoid, that the last buffer is play until the
985 end, and then trying to get more data, so it will also
986 work - if the next buffer will arrive some ms before the
987 last buffer is finished.
989 if(i_queued_frames < FRAMES_NUM)
990 WaitForSingleObject( p_sys->new_buffer_event, INFINITE );
992 WaitForSingleObject( p_sys->event, INFINITE );
997 vlc_restorecancel (canc);
1001 static int VolumeSet( audio_output_t *aout, float volume )
1003 aout_sys_t *sys = aout->sys;
1004 const HWAVEOUT hwo = sys->h_waveout;
1005 const float full = 0xffff.fp0;
1008 if( volume >= full )
1011 sys->volume = volume;
1015 uint16_t vol = lroundf(volume);
1016 waveOutSetVolume( hwo, vol | (vol << 16) );
1020 static int MuteSet( audio_output_t * p_aout, bool mute )
1022 aout_sys_t *sys = p_aout->sys;
1023 const HWAVEOUT hwo = sys->h_waveout;
1024 uint16_t vol = mute ? 0 : lroundf(sys->volume);
1027 waveOutSetVolume( hwo, vol | (vol << 16) );
1032 reload the configuration drop down list, of the Audio Devices
1034 static int ReloadWaveoutDevices( vlc_object_t *p_this, char const *psz_name,
1035 char ***values, char ***descs )
1037 int n = 0, nb_devices = waveOutGetNumDevs();
1039 VLC_UNUSED( psz_name );
1041 *values = xmalloc( (nb_devices + 1) * sizeof(char *) );
1042 *descs = xmalloc( (nb_devices + 1) * sizeof(char *) );
1044 (*values)[n] = strdup( "wavemapper" );
1045 (*descs)[n] = strdup( _("Microsoft Soundmapper") );
1048 for(int i = 0; i < nb_devices; i++)
1051 wchar_t dev_name[MAXPNAMELEN+32];
1053 if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
1054 != MMSYSERR_NOERROR)
1057 _snwprintf(dev_name, MAXPNAMELEN + 32, device_name_fmt,
1058 caps.szPname, caps.wMid, caps.wPid);
1059 (*values)[n] = FromWide( dev_name );
1060 (*descs)[n] = strdup( (*values)[n] );
1068 convert devicename to device ID for output
1069 if device not found return WAVE_MAPPER, so let
1070 windows decide which preferred audio device
1073 static uint32_t findDeviceID(char *psz_device_name)
1075 if( !psz_device_name )
1078 uint32_t wave_devices = waveOutGetNumDevs();
1080 for( uint32_t i = 0; i < wave_devices; i++ )
1083 wchar_t dev_name[MAXPNAMELEN+32];
1085 if( waveOutGetDevCaps( i, &caps, sizeof(WAVEOUTCAPS) )
1086 != MMSYSERR_NOERROR )
1089 _snwprintf( dev_name, MAXPNAMELEN + 32, device_name_fmt,
1090 caps.szPname, caps.wMid, caps.wPid );
1091 char *u8 = FromWide(dev_name);
1092 if( !stricmp(u8, psz_device_name) )