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
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
36 #include <vlc_charset.h>
38 #include "windows_audio_common.h"
40 #define FRAME_SIZE 4096 /* The size is in samples, not in bytes */
42 /*****************************************************************************
44 *****************************************************************************/
45 static int Open ( vlc_object_t * );
46 static void Close ( vlc_object_t * );
47 static void Play ( aout_instance_t * );
49 /*****************************************************************************
50 * notification_thread_t: waveOut event thread
51 *****************************************************************************/
52 typedef struct notification_thread_t
55 aout_instance_t *p_aout;
57 } notification_thread_t;
60 static void Probe ( aout_instance_t * );
61 static int OpenWaveOut ( aout_instance_t *, uint32_t,
62 int, int, int, int, bool );
63 static int OpenWaveOutPCM( aout_instance_t *, uint32_t,
64 vlc_fourcc_t*, int, int, int, bool );
65 static int PlayWaveOut ( aout_instance_t *, HWAVEOUT, WAVEHDR *,
66 aout_buffer_t *, bool );
68 static void CALLBACK WaveOutCallback ( HWAVEOUT, UINT, DWORD, DWORD, DWORD );
69 static void* WaveOutThread( vlc_object_t * );
71 static int VolumeGet( aout_instance_t *, audio_volume_t * );
72 static int VolumeSet( aout_instance_t *, audio_volume_t );
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 char psz_device_name_fmt[] = "%s ($%x,$%x)";
82 static const char *const ppsz_adev[] = { "wavemapper", };
83 static const char *const ppsz_adev_text[] = { N_("Microsoft Soundmapper") };
87 /*****************************************************************************
89 *****************************************************************************/
90 #define DEVICE_TEXT N_("Select Audio Device")
91 #define DEVICE_LONG N_("Select special Audio device, or let windows "\
92 "decide (default), change needs VLC restart "\
94 #define DEFAULT_AUDIO_DEVICE N_("Default Audio Device")
97 set_shortname( "WaveOut" )
98 set_description( N_("Win32 waveOut extension output") )
99 set_capability( "audio output", 50 )
100 set_category( CAT_AUDIO )
101 set_subcategory( SUBCAT_AUDIO_AOUT )
102 add_bool( "waveout-float32", true, FLOAT_TEXT, FLOAT_LONGTEXT, true )
104 add_string( "waveout-audio-device", "wavemapper",
105 DEVICE_TEXT, DEVICE_LONG, false )
106 add_deprecated_alias( "waveout-dev" ) /* deprecated since 0.9.3 */
107 change_string_list( ppsz_adev, ppsz_adev_text, ReloadWaveoutDevices )
108 change_need_restart ()
109 change_action_add( ReloadWaveoutDevices, N_("Refresh list") )
112 set_callbacks( Open, Close )
115 /*****************************************************************************
116 * aout_sys_t: waveOut audio output method descriptor
117 *****************************************************************************
118 * This structure is part of the audio output thread descriptor.
119 * It describes the waveOut specific properties of an audio device.
120 *****************************************************************************/
123 uint32_t i_wave_device_id; /* ID of selected output device */
125 HWAVEOUT h_waveout; /* handle to waveout instance */
127 WAVEFORMATEXTENSIBLE waveformat; /* audio format */
129 WAVEHDR waveheader[FRAMES_NUM];
131 notification_thread_t *p_notif; /* WaveOutThread id */
133 HANDLE new_buffer_event;
135 // rental from alsa.c to synchronize startup of audiothread
136 int b_playing; /* playing status */
139 int i_repeat_counter;
143 uint8_t *p_silence_buffer; /* buffer we use to play silence */
145 bool b_chan_reorder; /* do we need channel reordering */
146 int pi_chan_table[AOUT_CHAN_MAX];
149 /*****************************************************************************
150 * Open: open the audio device
151 *****************************************************************************
152 * This function opens and setups Win32 waveOut
153 *****************************************************************************/
154 static int Open( vlc_object_t *p_this )
156 aout_instance_t *p_aout = (aout_instance_t *)p_this;
159 /* Allocate structure */
160 p_aout->output.p_sys = malloc( sizeof( aout_sys_t ) );
162 if( p_aout->output.p_sys == NULL )
165 p_aout->output.pf_play = Play;
166 p_aout->b_die = false;
170 initialize/update Device selection List
172 ReloadWaveoutDevices( p_this, "waveout-audio-device", val, val, NULL);
176 check for configured audio device!
178 char *psz_waveout_dev = var_CreateGetString( p_aout, "waveout-audio-device");
180 p_aout->output.p_sys->i_wave_device_id =
181 findDeviceID( psz_waveout_dev );
183 if(p_aout->output.p_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->output.p_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: %s", 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");
221 free( p_aout->output.p_sys );
226 /* Open the device */
227 if( val.i_int == AOUT_VAR_SPDIF )
229 p_aout->output.output.i_format = VLC_CODEC_SPDIFL;
231 if( OpenWaveOut( p_aout,
232 p_aout->output.p_sys->i_wave_device_id,
234 p_aout->output.output.i_physical_channels,
235 aout_FormatNbChannels( &p_aout->output.output ),
236 p_aout->output.output.i_rate, false )
239 msg_Err( p_aout, "cannot open waveout audio device" );
240 free( p_aout->output.p_sys );
244 /* Calculate the frame size in bytes */
245 p_aout->output.i_nb_samples = A52_FRAME_NB;
246 p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
247 p_aout->output.output.i_frame_length = A52_FRAME_NB;
248 p_aout->output.p_sys->i_buffer_size =
249 p_aout->output.output.i_bytes_per_frame;
251 aout_VolumeNoneInit( p_aout );
260 p_aout->output.output.i_physical_channels
261 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
262 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
266 p_aout->output.output.i_physical_channels
267 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
268 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
271 p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
274 p_aout->output.output.i_physical_channels
275 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
278 if( OpenWaveOutPCM( p_aout,
279 p_aout->output.p_sys->i_wave_device_id,
280 &p_aout->output.output.i_format,
281 p_aout->output.output.i_physical_channels,
282 aout_FormatNbChannels( &p_aout->output.output ),
283 p_aout->output.output.i_rate, false )
286 msg_Err( p_aout, "cannot open waveout audio device" );
287 free( p_aout->output.p_sys );
291 /* Calculate the frame size in bytes */
292 p_aout->output.i_nb_samples = FRAME_SIZE;
293 aout_FormatPrepare( &p_aout->output.output );
294 p_aout->output.p_sys->i_buffer_size = FRAME_SIZE *
295 p_aout->output.output.i_bytes_per_frame;
297 aout_VolumeSoftInit( p_aout );
299 /* Check for hardware volume support */
300 if( waveOutGetDevCaps( (UINT_PTR)p_aout->output.p_sys->h_waveout,
301 &wocaps, sizeof(wocaps) ) == MMSYSERR_NOERROR &&
302 wocaps.dwSupport & WAVECAPS_VOLUME )
305 if( waveOutGetVolume( p_aout->output.p_sys->h_waveout, &i_dummy )
306 == MMSYSERR_NOERROR )
308 p_aout->output.pf_volume_get = VolumeGet;
309 p_aout->output.pf_volume_set = VolumeSet;
315 waveOutReset( p_aout->output.p_sys->h_waveout );
317 /* Allocate silence buffer */
318 p_aout->output.p_sys->p_silence_buffer =
319 malloc( p_aout->output.p_sys->i_buffer_size );
320 if( p_aout->output.p_sys->p_silence_buffer == NULL )
322 free( p_aout->output.p_sys );
325 p_aout->output.p_sys->i_repeat_counter = 0;
328 /* Zero the buffer. WinCE doesn't have calloc(). */
329 memset( p_aout->output.p_sys->p_silence_buffer, 0,
330 p_aout->output.p_sys->i_buffer_size );
332 /* Now we need to setup our waveOut play notification structure */
333 p_aout->output.p_sys->p_notif =
334 vlc_object_create( p_aout, sizeof(notification_thread_t) );
335 p_aout->output.p_sys->p_notif->p_aout = p_aout;
336 p_aout->output.p_sys->event = CreateEvent( NULL, FALSE, FALSE, NULL );
337 p_aout->output.p_sys->new_buffer_event = CreateEvent( NULL, FALSE, FALSE, NULL );
339 /* define startpoint of playback on first call to play()
340 like alsa does (instead of playing a blank sample) */
341 p_aout->output.p_sys->b_playing = 0;
342 p_aout->output.p_sys->start_date = 0;
345 /* Then launch the notification thread */
346 if( vlc_thread_create( p_aout->output.p_sys->p_notif,
347 WaveOutThread, VLC_THREAD_PRIORITY_OUTPUT ) )
349 msg_Err( p_aout, "cannot create WaveOutThread" );
352 /* We need to kick off the playback in order to have the callback properly
354 for( int i = 0; i < FRAMES_NUM; i++ )
356 p_aout->output.p_sys->waveheader[i].dwFlags = WHDR_DONE;
357 p_aout->output.p_sys->waveheader[i].dwUser = 0;
363 /*****************************************************************************
364 * Probe: probe the audio device for available formats and channels
365 *****************************************************************************/
366 static void Probe( aout_instance_t * p_aout )
368 vlc_value_t val, text;
369 vlc_fourcc_t i_format;
370 unsigned int i_physical_channels;
372 var_Create( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
373 text.psz_string = _("Audio Device");
374 var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
376 /* Test for 5.1 support */
377 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
378 AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
379 AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE;
380 if( p_aout->output.output.i_physical_channels == i_physical_channels )
382 if( OpenWaveOutPCM( p_aout,
383 p_aout->output.p_sys->i_wave_device_id,
385 i_physical_channels, 6,
386 p_aout->output.output.i_rate, true )
389 val.i_int = AOUT_VAR_5_1;
390 text.psz_string = (char *)_("5.1");
391 var_Change( p_aout, "audio-device",
392 VLC_VAR_ADDCHOICE, &val, &text );
393 msg_Dbg( p_aout, "device supports 5.1 channels" );
397 /* Test for 2 Front 2 Rear support */
398 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
399 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
400 if( ( p_aout->output.output.i_physical_channels & i_physical_channels )
401 == i_physical_channels )
403 if( OpenWaveOutPCM( p_aout,
404 p_aout->output.p_sys->i_wave_device_id,
406 i_physical_channels, 4,
407 p_aout->output.output.i_rate, true )
410 val.i_int = AOUT_VAR_2F2R;
411 text.psz_string = (char *)_("2 Front 2 Rear");
412 var_Change( p_aout, "audio-device",
413 VLC_VAR_ADDCHOICE, &val, &text );
414 msg_Dbg( p_aout, "device supports 4 channels" );
418 /* Test for stereo support */
419 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
420 if( OpenWaveOutPCM( p_aout,
421 p_aout->output.p_sys->i_wave_device_id,
423 i_physical_channels, 2,
424 p_aout->output.output.i_rate, true )
427 val.i_int = AOUT_VAR_STEREO;
428 text.psz_string = (char *)_("Stereo");
429 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
430 msg_Dbg( p_aout, "device supports 2 channels" );
433 /* Test for mono support */
434 i_physical_channels = AOUT_CHAN_CENTER;
435 if( OpenWaveOutPCM( p_aout,
436 p_aout->output.p_sys->i_wave_device_id,
438 i_physical_channels, 1,
439 p_aout->output.output.i_rate, true )
442 val.i_int = AOUT_VAR_MONO;
443 text.psz_string = (char *)_("Mono");
444 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
445 msg_Dbg( p_aout, "device supports 1 channel" );
448 /* Test for SPDIF support */
449 if ( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
451 if( OpenWaveOut( p_aout,
452 p_aout->output.p_sys->i_wave_device_id,
454 p_aout->output.output.i_physical_channels,
455 aout_FormatNbChannels( &p_aout->output.output ),
456 p_aout->output.output.i_rate, true )
459 msg_Dbg( p_aout, "device supports A/52 over S/PDIF" );
460 val.i_int = AOUT_VAR_SPDIF;
461 text.psz_string = (char *)_("A/52 over S/PDIF");
462 var_Change( p_aout, "audio-device",
463 VLC_VAR_ADDCHOICE, &val, &text );
464 if( var_InheritBool( p_aout, "spdif" ) )
465 var_Set( p_aout, "audio-device", val );
469 var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
472 /* Probe() has failed. */
473 var_Destroy( p_aout, "audio-device" );
477 var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
478 var_SetBool( p_aout, "intf-change", true );
481 /*****************************************************************************
482 * Play: play a sound buffer
483 *****************************************************************************
484 * This doesn't actually play the buffer. This just stores the buffer so it
485 * can be played by the callback thread.
486 *****************************************************************************/
487 static void Play( aout_instance_t *_p_aout )
489 if( !_p_aout->output.p_sys->b_playing )
491 _p_aout->output.p_sys->b_playing = 1;
493 /* get the playing date of the first aout buffer */
494 _p_aout->output.p_sys->start_date =
495 aout_FifoFirstDate( _p_aout, &_p_aout->output.fifo );
497 msg_Dbg( _p_aout, "Wakeup sleeping output thread.");
499 /* wake up the audio output thread */
500 SetEvent( _p_aout->output.p_sys->event );
502 SetEvent( _p_aout->output.p_sys->new_buffer_event );
506 /*****************************************************************************
507 * Close: close the audio device
508 *****************************************************************************/
509 static void Close( vlc_object_t *p_this )
511 aout_instance_t *p_aout = (aout_instance_t *)p_this;
512 aout_sys_t *p_sys = p_aout->output.p_sys;
514 /* Before calling waveOutClose we must reset the device */
515 vlc_object_kill( p_aout );
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_thread_join( p_sys->p_notif );
522 vlc_object_release( p_sys->p_notif );
525 kill the real output then - when the feed thread
526 is surely terminated!
527 old code could be too early in case that "feeding"
528 was running on termination
530 at this point now its sure, that there will be no new
531 data send to the driver, and we can cancel the last
534 MMRESULT result = waveOutReset( p_sys->h_waveout );
535 if(result != MMSYSERR_NOERROR)
537 msg_Err( p_aout, "waveOutReset failed 0x%x", result );
539 now we must wait, that all buffers are played
540 because cancel doesn't work in this case...
542 if(result == MMSYSERR_NOTSUPPORTED)
545 clear currently played (done) buffers,
546 if returnvalue > 0 (means some buffer still playing)
547 wait for the driver event callback that one buffer
548 is finished with playing, and check again
549 the timeout of 5000ms is just, an emergency exit
550 of this loop, to avoid deadlock in case of other
551 (currently not known bugs, problems, errors cases?)
554 (WaveOutClearDoneBuffers( p_sys ) > 0)
556 (WaitForSingleObject( p_sys->event, 5000) == WAIT_OBJECT_0)
559 msg_Dbg( p_aout, "Wait for waveout device...");
563 WaveOutClearDoneBuffers( p_sys );
566 /* now we can Close the device */
567 if( waveOutClose( p_sys->h_waveout ) != MMSYSERR_NOERROR )
569 msg_Err( p_aout, "waveOutClose failed" );
573 because so long, the waveout device is playing, the callback
574 could occur and need the events
576 CloseHandle( p_sys->event );
577 CloseHandle( p_sys->new_buffer_event);
579 free( p_sys->p_silence_buffer );
583 /*****************************************************************************
584 * OpenWaveOut: open the waveout sound device
585 ****************************************************************************/
586 static int OpenWaveOut( aout_instance_t *p_aout, uint32_t i_device_id, int i_format,
587 int i_channels, int i_nb_channels, int i_rate,
593 /* Set sound format */
595 #define waveformat p_aout->output.p_sys->waveformat
597 waveformat.dwChannelMask = 0;
598 for( i = 0; i < sizeof(pi_channels_src)/sizeof(uint32_t); i++ )
600 if( i_channels & pi_channels_src[i] )
601 waveformat.dwChannelMask |= pi_channels_in[i];
606 case VLC_CODEC_SPDIFL:
608 /* To prevent channel re-ordering */
609 waveformat.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
610 waveformat.Format.wBitsPerSample = 16;
611 waveformat.Samples.wValidBitsPerSample =
612 waveformat.Format.wBitsPerSample;
613 waveformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
614 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF;
618 waveformat.Format.wBitsPerSample = sizeof(float) * 8;
619 waveformat.Samples.wValidBitsPerSample =
620 waveformat.Format.wBitsPerSample;
621 waveformat.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
622 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
626 waveformat.Format.wBitsPerSample = 16;
627 waveformat.Samples.wValidBitsPerSample =
628 waveformat.Format.wBitsPerSample;
629 waveformat.Format.wFormatTag = WAVE_FORMAT_PCM;
630 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_PCM;
634 waveformat.Format.nChannels = i_nb_channels;
635 waveformat.Format.nSamplesPerSec = i_rate;
636 waveformat.Format.nBlockAlign =
637 waveformat.Format.wBitsPerSample / 8 * i_nb_channels;
638 waveformat.Format.nAvgBytesPerSec =
639 waveformat.Format.nSamplesPerSec * waveformat.Format.nBlockAlign;
641 /* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */
642 if( i_nb_channels <= 2 )
644 waveformat.Format.cbSize = 0;
648 waveformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
649 waveformat.Format.cbSize =
650 sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
654 msg_Dbg( p_aout, "OpenWaveDevice-ID: %u", i_device_id);
655 msg_Dbg( p_aout,"waveformat.Format.cbSize = %d",
656 waveformat.Format.cbSize);
657 msg_Dbg( p_aout,"waveformat.Format.wFormatTag = %u",
658 waveformat.Format.wFormatTag);
659 msg_Dbg( p_aout,"waveformat.Format.nChannels = %u",
660 waveformat.Format.nChannels);
661 msg_Dbg( p_aout,"waveformat.Format.nSamplesPerSec = %d",
662 (int)waveformat.Format.nSamplesPerSec);
663 msg_Dbg( p_aout,"waveformat.Format.nAvgBytesPerSec = %u",
664 (int)waveformat.Format.nAvgBytesPerSec);
665 msg_Dbg( p_aout,"waveformat.Format.nBlockAlign = %d",
666 waveformat.Format.nBlockAlign);
667 msg_Dbg( p_aout,"waveformat.Format.wBitsPerSample = %d",
668 waveformat.Format.wBitsPerSample);
669 msg_Dbg( p_aout,"waveformat.Samples.wValidBitsPerSample = %d",
670 waveformat.Samples.wValidBitsPerSample);
671 msg_Dbg( p_aout,"waveformat.Samples.wSamplesPerBlock = %d",
672 waveformat.Samples.wSamplesPerBlock);
673 msg_Dbg( p_aout,"waveformat.dwChannelMask = %lu",
674 waveformat.dwChannelMask);
677 /* Open the device */
678 result = waveOutOpen( &p_aout->output.p_sys->h_waveout, i_device_id,
679 (WAVEFORMATEX *)&waveformat,
680 (DWORD_PTR)WaveOutCallback, (DWORD_PTR)p_aout,
681 CALLBACK_FUNCTION | (b_probe?WAVE_FORMAT_QUERY:0) );
682 if( result == WAVERR_BADFORMAT )
684 msg_Warn( p_aout, "waveOutOpen failed WAVERR_BADFORMAT" );
687 if( result == MMSYSERR_ALLOCATED )
689 msg_Warn( p_aout, "waveOutOpen failed WAVERR_ALLOCATED" );
692 if( result != MMSYSERR_NOERROR )
694 msg_Warn( p_aout, "waveOutOpen failed" );
698 p_aout->output.p_sys->b_chan_reorder =
699 aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
700 waveformat.dwChannelMask, i_nb_channels,
701 p_aout->output.p_sys->pi_chan_table );
703 if( p_aout->output.p_sys->b_chan_reorder )
705 msg_Dbg( p_aout, "channel reordering needed" );
714 /*****************************************************************************
715 * OpenWaveOutPCM: open a PCM waveout sound device
716 ****************************************************************************/
717 static int OpenWaveOutPCM( aout_instance_t *p_aout, uint32_t i_device_id,
718 vlc_fourcc_t *i_format,
719 int i_channels, int i_nb_channels, int i_rate,
722 bool b_use_float32 = var_CreateGetBool( p_aout, "waveout-float32");
724 if( !b_use_float32 || OpenWaveOut( p_aout, i_device_id, VLC_CODEC_FL32,
725 i_channels, i_nb_channels, i_rate, b_probe )
728 if ( OpenWaveOut( p_aout, i_device_id, VLC_CODEC_S16L,
729 i_channels, i_nb_channels, i_rate, b_probe )
736 *i_format = VLC_CODEC_S16L;
742 *i_format = VLC_CODEC_FL32;
747 /*****************************************************************************
748 * PlayWaveOut: play a buffer through the WaveOut device
749 *****************************************************************************/
750 static int PlayWaveOut( aout_instance_t *p_aout, HWAVEOUT h_waveout,
751 WAVEHDR *p_waveheader, aout_buffer_t *p_buffer,
756 /* Prepare the buffer */
757 if( p_buffer != NULL )
759 p_waveheader->lpData = p_buffer->p_buffer;
761 copy the buffer to the silence buffer :) so in case we don't
762 get the next buffer fast enough (I will repeat this one a time
763 for AC3 / DTS and SPDIF this will sound better instead of
768 vlc_memcpy( p_aout->output.p_sys->p_silence_buffer,
770 p_aout->output.p_sys->i_buffer_size );
771 p_aout->output.p_sys->i_repeat_counter = 2;
774 /* Use silence buffer instead */
775 if(p_aout->output.p_sys->i_repeat_counter)
777 p_aout->output.p_sys->i_repeat_counter--;
778 if(!p_aout->output.p_sys->i_repeat_counter)
780 vlc_memset( p_aout->output.p_sys->p_silence_buffer,
781 0x00, p_aout->output.p_sys->i_buffer_size );
784 p_waveheader->lpData = p_aout->output.p_sys->p_silence_buffer;
787 p_waveheader->dwUser = p_buffer ? (DWORD_PTR)p_buffer : (DWORD_PTR)1;
788 p_waveheader->dwBufferLength = p_aout->output.p_sys->i_buffer_size;
789 p_waveheader->dwFlags = 0;
791 result = waveOutPrepareHeader( h_waveout, p_waveheader, sizeof(WAVEHDR) );
792 if( result != MMSYSERR_NOERROR )
794 msg_Err( p_aout, "waveOutPrepareHeader failed" );
798 /* Send the buffer to the waveOut queue */
799 result = waveOutWrite( h_waveout, p_waveheader, sizeof(WAVEHDR) );
800 if( result != MMSYSERR_NOERROR )
802 msg_Err( p_aout, "waveOutWrite failed" );
809 /*****************************************************************************
810 * WaveOutCallback: what to do once WaveOut has played its sound samples
811 *****************************************************************************/
812 static void CALLBACK WaveOutCallback( HWAVEOUT h_waveout, UINT uMsg,
814 DWORD dwParam1, DWORD dwParam2 )
816 (void)h_waveout; (void)dwParam1; (void)dwParam2;
817 aout_instance_t *p_aout = (aout_instance_t *)_p_aout;
818 int i, i_queued_frames = 0;
820 if( uMsg != WOM_DONE ) return;
822 if( !vlc_object_alive (p_aout) ) return;
824 /* Find out the current latency */
825 for( i = 0; i < FRAMES_NUM; i++ )
827 /* Check if frame buf is available */
828 if( !(p_aout->output.p_sys->waveheader[i].dwFlags & WHDR_DONE) )
834 /* Don't wake up the thread too much */
835 if( i_queued_frames <= FRAMES_NUM/2 )
836 SetEvent( p_aout->output.p_sys->event );
840 /****************************************************************************
841 * WaveOutClearDoneBuffers: Clear all done marked buffers, and free aout_bufer
842 ****************************************************************************
843 * return value is the number of still playing buffers in the queue
844 ****************************************************************************/
845 static int WaveOutClearDoneBuffers(aout_sys_t *p_sys)
847 WAVEHDR *p_waveheader = p_sys->waveheader;
848 int i_queued_frames = 0;
850 for( int i = 0; i < FRAMES_NUM; i++ )
852 if( (p_waveheader[i].dwFlags & WHDR_DONE) &&
853 p_waveheader[i].dwUser )
855 aout_buffer_t *p_buffer =
856 (aout_buffer_t *)(p_waveheader[i].dwUser);
857 /* Unprepare and free the buffers which has just been played */
858 waveOutUnprepareHeader( p_sys->h_waveout, &p_waveheader[i],
861 if( p_waveheader[i].dwUser != 1 )
862 aout_BufferFree( p_buffer );
864 p_waveheader[i].dwUser = 0;
867 /* Check if frame buf is available */
868 if( !(p_waveheader[i].dwFlags & WHDR_DONE) )
873 return i_queued_frames;
876 /*****************************************************************************
877 * WaveOutThread: this thread will capture play notification events.
878 *****************************************************************************
879 * We use this thread to feed new audio samples to the sound card because
880 * we are not authorized to use waveOutWrite() directly in the waveout
882 *****************************************************************************/
883 static void* WaveOutThread( vlc_object_t *p_this )
885 notification_thread_t *p_notif = (notification_thread_t*)p_this;
886 aout_instance_t *p_aout = p_notif->p_aout;
887 aout_sys_t *p_sys = p_aout->output.p_sys;
888 aout_buffer_t *p_buffer = NULL;
889 WAVEHDR *p_waveheader = p_sys->waveheader;
890 int i, i_queued_frames;
893 uint32_t i_buffer_length = 64;
894 int canc = vlc_savecancel ();
896 /* We don't want any resampling when using S/PDIF */
897 b_sleek = p_aout->output.output.i_format == VLC_CODEC_SPDIFL;
899 // wait for first call to "play()"
900 while( !p_sys->start_date && vlc_object_alive (p_aout) )
901 WaitForSingleObject( p_sys->event, INFINITE );
902 if( !vlc_object_alive (p_aout) )
905 msg_Dbg( p_aout, "will start to play in %"PRId64" us",
906 (p_sys->start_date - AOUT_PTS_TOLERANCE/4)-mdate());
908 // than wait a short time... before grabbing first frames
909 mwait( p_sys->start_date - AOUT_PTS_TOLERANCE/4 );
911 #define waveout_warn(msg) msg_Warn( p_aout, "aout_OutputNextBuffer no buffer "\
912 "got next_date=%d ms, "\
913 "%d frames to play, "\
914 "starving? %d, %s",(int)(next_date/(mtime_t)1000), \
916 p_aout->output.b_starving, msg);
919 while( vlc_object_alive (p_aout) )
921 /* Cleanup and find out the current latency */
922 i_queued_frames = WaveOutClearDoneBuffers( p_sys );
924 if( !vlc_object_alive (p_aout) ) return NULL;
926 /* Try to fill in as many frame buffers as possible */
927 for( i = 0; i < FRAMES_NUM; i++ )
929 /* Check if frame buf is available */
930 if( p_waveheader[i].dwFlags & WHDR_DONE )
932 // next_date = mdate() + 1000000 * i_queued_frames /
933 // p_aout->output.output.i_rate * p_aout->output.i_nb_samples;
935 // the realtime has got our back-site:) to come in sync
936 if(next_date < mdate())
940 /* Take into account the latency */
941 p_buffer = aout_OutputNextBuffer( p_aout,
948 msg_Dbg( p_aout, "aout_OutputNextBuffer no buffer "\
949 "got next_date=%d ms, "\
950 "%d frames to play, "\
951 "starving? %d",(int)(next_date/(mtime_t)1000),
953 p_aout->output.b_starving);
955 if(p_aout->output.b_starving)
957 // means we are too early to request a new buffer?
958 waveout_warn("waiting...")
959 next_date = aout_FifoFirstDate( p_aout, &p_aout->output.fifo );
960 mwait( next_date - AOUT_PTS_TOLERANCE/4 );
962 p_buffer = aout_OutputNextBuffer( p_aout,
969 if( !p_buffer && i_queued_frames )
971 /* We aren't late so no need to play a blank sample */
977 mtime_t buffer_length = p_buffer->i_length;
978 next_date = next_date + buffer_length;
979 i_buffer_length = buffer_length/1000;
982 /* Do the channel reordering */
983 if( p_buffer && p_sys->b_chan_reorder )
985 aout_ChannelReorder( p_buffer->p_buffer,
987 p_sys->waveformat.Format.nChannels,
988 p_sys->pi_chan_table,
989 p_sys->waveformat.Format.wBitsPerSample );
992 PlayWaveOut( p_aout, p_sys->h_waveout,
993 &p_waveheader[i], p_buffer, b_sleek );
999 if( !vlc_object_alive (p_aout) ) return NULL;
1002 deal with the case that the loop didn't fillup the buffer to the
1003 max - instead of waiting that half the buffer is played before
1004 fillup the waveout buffers, wait only for the next sample buffer
1005 to arrive at the play method...
1007 this will also avoid, that the last buffer is play until the
1008 end, and then trying to get more data, so it will also
1009 work - if the next buffer will arrive some ms before the
1010 last buffer is finished.
1012 if(i_queued_frames < FRAMES_NUM)
1013 WaitForSingleObject( p_sys->new_buffer_event, INFINITE );
1015 WaitForSingleObject( p_sys->event, INFINITE );
1020 vlc_restorecancel (canc);
1024 static int VolumeGet( aout_instance_t * p_aout, audio_volume_t * pi_volume )
1026 DWORD i_waveout_vol;
1029 waveOutGetVolume( 0, &i_waveout_vol );
1031 waveOutGetVolume( p_aout->output.p_sys->h_waveout, &i_waveout_vol );
1034 i_waveout_vol &= 0xFFFF;
1035 *pi_volume = p_aout->output.i_volume =
1036 (i_waveout_vol * AOUT_VOLUME_MAX + 0xFFFF /*rounding*/) / 2 / 0xFFFF;
1040 static int VolumeSet( aout_instance_t * p_aout, audio_volume_t i_volume )
1042 unsigned long i_waveout_vol = i_volume * 0xFFFF * 2 / AOUT_VOLUME_MAX;
1043 i_waveout_vol |= (i_waveout_vol << 16);
1046 waveOutSetVolume( 0, i_waveout_vol );
1048 waveOutSetVolume( p_aout->output.p_sys->h_waveout, i_waveout_vol );
1051 p_aout->output.i_volume = i_volume;
1057 reload the configuration drop down list, of the Audio Devices
1059 static int ReloadWaveoutDevices( vlc_object_t *p_this, char const *psz_name,
1060 vlc_value_t newval, vlc_value_t oldval, void *data )
1062 VLC_UNUSED( newval ); VLC_UNUSED( oldval ); VLC_UNUSED( data );
1064 module_config_t *p_item = config_FindConfig( p_this, psz_name );
1065 if( !p_item ) return VLC_SUCCESS;
1067 /* Clear-up the current list */
1068 if( p_item->i_list )
1072 /* Keep the first entry */
1073 for( i = 1; i < p_item->i_list; i++ )
1075 free((char *)(p_item->ppsz_list[i]) );
1076 free((char *)(p_item->ppsz_list_text[i]) );
1078 /* TODO: Remove when no more needed */
1079 p_item->ppsz_list[i] = NULL;
1080 p_item->ppsz_list_text[i] = NULL;
1084 int wave_devices = waveOutGetNumDevs();
1086 p_item->ppsz_list = xrealloc( p_item->ppsz_list,
1087 (wave_devices+2) * sizeof(char *) );
1088 p_item->ppsz_list_text = xrealloc( p_item->ppsz_list_text,
1089 (wave_devices+2) * sizeof(char *) );
1092 char sz_dev_name[MAXPNAMELEN+32];
1094 for(int i=0; i<wave_devices; i++)
1096 if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
1097 == MMSYSERR_NOERROR)
1099 sprintf( sz_dev_name, psz_device_name_fmt, caps.szPname,
1103 p_item->ppsz_list[j] = FromLocaleDup( sz_dev_name );
1104 p_item->ppsz_list_text[j] = FromLocaleDup( sz_dev_name );
1110 p_item->ppsz_list[j] = NULL;
1111 p_item->ppsz_list_text[j] = NULL;
1113 /* Signal change to the interface */
1114 p_item->b_dirty = true;
1120 convert devicename to device ID for output
1121 if device not found return WAVE_MAPPER, so let
1122 windows decide which preferred audio device
1125 static uint32_t findDeviceID(char *psz_device_name)
1127 if(!psz_device_name)
1130 uint32_t wave_devices = waveOutGetNumDevs();
1132 char sz_dev_name[MAXPNAMELEN+32];
1133 for(uint32_t i=0; i<wave_devices; i++)
1135 if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
1136 == MMSYSERR_NOERROR)
1138 sprintf(sz_dev_name, psz_device_name_fmt, caps.szPname,
1142 char *psz_temp = FromLocaleDup(sz_dev_name);
1144 if( !stricmp(psz_temp, psz_device_name) )
1146 LocaleFree( psz_temp );
1149 LocaleFree( psz_temp );