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_charset.h> /* FromWide() */
42 #include <vlc_atomic.h>
44 #include "windows_audio_common.h"
46 #define FRAME_SIZE 4096 /* The size is in samples, not in bytes */
48 /*****************************************************************************
50 *****************************************************************************/
51 static int Open ( vlc_object_t * );
52 static void Close ( vlc_object_t * );
53 static void Play ( audio_output_t *, block_t * );
55 /*****************************************************************************
56 * notification_thread_t: waveOut event thread
57 *****************************************************************************/
59 static void Probe ( audio_output_t *, const audio_sample_format_t * );
60 static int OpenWaveOut ( audio_output_t *, uint32_t,
61 int, int, int, int, bool );
62 static int OpenWaveOutPCM( audio_output_t *, uint32_t,
63 vlc_fourcc_t*, int, int, int, bool );
64 static int PlayWaveOut ( audio_output_t *, HWAVEOUT, WAVEHDR *,
67 static void CALLBACK WaveOutCallback ( HWAVEOUT, UINT, DWORD_PTR, DWORD_PTR, DWORD_PTR );
68 static void* WaveOutThread( void * );
70 static int VolumeSet( audio_output_t *, float );
71 static int MuteSet( audio_output_t *, bool );
73 static int WaveOutClearDoneBuffers(aout_sys_t *p_sys);
75 static int ReloadWaveoutDevices( vlc_object_t *, const char *,
77 static uint32_t findDeviceID(char *);
79 static const wchar_t device_name_fmt[] = L"%ls ($%x,$%x)";
81 /*****************************************************************************
82 * aout_sys_t: waveOut audio output method descriptor
83 *****************************************************************************
84 * This structure is part of the audio output thread descriptor.
85 * It describes the waveOut specific properties of an audio device.
86 *****************************************************************************/
90 uint32_t i_wave_device_id; /* ID of selected output device */
92 HWAVEOUT h_waveout; /* handle to waveout instance */
94 WAVEFORMATEXTENSIBLE waveformat; /* audio format */
96 WAVEHDR waveheader[FRAMES_NUM];
101 HANDLE new_buffer_event;
103 // rental from alsa.c to synchronize startup of audiothread
104 int b_playing; /* playing status */
107 int i_repeat_counter;
111 uint8_t *p_silence_buffer; /* buffer we use to play silence */
122 uint8_t chans_to_reorder; /* do we need channel reordering */
123 uint8_t chan_table[AOUT_CHAN_MAX];
128 /*****************************************************************************
130 *****************************************************************************/
131 #define DEVICE_TEXT N_("Select Audio Device")
132 #define DEVICE_LONG N_("Select special Audio device, or let windows "\
133 "decide (default), change needs VLC restart "\
135 #define DEFAULT_AUDIO_DEVICE N_("Default Audio Device")
138 set_shortname( "WaveOut" )
139 set_description( N_("Win32 waveOut extension output") )
140 set_capability( "audio output", 50 )
141 set_category( CAT_AUDIO )
142 set_subcategory( SUBCAT_AUDIO_AOUT )
144 add_string( "waveout-audio-device", "wavemapper",
145 DEVICE_TEXT, DEVICE_LONG, false )
146 change_string_cb( ReloadWaveoutDevices )
149 add_bool( "waveout-float32", true, FLOAT_TEXT, FLOAT_LONGTEXT, true )
151 set_callbacks( Open, Close )
154 /*****************************************************************************
155 * Opens the audio device
156 *****************************************************************************
157 * This function opens and setups Win32 waveOut
158 *****************************************************************************/
159 static int Start( audio_output_t *p_aout, audio_sample_format_t *restrict fmt )
163 p_aout->time_get = aout_PacketTimeGet;
165 p_aout->pause = aout_PacketPause;
166 p_aout->flush = aout_PacketFlush;
169 check for configured audio device!
171 char *psz_waveout_dev = var_CreateGetString( p_aout, "waveout-audio-device");
173 p_aout->sys->i_wave_device_id =
174 findDeviceID( psz_waveout_dev );
176 if(p_aout->sys->i_wave_device_id == WAVE_MAPPER)
178 if(psz_waveout_dev &&
179 stricmp(psz_waveout_dev,"wavemapper"))
181 msg_Warn( p_aout, "configured audio device '%s' not available, "\
182 "use default instead", psz_waveout_dev );
185 free( psz_waveout_dev );
188 WAVEOUTCAPS waveoutcaps;
189 if(waveOutGetDevCaps( p_aout->sys->i_wave_device_id,
191 sizeof(WAVEOUTCAPS)) == MMSYSERR_NOERROR)
193 /* log debug some infos about driver, to know who to blame
194 if it doesn't work */
195 msg_Dbg( p_aout, "Drivername: %ls", waveoutcaps.szPname);
196 msg_Dbg( p_aout, "Driver Version: %d.%d",
197 (waveoutcaps.vDriverVersion>>8)&255,
198 waveoutcaps.vDriverVersion & 255);
199 msg_Dbg( p_aout, "Manufacturer identifier: 0x%x", waveoutcaps.wMid );
200 msg_Dbg( p_aout, "Product identifier: 0x%x", waveoutcaps.wPid );
205 if( var_Type( p_aout, "audio-device" ) == 0 )
207 Probe( p_aout, fmt );
210 if( var_Get( p_aout, "audio-device", &val ) < 0 )
212 /* Probe() has failed. */
213 var_Destroy( p_aout, "waveout-audio-device");
219 /* Open the device */
220 if( val.i_int == AOUT_VAR_SPDIF )
222 fmt->i_format = VLC_CODEC_SPDIFL;
224 if( OpenWaveOut( p_aout, p_aout->sys->i_wave_device_id,
225 VLC_CODEC_SPDIFL, fmt->i_physical_channels,
226 aout_FormatNbChannels( fmt ), fmt->i_rate, false )
229 msg_Err( p_aout, "cannot open waveout audio device" );
234 /* Calculate the frame size in bytes */
235 fmt->i_bytes_per_frame = AOUT_SPDIF_SIZE;
236 fmt->i_frame_length = A52_FRAME_NB;
237 p_aout->sys->i_buffer_size = fmt->i_bytes_per_frame;
239 aout_PacketInit( p_aout, &p_aout->sys->packet, A52_FRAME_NB, fmt );
248 fmt->i_physical_channels
249 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
250 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
254 fmt->i_physical_channels
255 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
256 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
259 fmt->i_physical_channels = AOUT_CHAN_CENTER;
262 fmt->i_physical_channels = AOUT_CHANS_STEREO;
265 if( OpenWaveOutPCM( p_aout, p_aout->sys->i_wave_device_id,
266 &fmt->i_format, fmt->i_physical_channels,
267 aout_FormatNbChannels( fmt ), fmt->i_rate, false )
270 msg_Err( p_aout, "cannot open waveout audio device" );
275 /* Calculate the frame size in bytes */
276 aout_FormatPrepare( fmt );
277 p_aout->sys->i_buffer_size = FRAME_SIZE * fmt->i_bytes_per_frame;
279 aout_PacketInit( p_aout, &p_aout->sys->packet, FRAME_SIZE, fmt );
281 /* Check for hardware volume support */
282 if( waveOutGetDevCaps( (UINT_PTR)p_aout->sys->h_waveout,
283 &wocaps, sizeof(wocaps) ) == MMSYSERR_NOERROR
284 && (wocaps.dwSupport & WAVECAPS_VOLUME) )
285 { /* FIXME: this needs to be moved to Open() */
286 p_aout->volume_set = VolumeSet;
287 p_aout->mute_set = MuteSet;
288 p_aout->sys->volume = 0xffff.fp0;
289 p_aout->sys->mute = false;
292 aout_SoftVolumeInit( p_aout );
295 waveOutReset( p_aout->sys->h_waveout );
297 /* Allocate silence buffer */
298 p_aout->sys->p_silence_buffer =
299 malloc( p_aout->sys->i_buffer_size );
300 if( p_aout->sys->p_silence_buffer == NULL )
302 aout_PacketDestroy( p_aout );
306 p_aout->sys->i_repeat_counter = 0;
309 /* Zero the buffer. WinCE doesn't have calloc(). */
310 memset( p_aout->sys->p_silence_buffer, 0,
311 p_aout->sys->i_buffer_size );
313 /* Now we need to setup our waveOut play notification structure */
314 p_aout->sys->event = CreateEvent( NULL, FALSE, FALSE, NULL );
315 p_aout->sys->new_buffer_event = CreateEvent( NULL, FALSE, FALSE, NULL );
317 /* define startpoint of playback on first call to play()
318 like alsa does (instead of playing a blank sample) */
319 p_aout->sys->b_playing = 0;
320 p_aout->sys->start_date = 0;
323 /* Then launch the notification thread */
324 vlc_atomic_set( &p_aout->sys->abort, 0);
325 if( vlc_clone( &p_aout->sys->thread,
326 WaveOutThread, p_aout, VLC_THREAD_PRIORITY_OUTPUT ) )
328 msg_Err( p_aout, "cannot create WaveOutThread" );
331 /* We need to kick off the playback in order to have the callback properly
333 for( int i = 0; i < FRAMES_NUM; i++ )
335 p_aout->sys->waveheader[i].dwFlags = WHDR_DONE;
336 p_aout->sys->waveheader[i].dwUser = 0;
342 /*****************************************************************************
343 * Probe: probe the audio device for available formats and channels
344 *****************************************************************************/
345 static void Probe( audio_output_t * p_aout, const audio_sample_format_t *fmt )
347 vlc_value_t val, text;
348 vlc_fourcc_t i_format;
349 unsigned int i_physical_channels;
351 var_Create( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
352 text.psz_string = _("Audio Device");
353 var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
355 /* Test for 5.1 support */
356 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
357 AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
358 AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE;
359 if( fmt->i_physical_channels == i_physical_channels )
361 if( OpenWaveOutPCM( p_aout, p_aout->sys->i_wave_device_id,
362 &i_format, i_physical_channels, 6,
366 val.i_int = AOUT_VAR_5_1;
367 text.psz_string = (char *)_("5.1");
368 var_Change( p_aout, "audio-device",
369 VLC_VAR_ADDCHOICE, &val, &text );
370 msg_Dbg( p_aout, "device supports 5.1 channels" );
374 /* Test for 2 Front 2 Rear support */
375 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
376 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
377 if( ( fmt->i_physical_channels & i_physical_channels )
378 == i_physical_channels )
380 if( OpenWaveOutPCM( p_aout,p_aout->sys->i_wave_device_id,
381 &i_format, i_physical_channels, 4,
385 val.i_int = AOUT_VAR_2F2R;
386 text.psz_string = (char *)_("2 Front 2 Rear");
387 var_Change( p_aout, "audio-device",
388 VLC_VAR_ADDCHOICE, &val, &text );
389 msg_Dbg( p_aout, "device supports 4 channels" );
393 /* Test for stereo support */
394 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
395 if( OpenWaveOutPCM( p_aout, p_aout->sys->i_wave_device_id,
396 &i_format,i_physical_channels, 2,
400 val.i_int = AOUT_VAR_STEREO;
401 text.psz_string = (char *)_("Stereo");
402 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
403 msg_Dbg( p_aout, "device supports 2 channels" );
406 /* Test for mono support */
407 i_physical_channels = AOUT_CHAN_CENTER;
408 if( OpenWaveOutPCM( p_aout, p_aout->sys->i_wave_device_id,
409 &i_format, i_physical_channels, 1, fmt->i_rate, true )
412 val.i_int = AOUT_VAR_MONO;
413 text.psz_string = (char *)_("Mono");
414 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
415 msg_Dbg( p_aout, "device supports 1 channel" );
418 /* Test for SPDIF support */
419 if ( AOUT_FMT_SPDIF( fmt ) )
421 if( OpenWaveOut( p_aout, p_aout->sys->i_wave_device_id,
422 VLC_CODEC_SPDIFL, fmt->i_physical_channels,
423 aout_FormatNbChannels( fmt ), fmt->i_rate, true )
426 msg_Dbg( p_aout, "device supports A/52 over S/PDIF" );
427 val.i_int = AOUT_VAR_SPDIF;
428 text.psz_string = (char *)_("A/52 over S/PDIF");
429 var_Change( p_aout, "audio-device",
430 VLC_VAR_ADDCHOICE, &val, &text );
431 if( var_InheritBool( p_aout, "spdif" ) )
432 var_Set( p_aout, "audio-device", val );
436 var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
439 /* Probe() has failed. */
440 var_Destroy( p_aout, "audio-device" );
444 var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
447 /*****************************************************************************
448 * Play: play a sound buffer
449 *****************************************************************************
450 * This doesn't actually play the buffer. This just stores the buffer so it
451 * can be played by the callback thread.
452 *****************************************************************************/
453 static void Play( audio_output_t *_p_aout, block_t *block )
455 if( !_p_aout->sys->b_playing )
457 _p_aout->sys->b_playing = 1;
459 /* get the playing date of the first aout buffer */
460 _p_aout->sys->start_date = block->i_pts;
462 msg_Dbg( _p_aout, "Wakeup sleeping output thread.");
464 /* wake up the audio output thread */
465 SetEvent( _p_aout->sys->event );
467 SetEvent( _p_aout->sys->new_buffer_event );
470 aout_PacketPlay( _p_aout, block );
473 /*****************************************************************************
474 * Close: close the audio device
475 *****************************************************************************/
476 static void Stop( audio_output_t *p_aout )
478 aout_sys_t *p_sys = p_aout->sys;
480 /* Before calling waveOutClose we must reset the device */
481 vlc_atomic_set( &p_sys->abort, 1);
483 /* wake up the audio thread, to recognize that p_aout died */
484 SetEvent( p_sys->event );
485 SetEvent( p_sys->new_buffer_event );
487 vlc_join( p_sys->thread, NULL );
490 kill the real output then - when the feed thread
491 is surely terminated!
492 old code could be too early in case that "feeding"
493 was running on termination
495 at this point now its sure, that there will be no new
496 data send to the driver, and we can cancel the last
499 MMRESULT result = waveOutReset( p_sys->h_waveout );
500 if(result != MMSYSERR_NOERROR)
502 msg_Err( p_aout, "waveOutReset failed 0x%x", result );
504 now we must wait, that all buffers are played
505 because cancel doesn't work in this case...
507 if(result == MMSYSERR_NOTSUPPORTED)
510 clear currently played (done) buffers,
511 if returnvalue > 0 (means some buffer still playing)
512 wait for the driver event callback that one buffer
513 is finished with playing, and check again
514 the timeout of 5000ms is just, an emergency exit
515 of this loop, to avoid deadlock in case of other
516 (currently not known bugs, problems, errors cases?)
519 (WaveOutClearDoneBuffers( p_sys ) > 0)
521 (WaitForSingleObject( p_sys->event, 5000) == WAIT_OBJECT_0)
524 msg_Dbg( p_aout, "Wait for waveout device...");
528 WaveOutClearDoneBuffers( p_sys );
531 /* now we can Close the device */
532 if( waveOutClose( p_sys->h_waveout ) != MMSYSERR_NOERROR )
534 msg_Err( p_aout, "waveOutClose failed" );
538 because so long, the waveout device is playing, the callback
539 could occur and need the events
541 CloseHandle( p_sys->event );
542 CloseHandle( p_sys->new_buffer_event);
544 free( p_sys->p_silence_buffer );
545 aout_PacketDestroy( p_aout );
548 /*****************************************************************************
549 * OpenWaveOut: open the waveout sound device
550 ****************************************************************************/
551 static int OpenWaveOut( audio_output_t *p_aout, uint32_t i_device_id, int i_format,
552 int i_channels, int i_nb_channels, int i_rate,
557 /* Set sound format */
559 #define waveformat p_aout->sys->waveformat
561 waveformat.dwChannelMask = 0;
562 for( unsigned i = 0; pi_vlc_chan_order_wg4[i]; i++ )
563 if( i_channels & pi_vlc_chan_order_wg4[i] )
564 waveformat.dwChannelMask |= pi_channels_in[i];
568 case VLC_CODEC_SPDIFL:
570 /* To prevent channel re-ordering */
571 waveformat.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
572 waveformat.Format.wBitsPerSample = 16;
573 waveformat.Samples.wValidBitsPerSample =
574 waveformat.Format.wBitsPerSample;
575 waveformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
576 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF;
580 waveformat.Format.wBitsPerSample = sizeof(float) * 8;
581 waveformat.Samples.wValidBitsPerSample =
582 waveformat.Format.wBitsPerSample;
583 waveformat.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
584 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
588 waveformat.Format.wBitsPerSample = 16;
589 waveformat.Samples.wValidBitsPerSample =
590 waveformat.Format.wBitsPerSample;
591 waveformat.Format.wFormatTag = WAVE_FORMAT_PCM;
592 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_PCM;
596 waveformat.Format.nChannels = i_nb_channels;
597 waveformat.Format.nSamplesPerSec = i_rate;
598 waveformat.Format.nBlockAlign =
599 waveformat.Format.wBitsPerSample / 8 * i_nb_channels;
600 waveformat.Format.nAvgBytesPerSec =
601 waveformat.Format.nSamplesPerSec * waveformat.Format.nBlockAlign;
603 /* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */
604 if( i_nb_channels <= 2 )
606 waveformat.Format.cbSize = 0;
610 waveformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
611 waveformat.Format.cbSize =
612 sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
616 msg_Dbg( p_aout, "OpenWaveDevice-ID: %u", i_device_id);
617 msg_Dbg( p_aout,"waveformat.Format.cbSize = %d",
618 waveformat.Format.cbSize);
619 msg_Dbg( p_aout,"waveformat.Format.wFormatTag = %u",
620 waveformat.Format.wFormatTag);
621 msg_Dbg( p_aout,"waveformat.Format.nChannels = %u",
622 waveformat.Format.nChannels);
623 msg_Dbg( p_aout,"waveformat.Format.nSamplesPerSec = %d",
624 (int)waveformat.Format.nSamplesPerSec);
625 msg_Dbg( p_aout,"waveformat.Format.nAvgBytesPerSec = %u",
626 (int)waveformat.Format.nAvgBytesPerSec);
627 msg_Dbg( p_aout,"waveformat.Format.nBlockAlign = %d",
628 waveformat.Format.nBlockAlign);
629 msg_Dbg( p_aout,"waveformat.Format.wBitsPerSample = %d",
630 waveformat.Format.wBitsPerSample);
631 msg_Dbg( p_aout,"waveformat.Samples.wValidBitsPerSample = %d",
632 waveformat.Samples.wValidBitsPerSample);
633 msg_Dbg( p_aout,"waveformat.Samples.wSamplesPerBlock = %d",
634 waveformat.Samples.wSamplesPerBlock);
635 msg_Dbg( p_aout,"waveformat.dwChannelMask = %lu",
636 waveformat.dwChannelMask);
639 /* Open the device */
640 result = waveOutOpen( &p_aout->sys->h_waveout, i_device_id,
641 (WAVEFORMATEX *)&waveformat,
642 (DWORD_PTR)WaveOutCallback, (DWORD_PTR)p_aout,
643 CALLBACK_FUNCTION | (b_probe?WAVE_FORMAT_QUERY:0) );
644 if( result == WAVERR_BADFORMAT )
646 msg_Warn( p_aout, "waveOutOpen failed WAVERR_BADFORMAT" );
649 if( result == MMSYSERR_ALLOCATED )
651 msg_Warn( p_aout, "waveOutOpen failed WAVERR_ALLOCATED" );
654 if( result != MMSYSERR_NOERROR )
656 msg_Warn( p_aout, "waveOutOpen failed" );
660 p_aout->sys->chans_to_reorder =
661 aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
662 waveformat.dwChannelMask,
663 p_aout->sys->chan_table );
664 if( p_aout->sys->chans_to_reorder )
665 msg_Dbg( p_aout, "channel reordering needed" );
673 /*****************************************************************************
674 * OpenWaveOutPCM: open a PCM waveout sound device
675 ****************************************************************************/
676 static int OpenWaveOutPCM( audio_output_t *p_aout, uint32_t i_device_id,
677 vlc_fourcc_t *i_format,
678 int i_channels, int i_nb_channels, int i_rate,
681 bool b_use_float32 = var_CreateGetBool( p_aout, "waveout-float32");
683 if( !b_use_float32 || OpenWaveOut( p_aout, i_device_id, VLC_CODEC_FL32,
684 i_channels, i_nb_channels, i_rate, b_probe )
687 if ( OpenWaveOut( p_aout, i_device_id, VLC_CODEC_S16L,
688 i_channels, i_nb_channels, i_rate, b_probe )
695 *i_format = VLC_CODEC_S16L;
701 *i_format = VLC_CODEC_FL32;
706 /*****************************************************************************
707 * PlayWaveOut: play a buffer through the WaveOut device
708 *****************************************************************************/
709 static int PlayWaveOut( audio_output_t *p_aout, HWAVEOUT h_waveout,
710 WAVEHDR *p_waveheader, block_t *p_buffer, bool b_spdif)
714 /* Prepare the buffer */
715 if( p_buffer != NULL )
717 p_waveheader->lpData = (LPSTR)p_buffer->p_buffer;
719 copy the buffer to the silence buffer :) so in case we don't
720 get the next buffer fast enough (I will repeat this one a time
721 for AC3 / DTS and SPDIF this will sound better instead of
726 memcpy( p_aout->sys->p_silence_buffer,
728 p_aout->sys->i_buffer_size );
729 p_aout->sys->i_repeat_counter = 2;
732 /* Use silence buffer instead */
733 if(p_aout->sys->i_repeat_counter)
735 p_aout->sys->i_repeat_counter--;
736 if(!p_aout->sys->i_repeat_counter)
738 memset( p_aout->sys->p_silence_buffer,
739 0x00, p_aout->sys->i_buffer_size );
742 p_waveheader->lpData = (LPSTR)p_aout->sys->p_silence_buffer;
745 p_waveheader->dwUser = p_buffer ? (DWORD_PTR)p_buffer : (DWORD_PTR)1;
746 p_waveheader->dwBufferLength = p_aout->sys->i_buffer_size;
747 p_waveheader->dwFlags = 0;
749 result = waveOutPrepareHeader( h_waveout, p_waveheader, sizeof(WAVEHDR) );
750 if( result != MMSYSERR_NOERROR )
752 msg_Err( p_aout, "waveOutPrepareHeader failed" );
756 /* Send the buffer to the waveOut queue */
757 result = waveOutWrite( h_waveout, p_waveheader, sizeof(WAVEHDR) );
758 if( result != MMSYSERR_NOERROR )
760 msg_Err( p_aout, "waveOutWrite failed" );
767 /*****************************************************************************
768 * WaveOutCallback: what to do once WaveOut has played its sound samples
769 *****************************************************************************/
770 static void CALLBACK WaveOutCallback( HWAVEOUT h_waveout, UINT uMsg,
772 DWORD_PTR dwParam1, DWORD_PTR dwParam2 )
774 (void)h_waveout; (void)dwParam1; (void)dwParam2;
775 audio_output_t *p_aout = (audio_output_t *)_p_aout;
776 int i_queued_frames = 0;
778 if( uMsg != WOM_DONE ) return;
780 if( vlc_atomic_get(&p_aout->sys->abort) ) return;
782 /* Find out the current latency */
783 for( int i = 0; i < FRAMES_NUM; i++ )
785 /* Check if frame buf is available */
786 if( !(p_aout->sys->waveheader[i].dwFlags & WHDR_DONE) )
792 /* Don't wake up the thread too much */
793 if( i_queued_frames <= FRAMES_NUM/2 )
794 SetEvent( p_aout->sys->event );
798 /****************************************************************************
799 * WaveOutClearDoneBuffers: Clear all done marked buffers, and free buffer
800 ****************************************************************************
801 * return value is the number of still playing buffers in the queue
802 ****************************************************************************/
803 static int WaveOutClearDoneBuffers(aout_sys_t *p_sys)
805 WAVEHDR *p_waveheader = p_sys->waveheader;
806 int i_queued_frames = 0;
808 for( int i = 0; i < FRAMES_NUM; i++ )
810 if( (p_waveheader[i].dwFlags & WHDR_DONE) &&
811 p_waveheader[i].dwUser )
814 (block_t *)(p_waveheader[i].dwUser);
815 /* Unprepare and free the buffers which has just been played */
816 waveOutUnprepareHeader( p_sys->h_waveout, &p_waveheader[i],
819 if( p_waveheader[i].dwUser != 1 )
820 block_Release( p_buffer );
822 p_waveheader[i].dwUser = 0;
825 /* Check if frame buf is available */
826 if( !(p_waveheader[i].dwFlags & WHDR_DONE) )
831 return i_queued_frames;
834 /*****************************************************************************
835 * WaveOutThread: this thread will capture play notification events.
836 *****************************************************************************
837 * We use this thread to feed new audio samples to the sound card because
838 * we are not authorized to use waveOutWrite() directly in the waveout
840 *****************************************************************************/
841 static void* WaveOutThread( void *data )
843 audio_output_t *p_aout = data;
844 aout_sys_t *p_sys = p_aout->sys;
845 block_t *p_buffer = NULL;
846 WAVEHDR *p_waveheader = p_sys->waveheader;
847 int i, i_queued_frames;
850 int canc = vlc_savecancel ();
852 /* We don't want any resampling when using S/PDIF */
853 b_sleek = p_sys->packet.format.i_format == VLC_CODEC_SPDIFL;
855 // wait for first call to "play()"
856 while( !p_sys->start_date && !vlc_atomic_get(&p_aout->sys->abort) )
857 WaitForSingleObject( p_sys->event, INFINITE );
858 if( vlc_atomic_get(&p_aout->sys->abort) )
861 msg_Dbg( p_aout, "will start to play in %"PRId64" us",
862 (p_sys->start_date - AOUT_MAX_PTS_ADVANCE/4)-mdate());
864 // than wait a short time... before grabbing first frames
865 mwait( p_sys->start_date - AOUT_MAX_PTS_ADVANCE/4 );
867 #define waveout_warn(msg) msg_Warn( p_aout, "aout_PacketNext no buffer "\
868 "got next_date=%d ms, "\
869 "%d frames to play, %s",\
870 (int)(next_date/(mtime_t)1000), \
871 i_queued_frames, msg);
874 while( !vlc_atomic_get(&p_aout->sys->abort) )
876 /* Cleanup and find out the current latency */
877 i_queued_frames = WaveOutClearDoneBuffers( p_sys );
879 if( vlc_atomic_get(&p_aout->sys->abort) ) return NULL;
881 /* Try to fill in as many frame buffers as possible */
882 for( i = 0; i < FRAMES_NUM; i++ )
884 /* Check if frame buf is available */
885 if( p_waveheader[i].dwFlags & WHDR_DONE )
887 // next_date = mdate() + 1000000 * i_queued_frames /
888 // p_aout->format.i_rate * p_aout->i_nb_samples;
890 // the realtime has got our back-site:) to come in sync
891 if(next_date < mdate())
895 /* Take into account the latency */
896 p_buffer = aout_PacketNext( p_aout, next_date );
900 msg_Dbg( p_aout, "aout_PacketNext no buffer got "
901 "next_date=%"PRId64" ms, %d frames to play",
902 next_date/1000, i_queued_frames);
904 // means we are too early to request a new buffer?
905 waveout_warn("waiting...")
906 mwait( next_date - AOUT_MAX_PTS_ADVANCE/4 );
908 p_buffer = aout_PacketNext( p_aout, next_date );
911 if( !p_buffer && i_queued_frames )
913 /* We aren't late so no need to play a blank sample */
919 mtime_t buffer_length = p_buffer->i_length;
920 next_date = next_date + buffer_length;
923 /* Do the channel reordering */
924 if( p_buffer && p_sys->chans_to_reorder )
926 aout_ChannelReorder( p_buffer->p_buffer,
928 p_sys->waveformat.Format.nChannels,
930 p_sys->waveformat.Format.wBitsPerSample );
933 PlayWaveOut( p_aout, p_sys->h_waveout,
934 &p_waveheader[i], p_buffer, b_sleek );
940 if( vlc_atomic_get(&p_aout->sys->abort) ) return NULL;
943 deal with the case that the loop didn't fillup the buffer to the
944 max - instead of waiting that half the buffer is played before
945 fillup the waveout buffers, wait only for the next sample buffer
946 to arrive at the play method...
948 this will also avoid, that the last buffer is play until the
949 end, and then trying to get more data, so it will also
950 work - if the next buffer will arrive some ms before the
951 last buffer is finished.
953 if(i_queued_frames < FRAMES_NUM)
954 WaitForSingleObject( p_sys->new_buffer_event, INFINITE );
956 WaitForSingleObject( p_sys->event, INFINITE );
961 vlc_restorecancel (canc);
965 static int VolumeSet( audio_output_t *aout, float volume )
967 aout_sys_t *sys = aout->sys;
968 const HWAVEOUT hwo = sys->h_waveout;
969 const float full = 0xffff.fp0;
975 sys->volume = volume;
979 uint16_t vol = lroundf(volume);
980 waveOutSetVolume( hwo, vol | (vol << 16) );
984 static int MuteSet( audio_output_t * p_aout, bool mute )
986 aout_sys_t *sys = p_aout->sys;
987 const HWAVEOUT hwo = sys->h_waveout;
988 uint16_t vol = mute ? 0 : lroundf(sys->volume);
991 waveOutSetVolume( hwo, vol | (vol << 16) );
996 reload the configuration drop down list, of the Audio Devices
998 static int ReloadWaveoutDevices( vlc_object_t *p_this, char const *psz_name,
999 char ***values, char ***descs )
1001 int n = 0, nb_devices = waveOutGetNumDevs();
1003 VLC_UNUSED( p_this); VLC_UNUSED( psz_name );
1005 *values = xmalloc( (nb_devices + 1) * sizeof(char *) );
1006 *descs = xmalloc( (nb_devices + 1) * sizeof(char *) );
1008 (*values)[n] = strdup( "wavemapper" );
1009 (*descs)[n] = strdup( _("Microsoft Soundmapper") );
1012 for(int i = 0; i < nb_devices; i++)
1015 wchar_t dev_name[MAXPNAMELEN+32];
1017 if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
1018 != MMSYSERR_NOERROR)
1021 _snwprintf(dev_name, MAXPNAMELEN + 32, device_name_fmt,
1022 caps.szPname, caps.wMid, caps.wPid);
1023 (*values)[n] = FromWide( dev_name );
1024 (*descs)[n] = strdup( (*values)[n] );
1032 convert devicename to device ID for output
1033 if device not found return WAVE_MAPPER, so let
1034 windows decide which preferred audio device
1037 static uint32_t findDeviceID(char *psz_device_name)
1039 if( !psz_device_name )
1042 uint32_t wave_devices = waveOutGetNumDevs();
1044 for( uint32_t i = 0; i < wave_devices; i++ )
1047 wchar_t dev_name[MAXPNAMELEN+32];
1049 if( waveOutGetDevCaps( i, &caps, sizeof(WAVEOUTCAPS) )
1050 != MMSYSERR_NOERROR )
1053 _snwprintf( dev_name, MAXPNAMELEN + 32, device_name_fmt,
1054 caps.szPname, caps.wMid, caps.wPid );
1055 char *u8 = FromWide(dev_name);
1056 if( !stricmp(u8, psz_device_name) )
1067 static int Open(vlc_object_t *obj)
1069 audio_output_t *aout = (audio_output_t *)obj;
1070 aout_sys_t *sys = malloc(sizeof (*sys));
1072 if (unlikely(sys == NULL))
1075 aout->start = Start;
1077 /* FIXME: volume handlers */
1081 static void Close(vlc_object_t *obj)
1083 audio_output_t *aout = (audio_output_t *)obj;
1084 aout_sys_t *sys = aout->sys;