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 )
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 initialize/update Device selection List
178 ReloadWaveoutDevices( p_this, "waveout-audio-device", val, val, NULL);
181 check for configured audio device!
183 char *psz_waveout_dev = var_CreateGetString( p_aout, "waveout-audio-device");
185 p_aout->sys->i_wave_device_id =
186 findDeviceID( psz_waveout_dev );
188 if(p_aout->sys->i_wave_device_id == WAVE_MAPPER)
190 if(psz_waveout_dev &&
191 stricmp(psz_waveout_dev,"wavemapper"))
193 msg_Warn( p_aout, "configured audio device '%s' not available, "\
194 "use default instead", psz_waveout_dev );
197 free( psz_waveout_dev );
200 WAVEOUTCAPS waveoutcaps;
201 if(waveOutGetDevCaps( p_aout->sys->i_wave_device_id,
203 sizeof(WAVEOUTCAPS)) == MMSYSERR_NOERROR)
205 /* log debug some infos about driver, to know who to blame
206 if it doesn't work */
207 msg_Dbg( p_aout, "Drivername: %ls", waveoutcaps.szPname);
208 msg_Dbg( p_aout, "Driver Version: %d.%d",
209 (waveoutcaps.vDriverVersion>>8)&255,
210 waveoutcaps.vDriverVersion & 255);
211 msg_Dbg( p_aout, "Manufacturer identifier: 0x%x", waveoutcaps.wMid );
212 msg_Dbg( p_aout, "Product identifier: 0x%x", waveoutcaps.wPid );
217 if( var_Type( p_aout, "audio-device" ) == 0 )
222 if( var_Get( p_aout, "audio-device", &val ) < 0 )
224 /* Probe() has failed. */
225 var_Destroy( p_aout, "waveout-audio-device");
231 /* Open the device */
232 if( val.i_int == AOUT_VAR_SPDIF )
234 p_aout->format.i_format = VLC_CODEC_SPDIFL;
236 if( OpenWaveOut( p_aout,
237 p_aout->sys->i_wave_device_id,
239 p_aout->format.i_physical_channels,
240 aout_FormatNbChannels( &p_aout->format ),
241 p_aout->format.i_rate, false )
244 msg_Err( p_aout, "cannot open waveout audio device" );
249 /* Calculate the frame size in bytes */
250 p_aout->format.i_bytes_per_frame = AOUT_SPDIF_SIZE;
251 p_aout->format.i_frame_length = A52_FRAME_NB;
252 p_aout->sys->i_buffer_size =
253 p_aout->format.i_bytes_per_frame;
255 aout_PacketInit( p_aout, &p_aout->sys->packet, A52_FRAME_NB );
256 p_aout->volume_set = NULL;
257 p_aout->mute_set = NULL;
266 p_aout->format.i_physical_channels
267 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
268 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
272 p_aout->format.i_physical_channels
273 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
274 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
277 p_aout->format.i_physical_channels = AOUT_CHAN_CENTER;
280 p_aout->format.i_physical_channels
281 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
284 if( OpenWaveOutPCM( p_aout,
285 p_aout->sys->i_wave_device_id,
286 &p_aout->format.i_format,
287 p_aout->format.i_physical_channels,
288 aout_FormatNbChannels( &p_aout->format ),
289 p_aout->format.i_rate, false )
292 msg_Err( p_aout, "cannot open waveout audio device" );
297 /* Calculate the frame size in bytes */
298 aout_FormatPrepare( &p_aout->format );
299 p_aout->sys->i_buffer_size = FRAME_SIZE *
300 p_aout->format.i_bytes_per_frame;
302 aout_PacketInit( p_aout, &p_aout->sys->packet, FRAME_SIZE );
305 /* Check for hardware volume support */
306 if( waveOutGetDevCaps( (UINT_PTR)p_aout->sys->h_waveout,
307 &wocaps, sizeof(wocaps) ) == MMSYSERR_NOERROR
308 && (wocaps.dwSupport & WAVECAPS_VOLUME) )
310 p_aout->volume_set = VolumeSet;
311 p_aout->mute_set = MuteSet;
312 p_aout->sys->volume = 0xffff.fp0;
313 p_aout->sys->mute = false;
317 aout_SoftVolumeInit( p_aout );
320 waveOutReset( p_aout->sys->h_waveout );
322 /* Allocate silence buffer */
323 p_aout->sys->p_silence_buffer =
324 malloc( p_aout->sys->i_buffer_size );
325 if( p_aout->sys->p_silence_buffer == NULL )
327 aout_PacketDestroy( p_aout );
331 p_aout->sys->i_repeat_counter = 0;
334 /* Zero the buffer. WinCE doesn't have calloc(). */
335 memset( p_aout->sys->p_silence_buffer, 0,
336 p_aout->sys->i_buffer_size );
338 /* Now we need to setup our waveOut play notification structure */
339 p_aout->sys->event = CreateEvent( NULL, FALSE, FALSE, NULL );
340 p_aout->sys->new_buffer_event = CreateEvent( NULL, FALSE, FALSE, NULL );
342 /* define startpoint of playback on first call to play()
343 like alsa does (instead of playing a blank sample) */
344 p_aout->sys->b_playing = 0;
345 p_aout->sys->start_date = 0;
348 /* Then launch the notification thread */
349 vlc_atomic_set( &p_aout->sys->abort, 0);
350 if( vlc_clone( &p_aout->sys->thread,
351 WaveOutThread, p_aout, VLC_THREAD_PRIORITY_OUTPUT ) )
353 msg_Err( p_aout, "cannot create WaveOutThread" );
356 /* We need to kick off the playback in order to have the callback properly
358 for( int i = 0; i < FRAMES_NUM; i++ )
360 p_aout->sys->waveheader[i].dwFlags = WHDR_DONE;
361 p_aout->sys->waveheader[i].dwUser = 0;
367 /*****************************************************************************
368 * Probe: probe the audio device for available formats and channels
369 *****************************************************************************/
370 static void Probe( audio_output_t * p_aout )
372 vlc_value_t val, text;
373 vlc_fourcc_t i_format;
374 unsigned int i_physical_channels;
376 var_Create( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
377 text.psz_string = _("Audio Device");
378 var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
380 /* Test for 5.1 support */
381 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
382 AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
383 AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE;
384 if( p_aout->format.i_physical_channels == i_physical_channels )
386 if( OpenWaveOutPCM( p_aout,
387 p_aout->sys->i_wave_device_id,
389 i_physical_channels, 6,
390 p_aout->format.i_rate, true )
393 val.i_int = AOUT_VAR_5_1;
394 text.psz_string = (char *)_("5.1");
395 var_Change( p_aout, "audio-device",
396 VLC_VAR_ADDCHOICE, &val, &text );
397 msg_Dbg( p_aout, "device supports 5.1 channels" );
401 /* Test for 2 Front 2 Rear support */
402 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
403 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
404 if( ( p_aout->format.i_physical_channels & i_physical_channels )
405 == i_physical_channels )
407 if( OpenWaveOutPCM( p_aout,
408 p_aout->sys->i_wave_device_id,
410 i_physical_channels, 4,
411 p_aout->format.i_rate, true )
414 val.i_int = AOUT_VAR_2F2R;
415 text.psz_string = (char *)_("2 Front 2 Rear");
416 var_Change( p_aout, "audio-device",
417 VLC_VAR_ADDCHOICE, &val, &text );
418 msg_Dbg( p_aout, "device supports 4 channels" );
422 /* Test for stereo support */
423 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
424 if( OpenWaveOutPCM( p_aout,
425 p_aout->sys->i_wave_device_id,
427 i_physical_channels, 2,
428 p_aout->format.i_rate, true )
431 val.i_int = AOUT_VAR_STEREO;
432 text.psz_string = (char *)_("Stereo");
433 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
434 msg_Dbg( p_aout, "device supports 2 channels" );
437 /* Test for mono support */
438 i_physical_channels = AOUT_CHAN_CENTER;
439 if( OpenWaveOutPCM( p_aout,
440 p_aout->sys->i_wave_device_id,
442 i_physical_channels, 1,
443 p_aout->format.i_rate, true )
446 val.i_int = AOUT_VAR_MONO;
447 text.psz_string = (char *)_("Mono");
448 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
449 msg_Dbg( p_aout, "device supports 1 channel" );
452 /* Test for SPDIF support */
453 if ( AOUT_FMT_SPDIF( &p_aout->format ) )
455 if( OpenWaveOut( p_aout,
456 p_aout->sys->i_wave_device_id,
458 p_aout->format.i_physical_channels,
459 aout_FormatNbChannels( &p_aout->format ),
460 p_aout->format.i_rate, true )
463 msg_Dbg( p_aout, "device supports A/52 over S/PDIF" );
464 val.i_int = AOUT_VAR_SPDIF;
465 text.psz_string = (char *)_("A/52 over S/PDIF");
466 var_Change( p_aout, "audio-device",
467 VLC_VAR_ADDCHOICE, &val, &text );
468 if( var_InheritBool( p_aout, "spdif" ) )
469 var_Set( p_aout, "audio-device", val );
473 var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
476 /* Probe() has failed. */
477 var_Destroy( p_aout, "audio-device" );
481 var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
484 /*****************************************************************************
485 * Play: play a sound buffer
486 *****************************************************************************
487 * This doesn't actually play the buffer. This just stores the buffer so it
488 * can be played by the callback thread.
489 *****************************************************************************/
490 static void Play( audio_output_t *_p_aout, block_t *block,
491 mtime_t *restrict drift )
493 if( !_p_aout->sys->b_playing )
495 _p_aout->sys->b_playing = 1;
497 /* get the playing date of the first aout buffer */
498 _p_aout->sys->start_date = block->i_pts;
500 msg_Dbg( _p_aout, "Wakeup sleeping output thread.");
502 /* wake up the audio output thread */
503 SetEvent( _p_aout->sys->event );
505 SetEvent( _p_aout->sys->new_buffer_event );
508 aout_PacketPlay( _p_aout, block, drift );
511 /*****************************************************************************
512 * Close: close the audio device
513 *****************************************************************************/
514 static void Close( vlc_object_t *p_this )
516 audio_output_t *p_aout = (audio_output_t *)p_this;
517 aout_sys_t *p_sys = p_aout->sys;
519 /* Before calling waveOutClose we must reset the device */
520 vlc_atomic_set( &p_sys->abort, 1);
522 /* wake up the audio thread, to recognize that p_aout died */
523 SetEvent( p_sys->event );
524 SetEvent( p_sys->new_buffer_event );
526 vlc_join( p_sys->thread, NULL );
529 kill the real output then - when the feed thread
530 is surely terminated!
531 old code could be too early in case that "feeding"
532 was running on termination
534 at this point now its sure, that there will be no new
535 data send to the driver, and we can cancel the last
538 MMRESULT result = waveOutReset( p_sys->h_waveout );
539 if(result != MMSYSERR_NOERROR)
541 msg_Err( p_aout, "waveOutReset failed 0x%x", result );
543 now we must wait, that all buffers are played
544 because cancel doesn't work in this case...
546 if(result == MMSYSERR_NOTSUPPORTED)
549 clear currently played (done) buffers,
550 if returnvalue > 0 (means some buffer still playing)
551 wait for the driver event callback that one buffer
552 is finished with playing, and check again
553 the timeout of 5000ms is just, an emergency exit
554 of this loop, to avoid deadlock in case of other
555 (currently not known bugs, problems, errors cases?)
558 (WaveOutClearDoneBuffers( p_sys ) > 0)
560 (WaitForSingleObject( p_sys->event, 5000) == WAIT_OBJECT_0)
563 msg_Dbg( p_aout, "Wait for waveout device...");
567 WaveOutClearDoneBuffers( p_sys );
570 /* now we can Close the device */
571 if( waveOutClose( p_sys->h_waveout ) != MMSYSERR_NOERROR )
573 msg_Err( p_aout, "waveOutClose failed" );
577 because so long, the waveout device is playing, the callback
578 could occur and need the events
580 CloseHandle( p_sys->event );
581 CloseHandle( p_sys->new_buffer_event);
583 free( p_sys->p_silence_buffer );
584 aout_PacketDestroy( p_aout );
588 /*****************************************************************************
589 * OpenWaveOut: open the waveout sound device
590 ****************************************************************************/
591 static int OpenWaveOut( audio_output_t *p_aout, uint32_t i_device_id, int i_format,
592 int i_channels, int i_nb_channels, int i_rate,
597 /* Set sound format */
599 #define waveformat p_aout->sys->waveformat
601 waveformat.dwChannelMask = 0;
602 for( unsigned i = 0; pi_vlc_chan_order_wg4[i]; i++ )
603 if( i_channels & pi_vlc_chan_order_wg4[i] )
604 waveformat.dwChannelMask |= pi_channels_in[i];
608 case VLC_CODEC_SPDIFL:
610 /* To prevent channel re-ordering */
611 waveformat.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
612 waveformat.Format.wBitsPerSample = 16;
613 waveformat.Samples.wValidBitsPerSample =
614 waveformat.Format.wBitsPerSample;
615 waveformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
616 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF;
620 waveformat.Format.wBitsPerSample = sizeof(float) * 8;
621 waveformat.Samples.wValidBitsPerSample =
622 waveformat.Format.wBitsPerSample;
623 waveformat.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
624 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
628 waveformat.Format.wBitsPerSample = 16;
629 waveformat.Samples.wValidBitsPerSample =
630 waveformat.Format.wBitsPerSample;
631 waveformat.Format.wFormatTag = WAVE_FORMAT_PCM;
632 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_PCM;
636 waveformat.Format.nChannels = i_nb_channels;
637 waveformat.Format.nSamplesPerSec = i_rate;
638 waveformat.Format.nBlockAlign =
639 waveformat.Format.wBitsPerSample / 8 * i_nb_channels;
640 waveformat.Format.nAvgBytesPerSec =
641 waveformat.Format.nSamplesPerSec * waveformat.Format.nBlockAlign;
643 /* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */
644 if( i_nb_channels <= 2 )
646 waveformat.Format.cbSize = 0;
650 waveformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
651 waveformat.Format.cbSize =
652 sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
656 msg_Dbg( p_aout, "OpenWaveDevice-ID: %u", i_device_id);
657 msg_Dbg( p_aout,"waveformat.Format.cbSize = %d",
658 waveformat.Format.cbSize);
659 msg_Dbg( p_aout,"waveformat.Format.wFormatTag = %u",
660 waveformat.Format.wFormatTag);
661 msg_Dbg( p_aout,"waveformat.Format.nChannels = %u",
662 waveformat.Format.nChannels);
663 msg_Dbg( p_aout,"waveformat.Format.nSamplesPerSec = %d",
664 (int)waveformat.Format.nSamplesPerSec);
665 msg_Dbg( p_aout,"waveformat.Format.nAvgBytesPerSec = %u",
666 (int)waveformat.Format.nAvgBytesPerSec);
667 msg_Dbg( p_aout,"waveformat.Format.nBlockAlign = %d",
668 waveformat.Format.nBlockAlign);
669 msg_Dbg( p_aout,"waveformat.Format.wBitsPerSample = %d",
670 waveformat.Format.wBitsPerSample);
671 msg_Dbg( p_aout,"waveformat.Samples.wValidBitsPerSample = %d",
672 waveformat.Samples.wValidBitsPerSample);
673 msg_Dbg( p_aout,"waveformat.Samples.wSamplesPerBlock = %d",
674 waveformat.Samples.wSamplesPerBlock);
675 msg_Dbg( p_aout,"waveformat.dwChannelMask = %lu",
676 waveformat.dwChannelMask);
679 /* Open the device */
680 result = waveOutOpen( &p_aout->sys->h_waveout, i_device_id,
681 (WAVEFORMATEX *)&waveformat,
682 (DWORD_PTR)WaveOutCallback, (DWORD_PTR)p_aout,
683 CALLBACK_FUNCTION | (b_probe?WAVE_FORMAT_QUERY:0) );
684 if( result == WAVERR_BADFORMAT )
686 msg_Warn( p_aout, "waveOutOpen failed WAVERR_BADFORMAT" );
689 if( result == MMSYSERR_ALLOCATED )
691 msg_Warn( p_aout, "waveOutOpen failed WAVERR_ALLOCATED" );
694 if( result != MMSYSERR_NOERROR )
696 msg_Warn( p_aout, "waveOutOpen failed" );
700 p_aout->sys->b_chan_reorder =
701 aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
702 waveformat.dwChannelMask, i_nb_channels,
703 p_aout->sys->pi_chan_table );
705 if( p_aout->sys->b_chan_reorder )
707 msg_Dbg( p_aout, "channel reordering needed" );
716 /*****************************************************************************
717 * OpenWaveOutPCM: open a PCM waveout sound device
718 ****************************************************************************/
719 static int OpenWaveOutPCM( audio_output_t *p_aout, uint32_t i_device_id,
720 vlc_fourcc_t *i_format,
721 int i_channels, int i_nb_channels, int i_rate,
724 bool b_use_float32 = var_CreateGetBool( p_aout, "waveout-float32");
726 if( !b_use_float32 || OpenWaveOut( p_aout, i_device_id, VLC_CODEC_FL32,
727 i_channels, i_nb_channels, i_rate, b_probe )
730 if ( OpenWaveOut( p_aout, i_device_id, VLC_CODEC_S16L,
731 i_channels, i_nb_channels, i_rate, b_probe )
738 *i_format = VLC_CODEC_S16L;
744 *i_format = VLC_CODEC_FL32;
749 /*****************************************************************************
750 * PlayWaveOut: play a buffer through the WaveOut device
751 *****************************************************************************/
752 static int PlayWaveOut( audio_output_t *p_aout, HWAVEOUT h_waveout,
753 WAVEHDR *p_waveheader, block_t *p_buffer, bool b_spdif)
757 /* Prepare the buffer */
758 if( p_buffer != NULL )
760 p_waveheader->lpData = (LPSTR)p_buffer->p_buffer;
762 copy the buffer to the silence buffer :) so in case we don't
763 get the next buffer fast enough (I will repeat this one a time
764 for AC3 / DTS and SPDIF this will sound better instead of
769 memcpy( p_aout->sys->p_silence_buffer,
771 p_aout->sys->i_buffer_size );
772 p_aout->sys->i_repeat_counter = 2;
775 /* Use silence buffer instead */
776 if(p_aout->sys->i_repeat_counter)
778 p_aout->sys->i_repeat_counter--;
779 if(!p_aout->sys->i_repeat_counter)
781 memset( p_aout->sys->p_silence_buffer,
782 0x00, p_aout->sys->i_buffer_size );
785 p_waveheader->lpData = (LPSTR)p_aout->sys->p_silence_buffer;
788 p_waveheader->dwUser = p_buffer ? (DWORD_PTR)p_buffer : (DWORD_PTR)1;
789 p_waveheader->dwBufferLength = p_aout->sys->i_buffer_size;
790 p_waveheader->dwFlags = 0;
792 result = waveOutPrepareHeader( h_waveout, p_waveheader, sizeof(WAVEHDR) );
793 if( result != MMSYSERR_NOERROR )
795 msg_Err( p_aout, "waveOutPrepareHeader failed" );
799 /* Send the buffer to the waveOut queue */
800 result = waveOutWrite( h_waveout, p_waveheader, sizeof(WAVEHDR) );
801 if( result != MMSYSERR_NOERROR )
803 msg_Err( p_aout, "waveOutWrite failed" );
810 /*****************************************************************************
811 * WaveOutCallback: what to do once WaveOut has played its sound samples
812 *****************************************************************************/
813 static void CALLBACK WaveOutCallback( HWAVEOUT h_waveout, UINT uMsg,
815 DWORD_PTR dwParam1, DWORD_PTR dwParam2 )
817 (void)h_waveout; (void)dwParam1; (void)dwParam2;
818 audio_output_t *p_aout = (audio_output_t *)_p_aout;
819 int i_queued_frames = 0;
821 if( uMsg != WOM_DONE ) return;
823 if( vlc_atomic_get(&p_aout->sys->abort) ) return;
825 /* Find out the current latency */
826 for( int i = 0; i < FRAMES_NUM; i++ )
828 /* Check if frame buf is available */
829 if( !(p_aout->sys->waveheader[i].dwFlags & WHDR_DONE) )
835 /* Don't wake up the thread too much */
836 if( i_queued_frames <= FRAMES_NUM/2 )
837 SetEvent( p_aout->sys->event );
841 /****************************************************************************
842 * WaveOutClearDoneBuffers: Clear all done marked buffers, and free buffer
843 ****************************************************************************
844 * return value is the number of still playing buffers in the queue
845 ****************************************************************************/
846 static int WaveOutClearDoneBuffers(aout_sys_t *p_sys)
848 WAVEHDR *p_waveheader = p_sys->waveheader;
849 int i_queued_frames = 0;
851 for( int i = 0; i < FRAMES_NUM; i++ )
853 if( (p_waveheader[i].dwFlags & WHDR_DONE) &&
854 p_waveheader[i].dwUser )
857 (block_t *)(p_waveheader[i].dwUser);
858 /* Unprepare and free the buffers which has just been played */
859 waveOutUnprepareHeader( p_sys->h_waveout, &p_waveheader[i],
862 if( p_waveheader[i].dwUser != 1 )
863 block_Release( p_buffer );
865 p_waveheader[i].dwUser = 0;
868 /* Check if frame buf is available */
869 if( !(p_waveheader[i].dwFlags & WHDR_DONE) )
874 return i_queued_frames;
877 /*****************************************************************************
878 * WaveOutThread: this thread will capture play notification events.
879 *****************************************************************************
880 * We use this thread to feed new audio samples to the sound card because
881 * we are not authorized to use waveOutWrite() directly in the waveout
883 *****************************************************************************/
884 static void* WaveOutThread( void *data )
886 audio_output_t *p_aout = data;
887 aout_sys_t *p_sys = p_aout->sys;
888 block_t *p_buffer = NULL;
889 WAVEHDR *p_waveheader = p_sys->waveheader;
890 int i, i_queued_frames;
893 int canc = vlc_savecancel ();
895 /* We don't want any resampling when using S/PDIF */
896 b_sleek = p_aout->format.i_format == VLC_CODEC_SPDIFL;
898 // wait for first call to "play()"
899 while( !p_sys->start_date && !vlc_atomic_get(&p_aout->sys->abort) )
900 WaitForSingleObject( p_sys->event, INFINITE );
901 if( vlc_atomic_get(&p_aout->sys->abort) )
904 msg_Dbg( p_aout, "will start to play in %"PRId64" us",
905 (p_sys->start_date - AOUT_MAX_PTS_ADVANCE/4)-mdate());
907 // than wait a short time... before grabbing first frames
908 mwait( p_sys->start_date - AOUT_MAX_PTS_ADVANCE/4 );
910 #define waveout_warn(msg) msg_Warn( p_aout, "aout_PacketNext no buffer "\
911 "got next_date=%d ms, "\
912 "%d frames to play, %s",\
913 (int)(next_date/(mtime_t)1000), \
914 i_queued_frames, msg);
917 while( !vlc_atomic_get(&p_aout->sys->abort) )
919 /* Cleanup and find out the current latency */
920 i_queued_frames = WaveOutClearDoneBuffers( p_sys );
922 if( vlc_atomic_get(&p_aout->sys->abort) ) return NULL;
924 /* Try to fill in as many frame buffers as possible */
925 for( i = 0; i < FRAMES_NUM; i++ )
927 /* Check if frame buf is available */
928 if( p_waveheader[i].dwFlags & WHDR_DONE )
930 // next_date = mdate() + 1000000 * i_queued_frames /
931 // p_aout->format.i_rate * p_aout->i_nb_samples;
933 // the realtime has got our back-site:) to come in sync
934 if(next_date < mdate())
938 /* Take into account the latency */
939 p_buffer = aout_PacketNext( p_aout, next_date );
943 msg_Dbg( p_aout, "aout_PacketNext no buffer got "
944 "next_date=%"PRId64" ms, %d frames to play",
945 next_date/1000, i_queued_frames);
947 // means we are too early to request a new buffer?
948 waveout_warn("waiting...")
949 mwait( next_date - AOUT_MAX_PTS_ADVANCE/4 );
951 p_buffer = aout_PacketNext( p_aout, next_date );
954 if( !p_buffer && i_queued_frames )
956 /* We aren't late so no need to play a blank sample */
962 mtime_t buffer_length = p_buffer->i_length;
963 next_date = next_date + buffer_length;
966 /* Do the channel reordering */
967 if( p_buffer && p_sys->b_chan_reorder )
969 aout_ChannelReorder( p_buffer->p_buffer,
971 p_sys->waveformat.Format.nChannels,
972 p_sys->pi_chan_table,
973 p_sys->waveformat.Format.wBitsPerSample );
976 PlayWaveOut( p_aout, p_sys->h_waveout,
977 &p_waveheader[i], p_buffer, b_sleek );
983 if( vlc_atomic_get(&p_aout->sys->abort) ) return NULL;
986 deal with the case that the loop didn't fillup the buffer to the
987 max - instead of waiting that half the buffer is played before
988 fillup the waveout buffers, wait only for the next sample buffer
989 to arrive at the play method...
991 this will also avoid, that the last buffer is play until the
992 end, and then trying to get more data, so it will also
993 work - if the next buffer will arrive some ms before the
994 last buffer is finished.
996 if(i_queued_frames < FRAMES_NUM)
997 WaitForSingleObject( p_sys->new_buffer_event, INFINITE );
999 WaitForSingleObject( p_sys->event, INFINITE );
1004 vlc_restorecancel (canc);
1009 static int VolumeSet( audio_output_t *aout, float volume )
1011 aout_sys_t *sys = aout->sys;
1012 const HWAVEOUT hwo = sys->h_waveout;
1013 const float full = 0xffff.fp0;
1016 if( volume >= full )
1019 sys->volume = volume;
1023 uint16_t vol = lroundf(volume);
1024 waveOutSetVolume( hwo, vol | (vol << 16) );
1028 static int MuteSet( audio_output_t * p_aout, bool mute )
1030 aout_sys_t *sys = p_aout->sys;
1031 const HWAVEOUT hwo = sys->h_waveout;
1032 uint16_t vol = mute ? 0 : lroundf(sys->volume);
1035 waveOutSetVolume( hwo, vol | (vol << 16) );
1041 reload the configuration drop down list, of the Audio Devices
1043 static int ReloadWaveoutDevices( vlc_object_t *p_this, char const *psz_name,
1044 vlc_value_t newval, vlc_value_t oldval, void *data )
1046 VLC_UNUSED( newval ); VLC_UNUSED( oldval ); VLC_UNUSED( data );
1048 module_config_t *p_item = config_FindConfig( p_this, psz_name );
1049 if( !p_item ) return VLC_SUCCESS;
1051 /* Clear-up the current list */
1052 if( p_item->i_list )
1056 /* Keep the first entry */
1057 for( i = 1; i < p_item->i_list; i++ )
1059 free((char *)(p_item->ppsz_list[i]) );
1060 free((char *)(p_item->ppsz_list_text[i]) );
1062 /* TODO: Remove when no more needed */
1063 p_item->ppsz_list[i] = NULL;
1064 p_item->ppsz_list_text[i] = NULL;
1068 int wave_devices = waveOutGetNumDevs();
1070 p_item->ppsz_list = xrealloc( p_item->ppsz_list,
1071 (wave_devices+2) * sizeof(char *) );
1072 p_item->ppsz_list_text = xrealloc( p_item->ppsz_list_text,
1073 (wave_devices+2) * sizeof(char *) );
1076 for(int i=0; i<wave_devices; i++)
1079 wchar_t dev_name[MAXPNAMELEN+32];
1081 if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
1082 != MMSYSERR_NOERROR)
1085 _snwprintf(dev_name, MAXPNAMELEN + 32, device_name_fmt,
1086 caps.szPname, caps.wMid, caps.wPid);
1087 p_item->ppsz_list[j] = FromWide( dev_name );
1088 p_item->ppsz_list_text[j] = FromWide( dev_name );
1092 p_item->ppsz_list[j] = NULL;
1093 p_item->ppsz_list_text[j] = NULL;
1099 convert devicename to device ID for output
1100 if device not found return WAVE_MAPPER, so let
1101 windows decide which preferred audio device
1104 static uint32_t findDeviceID(char *psz_device_name)
1106 if( !psz_device_name )
1109 uint32_t wave_devices = waveOutGetNumDevs();
1111 for( uint32_t i = 0; i < wave_devices; i++ )
1114 wchar_t dev_name[MAXPNAMELEN+32];
1116 if( waveOutGetDevCaps( i, &caps, sizeof(WAVEOUTCAPS) )
1117 != MMSYSERR_NOERROR )
1120 _snwprintf( dev_name, MAXPNAMELEN + 32, device_name_fmt,
1121 caps.szPname, caps.wMid, caps.wPid );
1122 char *u8 = FromWide(dev_name);
1123 if( !stricmp(u8, psz_device_name) )