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 VolumeSet( aout_instance_t *, audio_volume_t );
73 static int WaveOutClearDoneBuffers(aout_sys_t *p_sys);
75 static int ReloadWaveoutDevices( vlc_object_t *, char const *,
76 vlc_value_t, vlc_value_t, void * );
77 static uint32_t findDeviceID(char *);
79 static const char psz_device_name_fmt[] = "%s ($%x,$%x)";
81 static const char *const ppsz_adev[] = { "wavemapper", };
82 static const char *const ppsz_adev_text[] = { N_("Microsoft Soundmapper") };
86 /*****************************************************************************
88 *****************************************************************************/
89 #define DEVICE_TEXT N_("Select Audio Device")
90 #define DEVICE_LONG N_("Select special Audio device, or let windows "\
91 "decide (default), change needs VLC restart "\
93 #define DEFAULT_AUDIO_DEVICE N_("Default Audio Device")
96 set_shortname( "WaveOut" )
97 set_description( N_("Win32 waveOut extension output") )
98 set_capability( "audio output", 50 )
99 set_category( CAT_AUDIO )
100 set_subcategory( SUBCAT_AUDIO_AOUT )
101 add_bool( "waveout-float32", true, FLOAT_TEXT, FLOAT_LONGTEXT, true )
103 add_string( "waveout-audio-device", "wavemapper",
104 DEVICE_TEXT, DEVICE_LONG, false )
105 add_deprecated_alias( "waveout-dev" ) /* deprecated since 0.9.3 */
106 change_string_list( ppsz_adev, ppsz_adev_text, ReloadWaveoutDevices )
107 change_need_restart ()
108 change_action_add( ReloadWaveoutDevices, N_("Refresh list") )
111 set_callbacks( Open, Close )
114 /*****************************************************************************
115 * aout_sys_t: waveOut audio output method descriptor
116 *****************************************************************************
117 * This structure is part of the audio output thread descriptor.
118 * It describes the waveOut specific properties of an audio device.
119 *****************************************************************************/
122 uint32_t i_wave_device_id; /* ID of selected output device */
124 HWAVEOUT h_waveout; /* handle to waveout instance */
126 WAVEFORMATEXTENSIBLE waveformat; /* audio format */
128 WAVEHDR waveheader[FRAMES_NUM];
130 notification_thread_t *p_notif; /* WaveOutThread id */
132 HANDLE new_buffer_event;
134 // rental from alsa.c to synchronize startup of audiothread
135 int b_playing; /* playing status */
138 int i_repeat_counter;
142 uint8_t *p_silence_buffer; /* buffer we use to play silence */
144 bool b_chan_reorder; /* do we need channel reordering */
145 int pi_chan_table[AOUT_CHAN_MAX];
148 /*****************************************************************************
149 * Open: open the audio device
150 *****************************************************************************
151 * This function opens and setups Win32 waveOut
152 *****************************************************************************/
153 static int Open( vlc_object_t *p_this )
155 aout_instance_t *p_aout = (aout_instance_t *)p_this;
158 /* Allocate structure */
159 p_aout->output.p_sys = malloc( sizeof( aout_sys_t ) );
161 if( p_aout->output.p_sys == NULL )
164 p_aout->output.pf_play = Play;
165 p_aout->b_die = false;
169 initialize/update Device selection List
171 ReloadWaveoutDevices( p_this, "waveout-audio-device", val, val, NULL);
175 check for configured audio device!
177 char *psz_waveout_dev = var_CreateGetString( p_aout, "waveout-audio-device");
179 p_aout->output.p_sys->i_wave_device_id =
180 findDeviceID( psz_waveout_dev );
182 if(p_aout->output.p_sys->i_wave_device_id == WAVE_MAPPER)
184 if(psz_waveout_dev &&
185 stricmp(psz_waveout_dev,"wavemapper"))
187 msg_Warn( p_aout, "configured audio device '%s' not available, "\
188 "use default instead", psz_waveout_dev );
191 free( psz_waveout_dev );
194 WAVEOUTCAPS waveoutcaps;
195 if(waveOutGetDevCaps( p_aout->output.p_sys->i_wave_device_id,
197 sizeof(WAVEOUTCAPS)) == MMSYSERR_NOERROR)
199 /* log debug some infos about driver, to know who to blame
200 if it doesn't work */
201 msg_Dbg( p_aout, "Drivername: %s", waveoutcaps.szPname);
202 msg_Dbg( p_aout, "Driver Version: %d.%d",
203 (waveoutcaps.vDriverVersion>>8)&255,
204 waveoutcaps.vDriverVersion & 255);
205 msg_Dbg( p_aout, "Manufacturer identifier: 0x%x", waveoutcaps.wMid );
206 msg_Dbg( p_aout, "Product identifier: 0x%x", waveoutcaps.wPid );
211 if( var_Type( p_aout, "audio-device" ) == 0 )
216 if( var_Get( p_aout, "audio-device", &val ) < 0 )
218 /* Probe() has failed. */
219 var_Destroy( p_aout, "waveout-audio-device");
220 free( p_aout->output.p_sys );
225 /* Open the device */
226 if( val.i_int == AOUT_VAR_SPDIF )
228 p_aout->output.output.i_format = VLC_CODEC_SPDIFL;
230 if( OpenWaveOut( p_aout,
231 p_aout->output.p_sys->i_wave_device_id,
233 p_aout->output.output.i_physical_channels,
234 aout_FormatNbChannels( &p_aout->output.output ),
235 p_aout->output.output.i_rate, false )
238 msg_Err( p_aout, "cannot open waveout audio device" );
239 free( p_aout->output.p_sys );
243 /* Calculate the frame size in bytes */
244 p_aout->output.i_nb_samples = A52_FRAME_NB;
245 p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
246 p_aout->output.output.i_frame_length = A52_FRAME_NB;
247 p_aout->output.p_sys->i_buffer_size =
248 p_aout->output.output.i_bytes_per_frame;
250 aout_VolumeNoneInit( p_aout );
259 p_aout->output.output.i_physical_channels
260 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
261 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
265 p_aout->output.output.i_physical_channels
266 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
267 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
270 p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
273 p_aout->output.output.i_physical_channels
274 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
277 if( OpenWaveOutPCM( p_aout,
278 p_aout->output.p_sys->i_wave_device_id,
279 &p_aout->output.output.i_format,
280 p_aout->output.output.i_physical_channels,
281 aout_FormatNbChannels( &p_aout->output.output ),
282 p_aout->output.output.i_rate, false )
285 msg_Err( p_aout, "cannot open waveout audio device" );
286 free( p_aout->output.p_sys );
290 /* Calculate the frame size in bytes */
291 p_aout->output.i_nb_samples = FRAME_SIZE;
292 aout_FormatPrepare( &p_aout->output.output );
293 p_aout->output.p_sys->i_buffer_size = FRAME_SIZE *
294 p_aout->output.output.i_bytes_per_frame;
296 aout_VolumeSoftInit( p_aout );
298 /* Check for hardware volume support */
299 if( waveOutGetDevCaps( (UINT_PTR)p_aout->output.p_sys->h_waveout,
300 &wocaps, sizeof(wocaps) ) == MMSYSERR_NOERROR &&
301 wocaps.dwSupport & WAVECAPS_VOLUME )
304 if( waveOutGetVolume( p_aout->output.p_sys->h_waveout, &i_dummy )
305 == MMSYSERR_NOERROR )
307 p_aout->output.pf_volume_set = VolumeSet;
313 waveOutReset( p_aout->output.p_sys->h_waveout );
315 /* Allocate silence buffer */
316 p_aout->output.p_sys->p_silence_buffer =
317 malloc( p_aout->output.p_sys->i_buffer_size );
318 if( p_aout->output.p_sys->p_silence_buffer == NULL )
320 free( p_aout->output.p_sys );
323 p_aout->output.p_sys->i_repeat_counter = 0;
326 /* Zero the buffer. WinCE doesn't have calloc(). */
327 memset( p_aout->output.p_sys->p_silence_buffer, 0,
328 p_aout->output.p_sys->i_buffer_size );
330 /* Now we need to setup our waveOut play notification structure */
331 p_aout->output.p_sys->p_notif =
332 vlc_object_create( p_aout, sizeof(notification_thread_t) );
333 p_aout->output.p_sys->p_notif->p_aout = p_aout;
334 p_aout->output.p_sys->event = CreateEvent( NULL, FALSE, FALSE, NULL );
335 p_aout->output.p_sys->new_buffer_event = CreateEvent( NULL, FALSE, FALSE, NULL );
337 /* define startpoint of playback on first call to play()
338 like alsa does (instead of playing a blank sample) */
339 p_aout->output.p_sys->b_playing = 0;
340 p_aout->output.p_sys->start_date = 0;
343 /* Then launch the notification thread */
344 if( vlc_thread_create( p_aout->output.p_sys->p_notif,
345 WaveOutThread, VLC_THREAD_PRIORITY_OUTPUT ) )
347 msg_Err( p_aout, "cannot create WaveOutThread" );
350 /* We need to kick off the playback in order to have the callback properly
352 for( int i = 0; i < FRAMES_NUM; i++ )
354 p_aout->output.p_sys->waveheader[i].dwFlags = WHDR_DONE;
355 p_aout->output.p_sys->waveheader[i].dwUser = 0;
361 /*****************************************************************************
362 * Probe: probe the audio device for available formats and channels
363 *****************************************************************************/
364 static void Probe( aout_instance_t * p_aout )
366 vlc_value_t val, text;
367 vlc_fourcc_t i_format;
368 unsigned int i_physical_channels;
370 var_Create( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
371 text.psz_string = _("Audio Device");
372 var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
374 /* Test for 5.1 support */
375 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
376 AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
377 AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE;
378 if( p_aout->output.output.i_physical_channels == i_physical_channels )
380 if( OpenWaveOutPCM( p_aout,
381 p_aout->output.p_sys->i_wave_device_id,
383 i_physical_channels, 6,
384 p_aout->output.output.i_rate, true )
387 val.i_int = AOUT_VAR_5_1;
388 text.psz_string = (char *)_("5.1");
389 var_Change( p_aout, "audio-device",
390 VLC_VAR_ADDCHOICE, &val, &text );
391 msg_Dbg( p_aout, "device supports 5.1 channels" );
395 /* Test for 2 Front 2 Rear support */
396 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
397 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
398 if( ( p_aout->output.output.i_physical_channels & i_physical_channels )
399 == i_physical_channels )
401 if( OpenWaveOutPCM( p_aout,
402 p_aout->output.p_sys->i_wave_device_id,
404 i_physical_channels, 4,
405 p_aout->output.output.i_rate, true )
408 val.i_int = AOUT_VAR_2F2R;
409 text.psz_string = (char *)_("2 Front 2 Rear");
410 var_Change( p_aout, "audio-device",
411 VLC_VAR_ADDCHOICE, &val, &text );
412 msg_Dbg( p_aout, "device supports 4 channels" );
416 /* Test for stereo support */
417 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
418 if( OpenWaveOutPCM( p_aout,
419 p_aout->output.p_sys->i_wave_device_id,
421 i_physical_channels, 2,
422 p_aout->output.output.i_rate, true )
425 val.i_int = AOUT_VAR_STEREO;
426 text.psz_string = (char *)_("Stereo");
427 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
428 msg_Dbg( p_aout, "device supports 2 channels" );
431 /* Test for mono support */
432 i_physical_channels = AOUT_CHAN_CENTER;
433 if( OpenWaveOutPCM( p_aout,
434 p_aout->output.p_sys->i_wave_device_id,
436 i_physical_channels, 1,
437 p_aout->output.output.i_rate, true )
440 val.i_int = AOUT_VAR_MONO;
441 text.psz_string = (char *)_("Mono");
442 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
443 msg_Dbg( p_aout, "device supports 1 channel" );
446 /* Test for SPDIF support */
447 if ( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
449 if( OpenWaveOut( p_aout,
450 p_aout->output.p_sys->i_wave_device_id,
452 p_aout->output.output.i_physical_channels,
453 aout_FormatNbChannels( &p_aout->output.output ),
454 p_aout->output.output.i_rate, true )
457 msg_Dbg( p_aout, "device supports A/52 over S/PDIF" );
458 val.i_int = AOUT_VAR_SPDIF;
459 text.psz_string = (char *)_("A/52 over S/PDIF");
460 var_Change( p_aout, "audio-device",
461 VLC_VAR_ADDCHOICE, &val, &text );
462 if( var_InheritBool( p_aout, "spdif" ) )
463 var_Set( p_aout, "audio-device", val );
467 var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
470 /* Probe() has failed. */
471 var_Destroy( p_aout, "audio-device" );
475 var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
476 var_SetBool( p_aout, "intf-change", true );
479 /*****************************************************************************
480 * Play: play a sound buffer
481 *****************************************************************************
482 * This doesn't actually play the buffer. This just stores the buffer so it
483 * can be played by the callback thread.
484 *****************************************************************************/
485 static void Play( aout_instance_t *_p_aout )
487 if( !_p_aout->output.p_sys->b_playing )
489 _p_aout->output.p_sys->b_playing = 1;
491 /* get the playing date of the first aout buffer */
492 _p_aout->output.p_sys->start_date =
493 aout_FifoFirstDate( _p_aout, &_p_aout->output.fifo );
495 msg_Dbg( _p_aout, "Wakeup sleeping output thread.");
497 /* wake up the audio output thread */
498 SetEvent( _p_aout->output.p_sys->event );
500 SetEvent( _p_aout->output.p_sys->new_buffer_event );
504 /*****************************************************************************
505 * Close: close the audio device
506 *****************************************************************************/
507 static void Close( vlc_object_t *p_this )
509 aout_instance_t *p_aout = (aout_instance_t *)p_this;
510 aout_sys_t *p_sys = p_aout->output.p_sys;
512 /* Before calling waveOutClose we must reset the device */
513 vlc_object_kill( p_aout );
515 /* wake up the audio thread, to recognize that p_aout died */
516 SetEvent( p_sys->event );
517 SetEvent( p_sys->new_buffer_event );
519 vlc_thread_join( p_sys->p_notif );
520 vlc_object_release( p_sys->p_notif );
523 kill the real output then - when the feed thread
524 is surely terminated!
525 old code could be too early in case that "feeding"
526 was running on termination
528 at this point now its sure, that there will be no new
529 data send to the driver, and we can cancel the last
532 MMRESULT result = waveOutReset( p_sys->h_waveout );
533 if(result != MMSYSERR_NOERROR)
535 msg_Err( p_aout, "waveOutReset failed 0x%x", result );
537 now we must wait, that all buffers are played
538 because cancel doesn't work in this case...
540 if(result == MMSYSERR_NOTSUPPORTED)
543 clear currently played (done) buffers,
544 if returnvalue > 0 (means some buffer still playing)
545 wait for the driver event callback that one buffer
546 is finished with playing, and check again
547 the timeout of 5000ms is just, an emergency exit
548 of this loop, to avoid deadlock in case of other
549 (currently not known bugs, problems, errors cases?)
552 (WaveOutClearDoneBuffers( p_sys ) > 0)
554 (WaitForSingleObject( p_sys->event, 5000) == WAIT_OBJECT_0)
557 msg_Dbg( p_aout, "Wait for waveout device...");
561 WaveOutClearDoneBuffers( p_sys );
564 /* now we can Close the device */
565 if( waveOutClose( p_sys->h_waveout ) != MMSYSERR_NOERROR )
567 msg_Err( p_aout, "waveOutClose failed" );
571 because so long, the waveout device is playing, the callback
572 could occur and need the events
574 CloseHandle( p_sys->event );
575 CloseHandle( p_sys->new_buffer_event);
577 free( p_sys->p_silence_buffer );
581 /*****************************************************************************
582 * OpenWaveOut: open the waveout sound device
583 ****************************************************************************/
584 static int OpenWaveOut( aout_instance_t *p_aout, uint32_t i_device_id, int i_format,
585 int i_channels, int i_nb_channels, int i_rate,
591 /* Set sound format */
593 #define waveformat p_aout->output.p_sys->waveformat
595 waveformat.dwChannelMask = 0;
596 for( i = 0; i < sizeof(pi_channels_src)/sizeof(uint32_t); i++ )
598 if( i_channels & pi_channels_src[i] )
599 waveformat.dwChannelMask |= pi_channels_in[i];
604 case VLC_CODEC_SPDIFL:
606 /* To prevent channel re-ordering */
607 waveformat.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
608 waveformat.Format.wBitsPerSample = 16;
609 waveformat.Samples.wValidBitsPerSample =
610 waveformat.Format.wBitsPerSample;
611 waveformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
612 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF;
616 waveformat.Format.wBitsPerSample = sizeof(float) * 8;
617 waveformat.Samples.wValidBitsPerSample =
618 waveformat.Format.wBitsPerSample;
619 waveformat.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
620 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
624 waveformat.Format.wBitsPerSample = 16;
625 waveformat.Samples.wValidBitsPerSample =
626 waveformat.Format.wBitsPerSample;
627 waveformat.Format.wFormatTag = WAVE_FORMAT_PCM;
628 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_PCM;
632 waveformat.Format.nChannels = i_nb_channels;
633 waveformat.Format.nSamplesPerSec = i_rate;
634 waveformat.Format.nBlockAlign =
635 waveformat.Format.wBitsPerSample / 8 * i_nb_channels;
636 waveformat.Format.nAvgBytesPerSec =
637 waveformat.Format.nSamplesPerSec * waveformat.Format.nBlockAlign;
639 /* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */
640 if( i_nb_channels <= 2 )
642 waveformat.Format.cbSize = 0;
646 waveformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
647 waveformat.Format.cbSize =
648 sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
652 msg_Dbg( p_aout, "OpenWaveDevice-ID: %u", i_device_id);
653 msg_Dbg( p_aout,"waveformat.Format.cbSize = %d",
654 waveformat.Format.cbSize);
655 msg_Dbg( p_aout,"waveformat.Format.wFormatTag = %u",
656 waveformat.Format.wFormatTag);
657 msg_Dbg( p_aout,"waveformat.Format.nChannels = %u",
658 waveformat.Format.nChannels);
659 msg_Dbg( p_aout,"waveformat.Format.nSamplesPerSec = %d",
660 (int)waveformat.Format.nSamplesPerSec);
661 msg_Dbg( p_aout,"waveformat.Format.nAvgBytesPerSec = %u",
662 (int)waveformat.Format.nAvgBytesPerSec);
663 msg_Dbg( p_aout,"waveformat.Format.nBlockAlign = %d",
664 waveformat.Format.nBlockAlign);
665 msg_Dbg( p_aout,"waveformat.Format.wBitsPerSample = %d",
666 waveformat.Format.wBitsPerSample);
667 msg_Dbg( p_aout,"waveformat.Samples.wValidBitsPerSample = %d",
668 waveformat.Samples.wValidBitsPerSample);
669 msg_Dbg( p_aout,"waveformat.Samples.wSamplesPerBlock = %d",
670 waveformat.Samples.wSamplesPerBlock);
671 msg_Dbg( p_aout,"waveformat.dwChannelMask = %lu",
672 waveformat.dwChannelMask);
675 /* Open the device */
676 result = waveOutOpen( &p_aout->output.p_sys->h_waveout, i_device_id,
677 (WAVEFORMATEX *)&waveformat,
678 (DWORD_PTR)WaveOutCallback, (DWORD_PTR)p_aout,
679 CALLBACK_FUNCTION | (b_probe?WAVE_FORMAT_QUERY:0) );
680 if( result == WAVERR_BADFORMAT )
682 msg_Warn( p_aout, "waveOutOpen failed WAVERR_BADFORMAT" );
685 if( result == MMSYSERR_ALLOCATED )
687 msg_Warn( p_aout, "waveOutOpen failed WAVERR_ALLOCATED" );
690 if( result != MMSYSERR_NOERROR )
692 msg_Warn( p_aout, "waveOutOpen failed" );
696 p_aout->output.p_sys->b_chan_reorder =
697 aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
698 waveformat.dwChannelMask, i_nb_channels,
699 p_aout->output.p_sys->pi_chan_table );
701 if( p_aout->output.p_sys->b_chan_reorder )
703 msg_Dbg( p_aout, "channel reordering needed" );
712 /*****************************************************************************
713 * OpenWaveOutPCM: open a PCM waveout sound device
714 ****************************************************************************/
715 static int OpenWaveOutPCM( aout_instance_t *p_aout, uint32_t i_device_id,
716 vlc_fourcc_t *i_format,
717 int i_channels, int i_nb_channels, int i_rate,
720 bool b_use_float32 = var_CreateGetBool( p_aout, "waveout-float32");
722 if( !b_use_float32 || OpenWaveOut( p_aout, i_device_id, VLC_CODEC_FL32,
723 i_channels, i_nb_channels, i_rate, b_probe )
726 if ( OpenWaveOut( p_aout, i_device_id, VLC_CODEC_S16L,
727 i_channels, i_nb_channels, i_rate, b_probe )
734 *i_format = VLC_CODEC_S16L;
740 *i_format = VLC_CODEC_FL32;
745 /*****************************************************************************
746 * PlayWaveOut: play a buffer through the WaveOut device
747 *****************************************************************************/
748 static int PlayWaveOut( aout_instance_t *p_aout, HWAVEOUT h_waveout,
749 WAVEHDR *p_waveheader, aout_buffer_t *p_buffer,
754 /* Prepare the buffer */
755 if( p_buffer != NULL )
757 p_waveheader->lpData = p_buffer->p_buffer;
759 copy the buffer to the silence buffer :) so in case we don't
760 get the next buffer fast enough (I will repeat this one a time
761 for AC3 / DTS and SPDIF this will sound better instead of
766 vlc_memcpy( p_aout->output.p_sys->p_silence_buffer,
768 p_aout->output.p_sys->i_buffer_size );
769 p_aout->output.p_sys->i_repeat_counter = 2;
772 /* Use silence buffer instead */
773 if(p_aout->output.p_sys->i_repeat_counter)
775 p_aout->output.p_sys->i_repeat_counter--;
776 if(!p_aout->output.p_sys->i_repeat_counter)
778 vlc_memset( p_aout->output.p_sys->p_silence_buffer,
779 0x00, p_aout->output.p_sys->i_buffer_size );
782 p_waveheader->lpData = p_aout->output.p_sys->p_silence_buffer;
785 p_waveheader->dwUser = p_buffer ? (DWORD_PTR)p_buffer : (DWORD_PTR)1;
786 p_waveheader->dwBufferLength = p_aout->output.p_sys->i_buffer_size;
787 p_waveheader->dwFlags = 0;
789 result = waveOutPrepareHeader( h_waveout, p_waveheader, sizeof(WAVEHDR) );
790 if( result != MMSYSERR_NOERROR )
792 msg_Err( p_aout, "waveOutPrepareHeader failed" );
796 /* Send the buffer to the waveOut queue */
797 result = waveOutWrite( h_waveout, p_waveheader, sizeof(WAVEHDR) );
798 if( result != MMSYSERR_NOERROR )
800 msg_Err( p_aout, "waveOutWrite failed" );
807 /*****************************************************************************
808 * WaveOutCallback: what to do once WaveOut has played its sound samples
809 *****************************************************************************/
810 static void CALLBACK WaveOutCallback( HWAVEOUT h_waveout, UINT uMsg,
812 DWORD dwParam1, DWORD dwParam2 )
814 (void)h_waveout; (void)dwParam1; (void)dwParam2;
815 aout_instance_t *p_aout = (aout_instance_t *)_p_aout;
816 int i, i_queued_frames = 0;
818 if( uMsg != WOM_DONE ) return;
820 if( !vlc_object_alive (p_aout) ) return;
822 /* Find out the current latency */
823 for( i = 0; i < FRAMES_NUM; i++ )
825 /* Check if frame buf is available */
826 if( !(p_aout->output.p_sys->waveheader[i].dwFlags & WHDR_DONE) )
832 /* Don't wake up the thread too much */
833 if( i_queued_frames <= FRAMES_NUM/2 )
834 SetEvent( p_aout->output.p_sys->event );
838 /****************************************************************************
839 * WaveOutClearDoneBuffers: Clear all done marked buffers, and free aout_bufer
840 ****************************************************************************
841 * return value is the number of still playing buffers in the queue
842 ****************************************************************************/
843 static int WaveOutClearDoneBuffers(aout_sys_t *p_sys)
845 WAVEHDR *p_waveheader = p_sys->waveheader;
846 int i_queued_frames = 0;
848 for( int i = 0; i < FRAMES_NUM; i++ )
850 if( (p_waveheader[i].dwFlags & WHDR_DONE) &&
851 p_waveheader[i].dwUser )
853 aout_buffer_t *p_buffer =
854 (aout_buffer_t *)(p_waveheader[i].dwUser);
855 /* Unprepare and free the buffers which has just been played */
856 waveOutUnprepareHeader( p_sys->h_waveout, &p_waveheader[i],
859 if( p_waveheader[i].dwUser != 1 )
860 aout_BufferFree( p_buffer );
862 p_waveheader[i].dwUser = 0;
865 /* Check if frame buf is available */
866 if( !(p_waveheader[i].dwFlags & WHDR_DONE) )
871 return i_queued_frames;
874 /*****************************************************************************
875 * WaveOutThread: this thread will capture play notification events.
876 *****************************************************************************
877 * We use this thread to feed new audio samples to the sound card because
878 * we are not authorized to use waveOutWrite() directly in the waveout
880 *****************************************************************************/
881 static void* WaveOutThread( vlc_object_t *p_this )
883 notification_thread_t *p_notif = (notification_thread_t*)p_this;
884 aout_instance_t *p_aout = p_notif->p_aout;
885 aout_sys_t *p_sys = p_aout->output.p_sys;
886 aout_buffer_t *p_buffer = NULL;
887 WAVEHDR *p_waveheader = p_sys->waveheader;
888 int i, i_queued_frames;
891 uint32_t i_buffer_length = 64;
892 int canc = vlc_savecancel ();
894 /* We don't want any resampling when using S/PDIF */
895 b_sleek = p_aout->output.output.i_format == VLC_CODEC_SPDIFL;
897 // wait for first call to "play()"
898 while( !p_sys->start_date && vlc_object_alive (p_aout) )
899 WaitForSingleObject( p_sys->event, INFINITE );
900 if( !vlc_object_alive (p_aout) )
903 msg_Dbg( p_aout, "will start to play in %"PRId64" us",
904 (p_sys->start_date - AOUT_PTS_TOLERANCE/4)-mdate());
906 // than wait a short time... before grabbing first frames
907 mwait( p_sys->start_date - AOUT_PTS_TOLERANCE/4 );
909 #define waveout_warn(msg) msg_Warn( p_aout, "aout_OutputNextBuffer no buffer "\
910 "got next_date=%d ms, "\
911 "%d frames to play, "\
912 "starving? %d, %s",(int)(next_date/(mtime_t)1000), \
914 p_aout->output.b_starving, msg);
917 while( vlc_object_alive (p_aout) )
919 /* Cleanup and find out the current latency */
920 i_queued_frames = WaveOutClearDoneBuffers( p_sys );
922 if( !vlc_object_alive (p_aout) ) 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->output.output.i_rate * p_aout->output.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_OutputNextBuffer( p_aout,
946 msg_Dbg( p_aout, "aout_OutputNextBuffer no buffer "\
947 "got next_date=%d ms, "\
948 "%d frames to play, "\
949 "starving? %d",(int)(next_date/(mtime_t)1000),
951 p_aout->output.b_starving);
953 if(p_aout->output.b_starving)
955 // means we are too early to request a new buffer?
956 waveout_warn("waiting...")
957 next_date = aout_FifoFirstDate( p_aout, &p_aout->output.fifo );
958 mwait( next_date - AOUT_PTS_TOLERANCE/4 );
960 p_buffer = aout_OutputNextBuffer( p_aout,
967 if( !p_buffer && i_queued_frames )
969 /* We aren't late so no need to play a blank sample */
975 mtime_t buffer_length = p_buffer->i_length;
976 next_date = next_date + buffer_length;
977 i_buffer_length = buffer_length/1000;
980 /* Do the channel reordering */
981 if( p_buffer && p_sys->b_chan_reorder )
983 aout_ChannelReorder( p_buffer->p_buffer,
985 p_sys->waveformat.Format.nChannels,
986 p_sys->pi_chan_table,
987 p_sys->waveformat.Format.wBitsPerSample );
990 PlayWaveOut( p_aout, p_sys->h_waveout,
991 &p_waveheader[i], p_buffer, b_sleek );
997 if( !vlc_object_alive (p_aout) ) return NULL;
1000 deal with the case that the loop didn't fillup the buffer to the
1001 max - instead of waiting that half the buffer is played before
1002 fillup the waveout buffers, wait only for the next sample buffer
1003 to arrive at the play method...
1005 this will also avoid, that the last buffer is play until the
1006 end, and then trying to get more data, so it will also
1007 work - if the next buffer will arrive some ms before the
1008 last buffer is finished.
1010 if(i_queued_frames < FRAMES_NUM)
1011 WaitForSingleObject( p_sys->new_buffer_event, INFINITE );
1013 WaitForSingleObject( p_sys->event, INFINITE );
1018 vlc_restorecancel (canc);
1022 static int VolumeSet( aout_instance_t * p_aout, audio_volume_t i_volume )
1024 unsigned long i_waveout_vol = i_volume * 0xFFFF * 2 / AOUT_VOLUME_MAX;
1025 i_waveout_vol |= (i_waveout_vol << 16);
1028 waveOutSetVolume( 0, i_waveout_vol );
1030 waveOutSetVolume( p_aout->output.p_sys->h_waveout, i_waveout_vol );
1033 p_aout->output.i_volume = i_volume;
1039 reload the configuration drop down list, of the Audio Devices
1041 static int ReloadWaveoutDevices( vlc_object_t *p_this, char const *psz_name,
1042 vlc_value_t newval, vlc_value_t oldval, void *data )
1044 VLC_UNUSED( newval ); VLC_UNUSED( oldval ); VLC_UNUSED( data );
1046 module_config_t *p_item = config_FindConfig( p_this, psz_name );
1047 if( !p_item ) return VLC_SUCCESS;
1049 /* Clear-up the current list */
1050 if( p_item->i_list )
1054 /* Keep the first entry */
1055 for( i = 1; i < p_item->i_list; i++ )
1057 free((char *)(p_item->ppsz_list[i]) );
1058 free((char *)(p_item->ppsz_list_text[i]) );
1060 /* TODO: Remove when no more needed */
1061 p_item->ppsz_list[i] = NULL;
1062 p_item->ppsz_list_text[i] = NULL;
1066 int wave_devices = waveOutGetNumDevs();
1068 p_item->ppsz_list = xrealloc( p_item->ppsz_list,
1069 (wave_devices+2) * sizeof(char *) );
1070 p_item->ppsz_list_text = xrealloc( p_item->ppsz_list_text,
1071 (wave_devices+2) * sizeof(char *) );
1074 char sz_dev_name[MAXPNAMELEN+32];
1076 for(int i=0; i<wave_devices; i++)
1078 if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
1079 == MMSYSERR_NOERROR)
1081 sprintf( sz_dev_name, psz_device_name_fmt, caps.szPname,
1085 p_item->ppsz_list[j] = FromLocaleDup( sz_dev_name );
1086 p_item->ppsz_list_text[j] = FromLocaleDup( sz_dev_name );
1092 p_item->ppsz_list[j] = NULL;
1093 p_item->ppsz_list_text[j] = NULL;
1095 /* Signal change to the interface */
1096 p_item->b_dirty = true;
1102 convert devicename to device ID for output
1103 if device not found return WAVE_MAPPER, so let
1104 windows decide which preferred audio device
1107 static uint32_t findDeviceID(char *psz_device_name)
1109 if(!psz_device_name)
1112 uint32_t wave_devices = waveOutGetNumDevs();
1114 char sz_dev_name[MAXPNAMELEN+32];
1115 for(uint32_t i=0; i<wave_devices; i++)
1117 if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
1118 == MMSYSERR_NOERROR)
1120 sprintf(sz_dev_name, psz_device_name_fmt, caps.szPname,
1124 char *psz_temp = FromLocaleDup(sz_dev_name);
1126 if( !stricmp(psz_temp, psz_device_name) )
1128 LocaleFree( psz_temp );
1131 LocaleFree( psz_temp );