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 *****************************************************************************/
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
36 #include <vlc_charset.h> /* FromLocaleDup, LocaleFree */
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, bool );
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") };
85 /*****************************************************************************
87 *****************************************************************************/
88 #define DEVICE_TEXT N_("Select Audio Device")
89 #define DEVICE_LONG N_("Select special Audio device, or let windows "\
90 "decide (default), change needs VLC restart "\
92 #define DEFAULT_AUDIO_DEVICE N_("Default Audio Device")
95 set_shortname( "WaveOut" )
96 set_description( N_("Win32 waveOut extension output") )
97 set_capability( "audio output", 50 )
98 set_category( CAT_AUDIO )
99 set_subcategory( SUBCAT_AUDIO_AOUT )
100 add_bool( "waveout-float32", true, FLOAT_TEXT, FLOAT_LONGTEXT, true )
102 add_string( "waveout-audio-device", "wavemapper",
103 DEVICE_TEXT, DEVICE_LONG, false )
104 add_deprecated_alias( "waveout-dev" ) /* deprecated since 0.9.3 */
105 change_string_list( ppsz_adev, ppsz_adev_text, ReloadWaveoutDevices )
106 change_action_add( ReloadWaveoutDevices, N_("Refresh list") )
108 set_callbacks( Open, Close )
111 /*****************************************************************************
112 * aout_sys_t: waveOut audio output method descriptor
113 *****************************************************************************
114 * This structure is part of the audio output thread descriptor.
115 * It describes the waveOut specific properties of an audio device.
116 *****************************************************************************/
119 uint32_t i_wave_device_id; /* ID of selected output device */
121 HWAVEOUT h_waveout; /* handle to waveout instance */
123 WAVEFORMATEXTENSIBLE waveformat; /* audio format */
125 WAVEHDR waveheader[FRAMES_NUM];
127 notification_thread_t *p_notif; /* WaveOutThread id */
129 HANDLE new_buffer_event;
131 // rental from alsa.c to synchronize startup of audiothread
132 int b_playing; /* playing status */
135 int i_repeat_counter;
139 uint8_t *p_silence_buffer; /* buffer we use to play silence */
141 bool b_chan_reorder; /* do we need channel reordering */
142 int pi_chan_table[AOUT_CHAN_MAX];
145 /*****************************************************************************
146 * Open: open the audio device
147 *****************************************************************************
148 * This function opens and setups Win32 waveOut
149 *****************************************************************************/
150 static int Open( vlc_object_t *p_this )
152 aout_instance_t *p_aout = (aout_instance_t *)p_this;
155 /* Allocate structure */
156 p_aout->output.p_sys = malloc( sizeof( aout_sys_t ) );
158 if( p_aout->output.p_sys == NULL )
161 p_aout->output.pf_play = Play;
162 p_aout->b_die = false;
166 initialize/update Device selection List
168 ReloadWaveoutDevices( p_this, "waveout-audio-device", val, val, NULL);
172 check for configured audio device!
174 char *psz_waveout_dev = var_CreateGetString( p_aout, "waveout-audio-device");
176 p_aout->output.p_sys->i_wave_device_id =
177 findDeviceID( psz_waveout_dev );
179 if(p_aout->output.p_sys->i_wave_device_id == WAVE_MAPPER)
181 if(psz_waveout_dev &&
182 stricmp(psz_waveout_dev,"wavemapper"))
184 msg_Warn( p_aout, "configured audio device '%s' not available, "\
185 "use default instead", psz_waveout_dev );
188 free( psz_waveout_dev );
191 WAVEOUTCAPS waveoutcaps;
192 if(waveOutGetDevCaps( p_aout->output.p_sys->i_wave_device_id,
194 sizeof(WAVEOUTCAPS)) == MMSYSERR_NOERROR)
196 /* log debug some infos about driver, to know who to blame
197 if it doesn't work */
198 msg_Dbg( p_aout, "Drivername: %s", waveoutcaps.szPname);
199 msg_Dbg( p_aout, "Driver Version: %d.%d",
200 (waveoutcaps.vDriverVersion>>8)&255,
201 waveoutcaps.vDriverVersion & 255);
202 msg_Dbg( p_aout, "Manufacturer identifier: 0x%x", waveoutcaps.wMid );
203 msg_Dbg( p_aout, "Product identifier: 0x%x", waveoutcaps.wPid );
208 if( var_Type( p_aout, "audio-device" ) == 0 )
213 if( var_Get( p_aout, "audio-device", &val ) < 0 )
215 /* Probe() has failed. */
216 var_Destroy( p_aout, "waveout-audio-device");
217 free( p_aout->output.p_sys );
222 /* Open the device */
223 if( val.i_int == AOUT_VAR_SPDIF )
225 p_aout->output.output.i_format = VLC_CODEC_SPDIFL;
227 if( OpenWaveOut( p_aout,
228 p_aout->output.p_sys->i_wave_device_id,
230 p_aout->output.output.i_physical_channels,
231 aout_FormatNbChannels( &p_aout->output.output ),
232 p_aout->output.output.i_rate, false )
235 msg_Err( p_aout, "cannot open waveout audio device" );
236 free( p_aout->output.p_sys );
240 /* Calculate the frame size in bytes */
241 p_aout->output.i_nb_samples = A52_FRAME_NB;
242 p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
243 p_aout->output.output.i_frame_length = A52_FRAME_NB;
244 p_aout->output.p_sys->i_buffer_size =
245 p_aout->output.output.i_bytes_per_frame;
247 aout_VolumeNoneInit( p_aout );
256 p_aout->output.output.i_physical_channels
257 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
258 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
262 p_aout->output.output.i_physical_channels
263 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
264 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
267 p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
270 p_aout->output.output.i_physical_channels
271 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
274 if( OpenWaveOutPCM( p_aout,
275 p_aout->output.p_sys->i_wave_device_id,
276 &p_aout->output.output.i_format,
277 p_aout->output.output.i_physical_channels,
278 aout_FormatNbChannels( &p_aout->output.output ),
279 p_aout->output.output.i_rate, false )
282 msg_Err( p_aout, "cannot open waveout audio device" );
283 free( p_aout->output.p_sys );
287 /* Calculate the frame size in bytes */
288 p_aout->output.i_nb_samples = FRAME_SIZE;
289 aout_FormatPrepare( &p_aout->output.output );
290 p_aout->output.p_sys->i_buffer_size = FRAME_SIZE *
291 p_aout->output.output.i_bytes_per_frame;
293 aout_VolumeSoftInit( p_aout );
295 /* Check for hardware volume support */
296 if( waveOutGetDevCaps( (UINT_PTR)p_aout->output.p_sys->h_waveout,
297 &wocaps, sizeof(wocaps) ) == MMSYSERR_NOERROR &&
298 wocaps.dwSupport & WAVECAPS_VOLUME )
301 if( waveOutGetVolume( p_aout->output.p_sys->h_waveout, &i_dummy )
302 == MMSYSERR_NOERROR )
304 p_aout->output.pf_volume_set = VolumeSet;
310 waveOutReset( p_aout->output.p_sys->h_waveout );
312 /* Allocate silence buffer */
313 p_aout->output.p_sys->p_silence_buffer =
314 malloc( p_aout->output.p_sys->i_buffer_size );
315 if( p_aout->output.p_sys->p_silence_buffer == NULL )
317 free( p_aout->output.p_sys );
320 p_aout->output.p_sys->i_repeat_counter = 0;
323 /* Zero the buffer. WinCE doesn't have calloc(). */
324 memset( p_aout->output.p_sys->p_silence_buffer, 0,
325 p_aout->output.p_sys->i_buffer_size );
327 /* Now we need to setup our waveOut play notification structure */
328 p_aout->output.p_sys->p_notif =
329 vlc_object_create( p_aout, sizeof(notification_thread_t) );
330 p_aout->output.p_sys->p_notif->p_aout = p_aout;
331 p_aout->output.p_sys->event = CreateEvent( NULL, FALSE, FALSE, NULL );
332 p_aout->output.p_sys->new_buffer_event = CreateEvent( NULL, FALSE, FALSE, NULL );
334 /* define startpoint of playback on first call to play()
335 like alsa does (instead of playing a blank sample) */
336 p_aout->output.p_sys->b_playing = 0;
337 p_aout->output.p_sys->start_date = 0;
340 /* Then launch the notification thread */
341 if( vlc_thread_create( p_aout->output.p_sys->p_notif,
342 WaveOutThread, VLC_THREAD_PRIORITY_OUTPUT ) )
344 msg_Err( p_aout, "cannot create WaveOutThread" );
347 /* We need to kick off the playback in order to have the callback properly
349 for( int i = 0; i < FRAMES_NUM; i++ )
351 p_aout->output.p_sys->waveheader[i].dwFlags = WHDR_DONE;
352 p_aout->output.p_sys->waveheader[i].dwUser = 0;
358 /*****************************************************************************
359 * Probe: probe the audio device for available formats and channels
360 *****************************************************************************/
361 static void Probe( aout_instance_t * p_aout )
363 vlc_value_t val, text;
364 vlc_fourcc_t i_format;
365 unsigned int i_physical_channels;
367 var_Create( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
368 text.psz_string = _("Audio Device");
369 var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
371 /* Test for 5.1 support */
372 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
373 AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
374 AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE;
375 if( p_aout->output.output.i_physical_channels == i_physical_channels )
377 if( OpenWaveOutPCM( p_aout,
378 p_aout->output.p_sys->i_wave_device_id,
380 i_physical_channels, 6,
381 p_aout->output.output.i_rate, true )
384 val.i_int = AOUT_VAR_5_1;
385 text.psz_string = (char *)_("5.1");
386 var_Change( p_aout, "audio-device",
387 VLC_VAR_ADDCHOICE, &val, &text );
388 msg_Dbg( p_aout, "device supports 5.1 channels" );
392 /* Test for 2 Front 2 Rear support */
393 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
394 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
395 if( ( p_aout->output.output.i_physical_channels & i_physical_channels )
396 == i_physical_channels )
398 if( OpenWaveOutPCM( p_aout,
399 p_aout->output.p_sys->i_wave_device_id,
401 i_physical_channels, 4,
402 p_aout->output.output.i_rate, true )
405 val.i_int = AOUT_VAR_2F2R;
406 text.psz_string = (char *)_("2 Front 2 Rear");
407 var_Change( p_aout, "audio-device",
408 VLC_VAR_ADDCHOICE, &val, &text );
409 msg_Dbg( p_aout, "device supports 4 channels" );
413 /* Test for stereo support */
414 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
415 if( OpenWaveOutPCM( p_aout,
416 p_aout->output.p_sys->i_wave_device_id,
418 i_physical_channels, 2,
419 p_aout->output.output.i_rate, true )
422 val.i_int = AOUT_VAR_STEREO;
423 text.psz_string = (char *)_("Stereo");
424 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
425 msg_Dbg( p_aout, "device supports 2 channels" );
428 /* Test for mono support */
429 i_physical_channels = AOUT_CHAN_CENTER;
430 if( OpenWaveOutPCM( p_aout,
431 p_aout->output.p_sys->i_wave_device_id,
433 i_physical_channels, 1,
434 p_aout->output.output.i_rate, true )
437 val.i_int = AOUT_VAR_MONO;
438 text.psz_string = (char *)_("Mono");
439 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
440 msg_Dbg( p_aout, "device supports 1 channel" );
443 /* Test for SPDIF support */
444 if ( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
446 if( OpenWaveOut( p_aout,
447 p_aout->output.p_sys->i_wave_device_id,
449 p_aout->output.output.i_physical_channels,
450 aout_FormatNbChannels( &p_aout->output.output ),
451 p_aout->output.output.i_rate, true )
454 msg_Dbg( p_aout, "device supports A/52 over S/PDIF" );
455 val.i_int = AOUT_VAR_SPDIF;
456 text.psz_string = (char *)_("A/52 over S/PDIF");
457 var_Change( p_aout, "audio-device",
458 VLC_VAR_ADDCHOICE, &val, &text );
459 if( var_InheritBool( p_aout, "spdif" ) )
460 var_Set( p_aout, "audio-device", val );
464 var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
467 /* Probe() has failed. */
468 var_Destroy( p_aout, "audio-device" );
472 var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
473 var_TriggerCallback( p_aout, "intf-change" );
476 /*****************************************************************************
477 * Play: play a sound buffer
478 *****************************************************************************
479 * This doesn't actually play the buffer. This just stores the buffer so it
480 * can be played by the callback thread.
481 *****************************************************************************/
482 static void Play( aout_instance_t *_p_aout )
484 if( !_p_aout->output.p_sys->b_playing )
486 _p_aout->output.p_sys->b_playing = 1;
488 /* get the playing date of the first aout buffer */
489 _p_aout->output.p_sys->start_date =
490 aout_FifoFirstDate( _p_aout, &_p_aout->output.fifo );
492 msg_Dbg( _p_aout, "Wakeup sleeping output thread.");
494 /* wake up the audio output thread */
495 SetEvent( _p_aout->output.p_sys->event );
497 SetEvent( _p_aout->output.p_sys->new_buffer_event );
501 /*****************************************************************************
502 * Close: close the audio device
503 *****************************************************************************/
504 static void Close( vlc_object_t *p_this )
506 aout_instance_t *p_aout = (aout_instance_t *)p_this;
507 aout_sys_t *p_sys = p_aout->output.p_sys;
509 /* Before calling waveOutClose we must reset the device */
510 vlc_object_kill( p_aout );
512 /* wake up the audio thread, to recognize that p_aout died */
513 SetEvent( p_sys->event );
514 SetEvent( p_sys->new_buffer_event );
516 vlc_thread_join( p_sys->p_notif );
517 vlc_object_release( p_sys->p_notif );
520 kill the real output then - when the feed thread
521 is surely terminated!
522 old code could be too early in case that "feeding"
523 was running on termination
525 at this point now its sure, that there will be no new
526 data send to the driver, and we can cancel the last
529 MMRESULT result = waveOutReset( p_sys->h_waveout );
530 if(result != MMSYSERR_NOERROR)
532 msg_Err( p_aout, "waveOutReset failed 0x%x", result );
534 now we must wait, that all buffers are played
535 because cancel doesn't work in this case...
537 if(result == MMSYSERR_NOTSUPPORTED)
540 clear currently played (done) buffers,
541 if returnvalue > 0 (means some buffer still playing)
542 wait for the driver event callback that one buffer
543 is finished with playing, and check again
544 the timeout of 5000ms is just, an emergency exit
545 of this loop, to avoid deadlock in case of other
546 (currently not known bugs, problems, errors cases?)
549 (WaveOutClearDoneBuffers( p_sys ) > 0)
551 (WaitForSingleObject( p_sys->event, 5000) == WAIT_OBJECT_0)
554 msg_Dbg( p_aout, "Wait for waveout device...");
558 WaveOutClearDoneBuffers( p_sys );
561 /* now we can Close the device */
562 if( waveOutClose( p_sys->h_waveout ) != MMSYSERR_NOERROR )
564 msg_Err( p_aout, "waveOutClose failed" );
568 because so long, the waveout device is playing, the callback
569 could occur and need the events
571 CloseHandle( p_sys->event );
572 CloseHandle( p_sys->new_buffer_event);
574 free( p_sys->p_silence_buffer );
578 /*****************************************************************************
579 * OpenWaveOut: open the waveout sound device
580 ****************************************************************************/
581 static int OpenWaveOut( aout_instance_t *p_aout, uint32_t i_device_id, int i_format,
582 int i_channels, int i_nb_channels, int i_rate,
587 /* Set sound format */
589 #define waveformat p_aout->output.p_sys->waveformat
591 waveformat.dwChannelMask = 0;
592 for( unsigned i = 0; i < sizeof(pi_channels_src)/sizeof(uint32_t); i++ )
594 if( i_channels & pi_channels_src[i] )
595 waveformat.dwChannelMask |= pi_channels_in[i];
600 case VLC_CODEC_SPDIFL:
602 /* To prevent channel re-ordering */
603 waveformat.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
604 waveformat.Format.wBitsPerSample = 16;
605 waveformat.Samples.wValidBitsPerSample =
606 waveformat.Format.wBitsPerSample;
607 waveformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
608 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF;
612 waveformat.Format.wBitsPerSample = sizeof(float) * 8;
613 waveformat.Samples.wValidBitsPerSample =
614 waveformat.Format.wBitsPerSample;
615 waveformat.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
616 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
620 waveformat.Format.wBitsPerSample = 16;
621 waveformat.Samples.wValidBitsPerSample =
622 waveformat.Format.wBitsPerSample;
623 waveformat.Format.wFormatTag = WAVE_FORMAT_PCM;
624 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_PCM;
628 waveformat.Format.nChannels = i_nb_channels;
629 waveformat.Format.nSamplesPerSec = i_rate;
630 waveformat.Format.nBlockAlign =
631 waveformat.Format.wBitsPerSample / 8 * i_nb_channels;
632 waveformat.Format.nAvgBytesPerSec =
633 waveformat.Format.nSamplesPerSec * waveformat.Format.nBlockAlign;
635 /* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */
636 if( i_nb_channels <= 2 )
638 waveformat.Format.cbSize = 0;
642 waveformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
643 waveformat.Format.cbSize =
644 sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
648 msg_Dbg( p_aout, "OpenWaveDevice-ID: %u", i_device_id);
649 msg_Dbg( p_aout,"waveformat.Format.cbSize = %d",
650 waveformat.Format.cbSize);
651 msg_Dbg( p_aout,"waveformat.Format.wFormatTag = %u",
652 waveformat.Format.wFormatTag);
653 msg_Dbg( p_aout,"waveformat.Format.nChannels = %u",
654 waveformat.Format.nChannels);
655 msg_Dbg( p_aout,"waveformat.Format.nSamplesPerSec = %d",
656 (int)waveformat.Format.nSamplesPerSec);
657 msg_Dbg( p_aout,"waveformat.Format.nAvgBytesPerSec = %u",
658 (int)waveformat.Format.nAvgBytesPerSec);
659 msg_Dbg( p_aout,"waveformat.Format.nBlockAlign = %d",
660 waveformat.Format.nBlockAlign);
661 msg_Dbg( p_aout,"waveformat.Format.wBitsPerSample = %d",
662 waveformat.Format.wBitsPerSample);
663 msg_Dbg( p_aout,"waveformat.Samples.wValidBitsPerSample = %d",
664 waveformat.Samples.wValidBitsPerSample);
665 msg_Dbg( p_aout,"waveformat.Samples.wSamplesPerBlock = %d",
666 waveformat.Samples.wSamplesPerBlock);
667 msg_Dbg( p_aout,"waveformat.dwChannelMask = %lu",
668 waveformat.dwChannelMask);
671 /* Open the device */
672 result = waveOutOpen( &p_aout->output.p_sys->h_waveout, i_device_id,
673 (WAVEFORMATEX *)&waveformat,
674 (DWORD_PTR)WaveOutCallback, (DWORD_PTR)p_aout,
675 CALLBACK_FUNCTION | (b_probe?WAVE_FORMAT_QUERY:0) );
676 if( result == WAVERR_BADFORMAT )
678 msg_Warn( p_aout, "waveOutOpen failed WAVERR_BADFORMAT" );
681 if( result == MMSYSERR_ALLOCATED )
683 msg_Warn( p_aout, "waveOutOpen failed WAVERR_ALLOCATED" );
686 if( result != MMSYSERR_NOERROR )
688 msg_Warn( p_aout, "waveOutOpen failed" );
692 p_aout->output.p_sys->b_chan_reorder =
693 aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
694 waveformat.dwChannelMask, i_nb_channels,
695 p_aout->output.p_sys->pi_chan_table );
697 if( p_aout->output.p_sys->b_chan_reorder )
699 msg_Dbg( p_aout, "channel reordering needed" );
708 /*****************************************************************************
709 * OpenWaveOutPCM: open a PCM waveout sound device
710 ****************************************************************************/
711 static int OpenWaveOutPCM( aout_instance_t *p_aout, uint32_t i_device_id,
712 vlc_fourcc_t *i_format,
713 int i_channels, int i_nb_channels, int i_rate,
716 bool b_use_float32 = var_CreateGetBool( p_aout, "waveout-float32");
718 if( !b_use_float32 || OpenWaveOut( p_aout, i_device_id, VLC_CODEC_FL32,
719 i_channels, i_nb_channels, i_rate, b_probe )
722 if ( OpenWaveOut( p_aout, i_device_id, VLC_CODEC_S16L,
723 i_channels, i_nb_channels, i_rate, b_probe )
730 *i_format = VLC_CODEC_S16L;
736 *i_format = VLC_CODEC_FL32;
741 /*****************************************************************************
742 * PlayWaveOut: play a buffer through the WaveOut device
743 *****************************************************************************/
744 static int PlayWaveOut( aout_instance_t *p_aout, HWAVEOUT h_waveout,
745 WAVEHDR *p_waveheader, aout_buffer_t *p_buffer,
750 /* Prepare the buffer */
751 if( p_buffer != NULL )
753 p_waveheader->lpData = (LPSTR)p_buffer->p_buffer;
755 copy the buffer to the silence buffer :) so in case we don't
756 get the next buffer fast enough (I will repeat this one a time
757 for AC3 / DTS and SPDIF this will sound better instead of
762 vlc_memcpy( p_aout->output.p_sys->p_silence_buffer,
764 p_aout->output.p_sys->i_buffer_size );
765 p_aout->output.p_sys->i_repeat_counter = 2;
768 /* Use silence buffer instead */
769 if(p_aout->output.p_sys->i_repeat_counter)
771 p_aout->output.p_sys->i_repeat_counter--;
772 if(!p_aout->output.p_sys->i_repeat_counter)
774 vlc_memset( p_aout->output.p_sys->p_silence_buffer,
775 0x00, p_aout->output.p_sys->i_buffer_size );
778 p_waveheader->lpData = (LPSTR)p_aout->output.p_sys->p_silence_buffer;
781 p_waveheader->dwUser = p_buffer ? (DWORD_PTR)p_buffer : (DWORD_PTR)1;
782 p_waveheader->dwBufferLength = p_aout->output.p_sys->i_buffer_size;
783 p_waveheader->dwFlags = 0;
785 result = waveOutPrepareHeader( h_waveout, p_waveheader, sizeof(WAVEHDR) );
786 if( result != MMSYSERR_NOERROR )
788 msg_Err( p_aout, "waveOutPrepareHeader failed" );
792 /* Send the buffer to the waveOut queue */
793 result = waveOutWrite( h_waveout, p_waveheader, sizeof(WAVEHDR) );
794 if( result != MMSYSERR_NOERROR )
796 msg_Err( p_aout, "waveOutWrite failed" );
803 /*****************************************************************************
804 * WaveOutCallback: what to do once WaveOut has played its sound samples
805 *****************************************************************************/
806 static void CALLBACK WaveOutCallback( HWAVEOUT h_waveout, UINT uMsg,
808 DWORD dwParam1, DWORD dwParam2 )
810 (void)h_waveout; (void)dwParam1; (void)dwParam2;
811 aout_instance_t *p_aout = (aout_instance_t *)_p_aout;
812 int i_queued_frames = 0;
814 if( uMsg != WOM_DONE ) return;
816 if( !vlc_object_alive (p_aout) ) return;
818 /* Find out the current latency */
819 for( int i = 0; i < FRAMES_NUM; i++ )
821 /* Check if frame buf is available */
822 if( !(p_aout->output.p_sys->waveheader[i].dwFlags & WHDR_DONE) )
828 /* Don't wake up the thread too much */
829 if( i_queued_frames <= FRAMES_NUM/2 )
830 SetEvent( p_aout->output.p_sys->event );
834 /****************************************************************************
835 * WaveOutClearDoneBuffers: Clear all done marked buffers, and free aout_bufer
836 ****************************************************************************
837 * return value is the number of still playing buffers in the queue
838 ****************************************************************************/
839 static int WaveOutClearDoneBuffers(aout_sys_t *p_sys)
841 WAVEHDR *p_waveheader = p_sys->waveheader;
842 int i_queued_frames = 0;
844 for( int i = 0; i < FRAMES_NUM; i++ )
846 if( (p_waveheader[i].dwFlags & WHDR_DONE) &&
847 p_waveheader[i].dwUser )
849 aout_buffer_t *p_buffer =
850 (aout_buffer_t *)(p_waveheader[i].dwUser);
851 /* Unprepare and free the buffers which has just been played */
852 waveOutUnprepareHeader( p_sys->h_waveout, &p_waveheader[i],
855 if( p_waveheader[i].dwUser != 1 )
856 aout_BufferFree( p_buffer );
858 p_waveheader[i].dwUser = 0;
861 /* Check if frame buf is available */
862 if( !(p_waveheader[i].dwFlags & WHDR_DONE) )
867 return i_queued_frames;
870 /*****************************************************************************
871 * WaveOutThread: this thread will capture play notification events.
872 *****************************************************************************
873 * We use this thread to feed new audio samples to the sound card because
874 * we are not authorized to use waveOutWrite() directly in the waveout
876 *****************************************************************************/
877 static void* WaveOutThread( vlc_object_t *p_this )
879 notification_thread_t *p_notif = (notification_thread_t*)p_this;
880 aout_instance_t *p_aout = p_notif->p_aout;
881 aout_sys_t *p_sys = p_aout->output.p_sys;
882 aout_buffer_t *p_buffer = NULL;
883 WAVEHDR *p_waveheader = p_sys->waveheader;
884 int i, i_queued_frames;
887 uint32_t i_buffer_length = 64;
888 int canc = vlc_savecancel ();
890 /* We don't want any resampling when using S/PDIF */
891 b_sleek = p_aout->output.output.i_format == VLC_CODEC_SPDIFL;
893 // wait for first call to "play()"
894 while( !p_sys->start_date && vlc_object_alive (p_aout) )
895 WaitForSingleObject( p_sys->event, INFINITE );
896 if( !vlc_object_alive (p_aout) )
899 msg_Dbg( p_aout, "will start to play in %"PRId64" us",
900 (p_sys->start_date - AOUT_PTS_TOLERANCE/4)-mdate());
902 // than wait a short time... before grabbing first frames
903 mwait( p_sys->start_date - AOUT_PTS_TOLERANCE/4 );
905 #define waveout_warn(msg) msg_Warn( p_aout, "aout_OutputNextBuffer no buffer "\
906 "got next_date=%d ms, "\
907 "%d frames to play, "\
908 "starving? %d, %s",(int)(next_date/(mtime_t)1000), \
910 p_aout->output.b_starving, msg);
913 while( vlc_object_alive (p_aout) )
915 /* Cleanup and find out the current latency */
916 i_queued_frames = WaveOutClearDoneBuffers( p_sys );
918 if( !vlc_object_alive (p_aout) ) return NULL;
920 /* Try to fill in as many frame buffers as possible */
921 for( i = 0; i < FRAMES_NUM; i++ )
923 /* Check if frame buf is available */
924 if( p_waveheader[i].dwFlags & WHDR_DONE )
926 // next_date = mdate() + 1000000 * i_queued_frames /
927 // p_aout->output.output.i_rate * p_aout->output.i_nb_samples;
929 // the realtime has got our back-site:) to come in sync
930 if(next_date < mdate())
934 /* Take into account the latency */
935 p_buffer = aout_OutputNextBuffer( p_aout,
942 msg_Dbg( p_aout, "aout_OutputNextBuffer no buffer "\
943 "got next_date=%d ms, "\
944 "%d frames to play, "\
945 "starving? %d",(int)(next_date/(mtime_t)1000),
947 p_aout->output.b_starving);
949 if(p_aout->output.b_starving)
951 // means we are too early to request a new buffer?
952 waveout_warn("waiting...")
953 next_date = aout_FifoFirstDate( p_aout, &p_aout->output.fifo );
954 mwait( next_date - AOUT_PTS_TOLERANCE/4 );
956 p_buffer = aout_OutputNextBuffer( p_aout,
963 if( !p_buffer && i_queued_frames )
965 /* We aren't late so no need to play a blank sample */
971 mtime_t buffer_length = p_buffer->i_length;
972 next_date = next_date + buffer_length;
973 i_buffer_length = buffer_length/1000;
976 /* Do the channel reordering */
977 if( p_buffer && p_sys->b_chan_reorder )
979 aout_ChannelReorder( p_buffer->p_buffer,
981 p_sys->waveformat.Format.nChannels,
982 p_sys->pi_chan_table,
983 p_sys->waveformat.Format.wBitsPerSample );
986 PlayWaveOut( p_aout, p_sys->h_waveout,
987 &p_waveheader[i], p_buffer, b_sleek );
993 if( !vlc_object_alive (p_aout) ) return NULL;
996 deal with the case that the loop didn't fillup the buffer to the
997 max - instead of waiting that half the buffer is played before
998 fillup the waveout buffers, wait only for the next sample buffer
999 to arrive at the play method...
1001 this will also avoid, that the last buffer is play until the
1002 end, and then trying to get more data, so it will also
1003 work - if the next buffer will arrive some ms before the
1004 last buffer is finished.
1006 if(i_queued_frames < FRAMES_NUM)
1007 WaitForSingleObject( p_sys->new_buffer_event, INFINITE );
1009 WaitForSingleObject( p_sys->event, INFINITE );
1014 vlc_restorecancel (canc);
1018 static int VolumeSet( aout_instance_t * p_aout, audio_volume_t i_volume,
1022 i_volume = AOUT_VOLUME_MIN;
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 );
1037 reload the configuration drop down list, of the Audio Devices
1039 static int ReloadWaveoutDevices( vlc_object_t *p_this, char const *psz_name,
1040 vlc_value_t newval, vlc_value_t oldval, void *data )
1042 VLC_UNUSED( newval ); VLC_UNUSED( oldval ); VLC_UNUSED( data );
1044 module_config_t *p_item = config_FindConfig( p_this, psz_name );
1045 if( !p_item ) return VLC_SUCCESS;
1047 /* Clear-up the current list */
1048 if( p_item->i_list )
1052 /* Keep the first entry */
1053 for( i = 1; i < p_item->i_list; i++ )
1055 free((char *)(p_item->ppsz_list[i]) );
1056 free((char *)(p_item->ppsz_list_text[i]) );
1058 /* TODO: Remove when no more needed */
1059 p_item->ppsz_list[i] = NULL;
1060 p_item->ppsz_list_text[i] = NULL;
1064 int wave_devices = waveOutGetNumDevs();
1066 p_item->ppsz_list = xrealloc( p_item->ppsz_list,
1067 (wave_devices+2) * sizeof(char *) );
1068 p_item->ppsz_list_text = xrealloc( p_item->ppsz_list_text,
1069 (wave_devices+2) * sizeof(char *) );
1072 char sz_dev_name[MAXPNAMELEN+32];
1074 for(int i=0; i<wave_devices; i++)
1076 if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
1077 == MMSYSERR_NOERROR)
1079 sprintf( sz_dev_name, psz_device_name_fmt, caps.szPname,
1083 p_item->ppsz_list[j] = FromLocaleDup( sz_dev_name );
1084 p_item->ppsz_list_text[j] = FromLocaleDup( sz_dev_name );
1090 p_item->ppsz_list[j] = NULL;
1091 p_item->ppsz_list_text[j] = NULL;
1093 /* Signal change to the interface */
1094 p_item->b_dirty = true;
1100 convert devicename to device ID for output
1101 if device not found return WAVE_MAPPER, so let
1102 windows decide which preferred audio device
1105 static uint32_t findDeviceID(char *psz_device_name)
1107 if( !psz_device_name )
1110 uint32_t wave_devices = waveOutGetNumDevs();
1112 char sz_dev_name[MAXPNAMELEN+32];
1114 for( uint32_t i = 0; i < wave_devices; i++ )
1116 if( waveOutGetDevCaps( i, &caps, sizeof(WAVEOUTCAPS) )
1117 == MMSYSERR_NOERROR)
1119 sprintf( sz_dev_name, psz_device_name_fmt, caps.szPname,
1123 char *psz_temp = FromLocaleDup(sz_dev_name);
1125 if( !stricmp(psz_temp, psz_device_name) )
1127 LocaleFree( psz_temp );
1130 LocaleFree( psz_temp );