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 *****************************************************************************/
35 #include <vlc_common.h>
36 #include <vlc_plugin.h>
38 #include <vlc_charset.h>
39 #include <vlc_memory.h>
44 #define FRAME_SIZE 4096 /* The size is in samples, not in bytes */
47 /*****************************************************************************
49 *****************************************************************************/
51 # define DWORD_PTR DWORD
52 # ifdef waveOutGetDevCaps
53 # undef waveOutGetDevCaps
54 MMRESULT WINAPI waveOutGetDevCaps(UINT, LPWAVEOUTCAPS, UINT);
58 #ifndef WAVE_FORMAT_IEEE_FLOAT
59 # define WAVE_FORMAT_IEEE_FLOAT 0x0003
62 #ifndef WAVE_FORMAT_DOLBY_AC3_SPDIF
63 # define WAVE_FORMAT_DOLBY_AC3_SPDIF 0x0092
66 #ifndef WAVE_FORMAT_EXTENSIBLE
67 #define WAVE_FORMAT_EXTENSIBLE 0xFFFE
70 #ifndef SPEAKER_FRONT_LEFT
71 # define SPEAKER_FRONT_LEFT 0x1
72 # define SPEAKER_FRONT_RIGHT 0x2
73 # define SPEAKER_FRONT_CENTER 0x4
74 # define SPEAKER_LOW_FREQUENCY 0x8
75 # define SPEAKER_BACK_LEFT 0x10
76 # define SPEAKER_BACK_RIGHT 0x20
77 # define SPEAKER_FRONT_LEFT_OF_CENTER 0x40
78 # define SPEAKER_FRONT_RIGHT_OF_CENTER 0x80
79 # define SPEAKER_BACK_CENTER 0x100
80 # define SPEAKER_SIDE_LEFT 0x200
81 # define SPEAKER_SIDE_RIGHT 0x400
82 # define SPEAKER_TOP_CENTER 0x800
83 # define SPEAKER_TOP_FRONT_LEFT 0x1000
84 # define SPEAKER_TOP_FRONT_CENTER 0x2000
85 # define SPEAKER_TOP_FRONT_RIGHT 0x4000
86 # define SPEAKER_TOP_BACK_LEFT 0x8000
87 # define SPEAKER_TOP_BACK_CENTER 0x10000
88 # define SPEAKER_TOP_BACK_RIGHT 0x20000
89 # define SPEAKER_RESERVED 0x80000000
92 #ifndef _WAVEFORMATEXTENSIBLE_
96 WORD wValidBitsPerSample; /* bits of precision */
97 WORD wSamplesPerBlock; /* valid if wBitsPerSample==0 */
98 WORD wReserved; /* If neither applies, set to zero. */
100 DWORD dwChannelMask; /* which channels are */
101 /* present in stream */
103 } WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE;
106 static const GUID __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = {WAVE_FORMAT_IEEE_FLOAT, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
107 static const GUID __KSDATAFORMAT_SUBTYPE_PCM = {WAVE_FORMAT_PCM, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
108 static const GUID __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF = {WAVE_FORMAT_DOLBY_AC3_SPDIF, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
110 /*****************************************************************************
112 *****************************************************************************/
113 static int Open ( vlc_object_t * );
114 static void Close ( vlc_object_t * );
115 static void Play ( aout_instance_t * );
117 /*****************************************************************************
118 * notification_thread_t: waveOut event thread
119 *****************************************************************************/
120 typedef struct notification_thread_t
123 aout_instance_t *p_aout;
125 } notification_thread_t;
127 /* local functions */
128 static void Probe ( aout_instance_t * );
129 static int OpenWaveOut ( aout_instance_t *, uint32_t,
130 int, int, int, int, bool );
131 static int OpenWaveOutPCM( aout_instance_t *, uint32_t,
132 vlc_fourcc_t*, int, int, int, bool );
133 static int PlayWaveOut ( aout_instance_t *, HWAVEOUT, WAVEHDR *,
134 aout_buffer_t *, bool );
136 static void CALLBACK WaveOutCallback ( HWAVEOUT, UINT, DWORD, DWORD, DWORD );
137 static void* WaveOutThread( vlc_object_t * );
139 static int VolumeGet( aout_instance_t *, audio_volume_t * );
140 static int VolumeSet( aout_instance_t *, audio_volume_t );
142 static int WaveOutClearDoneBuffers(aout_sys_t *p_sys);
144 static int ReloadWaveoutDevices( vlc_object_t *, char const *,
145 vlc_value_t, vlc_value_t, void * );
146 static uint32_t findDeviceID(char *);
148 static const char psz_device_name_fmt[] = "%s ($%x,$%x)";
150 static const char *const ppsz_adev[] = { "wavemapper", };
151 static const char *const ppsz_adev_text[] = { N_("Microsoft Soundmapper") };
155 /*****************************************************************************
157 *****************************************************************************/
158 #define FLOAT_TEXT N_("Use float32 output")
159 #define FLOAT_LONGTEXT N_( \
160 "The option allows you to enable or disable the high-quality float32 " \
161 "audio output mode (which is not well supported by some soundcards)." )
162 #define DEVICE_TEXT N_("Select Audio Device")
163 #define DEVICE_LONG N_("Select special Audio device, or let windows "\
164 "decide (default), change needs VLC restart "\
166 #define DEFAULT_AUDIO_DEVICE N_("Default Audio Device")
169 set_shortname( "WaveOut" )
170 set_description( N_("Win32 waveOut extension output") )
171 set_capability( "audio output", 50 )
172 set_category( CAT_AUDIO )
173 set_subcategory( SUBCAT_AUDIO_AOUT )
174 add_bool( "waveout-float32", true, NULL, FLOAT_TEXT, FLOAT_LONGTEXT, true )
176 add_string( "waveout-audio-device", "wavemapper", NULL,
177 DEVICE_TEXT, DEVICE_LONG, false )
178 add_deprecated_alias( "waveout-dev" ) /* deprecated since 0.9.3 */
179 change_string_list( ppsz_adev, ppsz_adev_text, ReloadWaveoutDevices )
180 change_need_restart ()
181 change_action_add( ReloadWaveoutDevices, N_("Refresh list") )
184 set_callbacks( Open, Close )
187 /*****************************************************************************
188 * aout_sys_t: waveOut audio output method descriptor
189 *****************************************************************************
190 * This structure is part of the audio output thread descriptor.
191 * It describes the waveOut specific properties of an audio device.
192 *****************************************************************************/
195 uint32_t i_wave_device_id; /* ID of selected output device */
197 HWAVEOUT h_waveout; /* handle to waveout instance */
199 WAVEFORMATEXTENSIBLE waveformat; /* audio format */
201 WAVEHDR waveheader[FRAMES_NUM];
203 notification_thread_t *p_notif; /* WaveOutThread id */
205 HANDLE new_buffer_event;
207 // rental from alsa.c to synchronize startup of audiothread
208 int b_playing; /* playing status */
211 int i_repeat_counter;
215 uint8_t *p_silence_buffer; /* buffer we use to play silence */
217 bool b_chan_reorder; /* do we need channel reordering */
218 int pi_chan_table[AOUT_CHAN_MAX];
221 static const uint32_t pi_channels_src[] =
222 { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT,
223 AOUT_CHAN_MIDDLELEFT, AOUT_CHAN_MIDDLERIGHT,
224 AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT, AOUT_CHAN_REARCENTER,
225 AOUT_CHAN_CENTER, AOUT_CHAN_LFE, 0 };
226 static const uint32_t pi_channels_in[] =
227 { SPEAKER_FRONT_LEFT, SPEAKER_FRONT_RIGHT,
228 SPEAKER_SIDE_LEFT, SPEAKER_SIDE_RIGHT,
229 SPEAKER_BACK_LEFT, SPEAKER_BACK_RIGHT, SPEAKER_BACK_CENTER,
230 SPEAKER_FRONT_CENTER, SPEAKER_LOW_FREQUENCY, 0 };
231 static const uint32_t pi_channels_out[] =
232 { SPEAKER_FRONT_LEFT, SPEAKER_FRONT_RIGHT,
233 SPEAKER_FRONT_CENTER, SPEAKER_LOW_FREQUENCY,
234 SPEAKER_BACK_LEFT, SPEAKER_BACK_RIGHT,
236 SPEAKER_SIDE_LEFT, SPEAKER_SIDE_RIGHT, 0 };
238 /*****************************************************************************
239 * Open: open the audio device
240 *****************************************************************************
241 * This function opens and setups Win32 waveOut
242 *****************************************************************************/
243 static int Open( vlc_object_t *p_this )
245 aout_instance_t *p_aout = (aout_instance_t *)p_this;
249 /* Allocate structure */
250 p_aout->output.p_sys = malloc( sizeof( aout_sys_t ) );
252 if( p_aout->output.p_sys == NULL )
255 p_aout->output.pf_play = Play;
256 p_aout->b_die = false;
260 initialize/update Device selection List
262 ReloadWaveoutDevices( p_this, "waveout-audio-device", val, val, NULL);
266 check for configured audio device!
268 char *psz_waveout_dev = var_CreateGetString( p_aout, "waveout-audio-device");
270 p_aout->output.p_sys->i_wave_device_id =
271 findDeviceID( psz_waveout_dev );
273 if(p_aout->output.p_sys->i_wave_device_id == WAVE_MAPPER)
275 if(psz_waveout_dev &&
276 stricmp(psz_waveout_dev,"wavemapper"))
278 msg_Warn( p_aout, "configured audio device '%s' not available, "\
279 "use default instead", psz_waveout_dev );
282 free( psz_waveout_dev );
285 WAVEOUTCAPS waveoutcaps;
286 if(waveOutGetDevCaps( p_aout->output.p_sys->i_wave_device_id,
288 sizeof(WAVEOUTCAPS)) == MMSYSERR_NOERROR)
290 /* log debug some infos about driver, to know who to blame
291 if it doesn't work */
292 msg_Dbg( p_aout, "Drivername: %s", waveoutcaps.szPname);
293 msg_Dbg( p_aout, "Driver Version: %d.%d",
294 (waveoutcaps.vDriverVersion>>8)&255,
295 waveoutcaps.vDriverVersion & 255);
296 msg_Dbg( p_aout, "Manufacturer identifier: 0x%x", waveoutcaps.wMid );
297 msg_Dbg( p_aout, "Product identifier: 0x%x", waveoutcaps.wPid );
302 if( var_Type( p_aout, "audio-device" ) == 0 )
307 if( var_Get( p_aout, "audio-device", &val ) < 0 )
309 /* Probe() has failed. */
310 var_Destroy( p_aout, "waveout-audio-device");
311 free( p_aout->output.p_sys );
316 /* Open the device */
317 if( val.i_int == AOUT_VAR_SPDIF )
319 p_aout->output.output.i_format = VLC_CODEC_SPDIFL;
321 if( OpenWaveOut( p_aout,
322 p_aout->output.p_sys->i_wave_device_id,
324 p_aout->output.output.i_physical_channels,
325 aout_FormatNbChannels( &p_aout->output.output ),
326 p_aout->output.output.i_rate, false )
329 msg_Err( p_aout, "cannot open waveout audio device" );
330 free( p_aout->output.p_sys );
334 /* Calculate the frame size in bytes */
335 p_aout->output.i_nb_samples = A52_FRAME_NB;
336 p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
337 p_aout->output.output.i_frame_length = A52_FRAME_NB;
338 p_aout->output.p_sys->i_buffer_size =
339 p_aout->output.output.i_bytes_per_frame;
341 aout_VolumeNoneInit( p_aout );
350 p_aout->output.output.i_physical_channels
351 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
352 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
356 p_aout->output.output.i_physical_channels
357 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
358 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
361 p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
364 p_aout->output.output.i_physical_channels
365 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
368 if( OpenWaveOutPCM( p_aout,
369 p_aout->output.p_sys->i_wave_device_id,
370 &p_aout->output.output.i_format,
371 p_aout->output.output.i_physical_channels,
372 aout_FormatNbChannels( &p_aout->output.output ),
373 p_aout->output.output.i_rate, false )
376 msg_Err( p_aout, "cannot open waveout audio device" );
377 free( p_aout->output.p_sys );
381 /* Calculate the frame size in bytes */
382 p_aout->output.i_nb_samples = FRAME_SIZE;
383 aout_FormatPrepare( &p_aout->output.output );
384 p_aout->output.p_sys->i_buffer_size = FRAME_SIZE *
385 p_aout->output.output.i_bytes_per_frame;
387 aout_VolumeSoftInit( p_aout );
389 /* Check for hardware volume support */
390 if( waveOutGetDevCaps( (UINT_PTR)p_aout->output.p_sys->h_waveout,
391 &wocaps, sizeof(wocaps) ) == MMSYSERR_NOERROR &&
392 wocaps.dwSupport & WAVECAPS_VOLUME )
395 if( waveOutGetVolume( p_aout->output.p_sys->h_waveout, &i_dummy )
396 == MMSYSERR_NOERROR )
398 p_aout->output.pf_volume_get = VolumeGet;
399 p_aout->output.pf_volume_set = VolumeSet;
405 waveOutReset( p_aout->output.p_sys->h_waveout );
407 /* Allocate silence buffer */
408 p_aout->output.p_sys->p_silence_buffer =
409 malloc( p_aout->output.p_sys->i_buffer_size );
410 if( p_aout->output.p_sys->p_silence_buffer == NULL )
412 free( p_aout->output.p_sys );
415 p_aout->output.p_sys->i_repeat_counter = 0;
418 /* Zero the buffer. WinCE doesn't have calloc(). */
419 memset( p_aout->output.p_sys->p_silence_buffer, 0,
420 p_aout->output.p_sys->i_buffer_size );
422 /* Now we need to setup our waveOut play notification structure */
423 p_aout->output.p_sys->p_notif =
424 vlc_object_create( p_aout, sizeof(notification_thread_t) );
425 p_aout->output.p_sys->p_notif->p_aout = p_aout;
426 p_aout->output.p_sys->event = CreateEvent( NULL, FALSE, FALSE, NULL );
427 p_aout->output.p_sys->new_buffer_event = CreateEvent( NULL, FALSE, FALSE, NULL );
429 /* define startpoint of playback on first call to play()
430 like alsa does (instead of playing a blank sample) */
431 p_aout->output.p_sys->b_playing = 0;
432 p_aout->output.p_sys->start_date = 0;
435 /* Then launch the notification thread */
436 if( vlc_thread_create( p_aout->output.p_sys->p_notif,
437 "waveOut Notification Thread", WaveOutThread,
438 VLC_THREAD_PRIORITY_OUTPUT ) )
440 msg_Err( p_aout, "cannot create WaveOutThread" );
443 /* We need to kick off the playback in order to have the callback properly
445 for( i = 0; i < FRAMES_NUM; i++ )
447 p_aout->output.p_sys->waveheader[i].dwFlags = WHDR_DONE;
448 p_aout->output.p_sys->waveheader[i].dwUser = 0;
454 /*****************************************************************************
455 * Probe: probe the audio device for available formats and channels
456 *****************************************************************************/
457 static void Probe( aout_instance_t * p_aout )
459 vlc_value_t val, text;
460 vlc_fourcc_t i_format;
461 unsigned int i_physical_channels;
463 var_Create( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
464 text.psz_string = _("Audio Device");
465 var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
467 /* Test for 5.1 support */
468 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
469 AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
470 AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE;
471 if( p_aout->output.output.i_physical_channels == i_physical_channels )
473 if( OpenWaveOutPCM( p_aout,
474 p_aout->output.p_sys->i_wave_device_id,
476 i_physical_channels, 6,
477 p_aout->output.output.i_rate, true )
480 val.i_int = AOUT_VAR_5_1;
481 text.psz_string = (char *)_("5.1");
482 var_Change( p_aout, "audio-device",
483 VLC_VAR_ADDCHOICE, &val, &text );
484 msg_Dbg( p_aout, "device supports 5.1 channels" );
488 /* Test for 2 Front 2 Rear support */
489 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
490 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
491 if( ( p_aout->output.output.i_physical_channels & i_physical_channels )
492 == i_physical_channels )
494 if( OpenWaveOutPCM( p_aout,
495 p_aout->output.p_sys->i_wave_device_id,
497 i_physical_channels, 4,
498 p_aout->output.output.i_rate, true )
501 val.i_int = AOUT_VAR_2F2R;
502 text.psz_string = (char *)_("2 Front 2 Rear");
503 var_Change( p_aout, "audio-device",
504 VLC_VAR_ADDCHOICE, &val, &text );
505 msg_Dbg( p_aout, "device supports 4 channels" );
509 /* Test for stereo support */
510 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
511 if( OpenWaveOutPCM( p_aout,
512 p_aout->output.p_sys->i_wave_device_id,
514 i_physical_channels, 2,
515 p_aout->output.output.i_rate, true )
518 val.i_int = AOUT_VAR_STEREO;
519 text.psz_string = (char *)_("Stereo");
520 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
521 msg_Dbg( p_aout, "device supports 2 channels" );
524 /* Test for mono support */
525 i_physical_channels = AOUT_CHAN_CENTER;
526 if( OpenWaveOutPCM( p_aout,
527 p_aout->output.p_sys->i_wave_device_id,
529 i_physical_channels, 1,
530 p_aout->output.output.i_rate, true )
533 val.i_int = AOUT_VAR_MONO;
534 text.psz_string = (char *)_("Mono");
535 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
536 msg_Dbg( p_aout, "device supports 1 channel" );
539 /* Test for SPDIF support */
540 if ( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
542 if( OpenWaveOut( p_aout,
543 p_aout->output.p_sys->i_wave_device_id,
545 p_aout->output.output.i_physical_channels,
546 aout_FormatNbChannels( &p_aout->output.output ),
547 p_aout->output.output.i_rate, true )
550 msg_Dbg( p_aout, "device supports A/52 over S/PDIF" );
551 val.i_int = AOUT_VAR_SPDIF;
552 text.psz_string = (char *)_("A/52 over S/PDIF");
553 var_Change( p_aout, "audio-device",
554 VLC_VAR_ADDCHOICE, &val, &text );
555 if( config_GetInt( p_aout, "spdif" ) )
556 var_Set( p_aout, "audio-device", val );
560 var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
563 /* Probe() has failed. */
564 var_Destroy( p_aout, "audio-device" );
568 var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
569 var_SetBool( p_aout, "intf-change", true );
572 /*****************************************************************************
573 * Play: play a sound buffer
574 *****************************************************************************
575 * This doesn't actually play the buffer. This just stores the buffer so it
576 * can be played by the callback thread.
577 *****************************************************************************/
578 static void Play( aout_instance_t *_p_aout )
580 if( !_p_aout->output.p_sys->b_playing )
582 _p_aout->output.p_sys->b_playing = 1;
584 /* get the playing date of the first aout buffer */
585 _p_aout->output.p_sys->start_date =
586 aout_FifoFirstDate( _p_aout, &_p_aout->output.fifo );
588 msg_Dbg( _p_aout, "Wakeup sleeping output thread.");
590 /* wake up the audio output thread */
591 SetEvent( _p_aout->output.p_sys->event );
593 SetEvent( _p_aout->output.p_sys->new_buffer_event );
597 /*****************************************************************************
598 * Close: close the audio device
599 *****************************************************************************/
600 static void Close( vlc_object_t *p_this )
602 aout_instance_t *p_aout = (aout_instance_t *)p_this;
603 aout_sys_t *p_sys = p_aout->output.p_sys;
605 /* Before calling waveOutClose we must reset the device */
606 vlc_object_kill( p_aout );
608 /* wake up the audio thread, to recognize that p_aout died */
609 SetEvent( p_sys->event );
610 SetEvent( p_sys->new_buffer_event );
612 vlc_thread_join( p_sys->p_notif );
613 vlc_object_release( p_sys->p_notif );
616 kill the real output then - when the feed thread
617 is surely terminated!
618 old code could be too early in case that "feeding"
619 was running on termination
621 at this point now its sure, that there will be no new
622 data send to the driver, and we can cancel the last
625 MMRESULT result = waveOutReset( p_sys->h_waveout );
626 if(result != MMSYSERR_NOERROR)
628 msg_Err( p_aout, "waveOutReset failed 0x%x", result );
630 now we must wait, that all buffers are played
631 because cancel doesn't work in this case...
633 if(result == MMSYSERR_NOTSUPPORTED)
636 clear currently played (done) buffers,
637 if returnvalue > 0 (means some buffer still playing)
638 wait for the driver event callback that one buffer
639 is finished with playing, and check again
640 the timeout of 5000ms is just, an emergency exit
641 of this loop, to avoid deadlock in case of other
642 (currently not known bugs, problems, errors cases?)
645 (WaveOutClearDoneBuffers( p_sys ) > 0)
647 (WaitForSingleObject( p_sys->event, 5000) == WAIT_OBJECT_0)
650 msg_Dbg( p_aout, "Wait for waveout device...");
654 WaveOutClearDoneBuffers( p_sys );
657 /* now we can Close the device */
658 if( waveOutClose( p_sys->h_waveout ) != MMSYSERR_NOERROR )
660 msg_Err( p_aout, "waveOutClose failed" );
664 because so long, the waveout device is playing, the callback
665 could occur and need the events
667 CloseHandle( p_sys->event );
668 CloseHandle( p_sys->new_buffer_event);
670 free( p_sys->p_silence_buffer );
674 /*****************************************************************************
675 * OpenWaveOut: open the waveout sound device
676 ****************************************************************************/
677 static int OpenWaveOut( aout_instance_t *p_aout, uint32_t i_device_id, int i_format,
678 int i_channels, int i_nb_channels, int i_rate,
684 /* Set sound format */
686 #define waveformat p_aout->output.p_sys->waveformat
688 waveformat.dwChannelMask = 0;
689 for( i = 0; i < sizeof(pi_channels_src)/sizeof(uint32_t); i++ )
691 if( i_channels & pi_channels_src[i] )
692 waveformat.dwChannelMask |= pi_channels_in[i];
697 case VLC_CODEC_SPDIFL:
699 /* To prevent channel re-ordering */
700 waveformat.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
701 waveformat.Format.wBitsPerSample = 16;
702 waveformat.Samples.wValidBitsPerSample =
703 waveformat.Format.wBitsPerSample;
704 waveformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
705 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF;
709 waveformat.Format.wBitsPerSample = sizeof(float) * 8;
710 waveformat.Samples.wValidBitsPerSample =
711 waveformat.Format.wBitsPerSample;
712 waveformat.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
713 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
717 waveformat.Format.wBitsPerSample = 16;
718 waveformat.Samples.wValidBitsPerSample =
719 waveformat.Format.wBitsPerSample;
720 waveformat.Format.wFormatTag = WAVE_FORMAT_PCM;
721 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_PCM;
725 waveformat.Format.nChannels = i_nb_channels;
726 waveformat.Format.nSamplesPerSec = i_rate;
727 waveformat.Format.nBlockAlign =
728 waveformat.Format.wBitsPerSample / 8 * i_nb_channels;
729 waveformat.Format.nAvgBytesPerSec =
730 waveformat.Format.nSamplesPerSec * waveformat.Format.nBlockAlign;
732 /* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */
733 if( i_nb_channels <= 2 )
735 waveformat.Format.cbSize = 0;
739 waveformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
740 waveformat.Format.cbSize =
741 sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
745 msg_Dbg( p_aout, "OpenWaveDevice-ID: %u", i_device_id);
746 msg_Dbg( p_aout,"waveformat.Format.cbSize = %d",
747 waveformat.Format.cbSize);
748 msg_Dbg( p_aout,"waveformat.Format.wFormatTag = %u",
749 waveformat.Format.wFormatTag);
750 msg_Dbg( p_aout,"waveformat.Format.nChannels = %u",
751 waveformat.Format.nChannels);
752 msg_Dbg( p_aout,"waveformat.Format.nSamplesPerSec = %d",
753 (int)waveformat.Format.nSamplesPerSec);
754 msg_Dbg( p_aout,"waveformat.Format.nAvgBytesPerSec = %u",
755 (int)waveformat.Format.nAvgBytesPerSec);
756 msg_Dbg( p_aout,"waveformat.Format.nBlockAlign = %d",
757 waveformat.Format.nBlockAlign);
758 msg_Dbg( p_aout,"waveformat.Format.wBitsPerSample = %d",
759 waveformat.Format.wBitsPerSample);
760 msg_Dbg( p_aout,"waveformat.Samples.wValidBitsPerSample = %d",
761 waveformat.Samples.wValidBitsPerSample);
762 msg_Dbg( p_aout,"waveformat.Samples.wSamplesPerBlock = %d",
763 waveformat.Samples.wSamplesPerBlock);
764 msg_Dbg( p_aout,"waveformat.dwChannelMask = %lu",
765 waveformat.dwChannelMask);
768 /* Open the device */
769 result = waveOutOpen( &p_aout->output.p_sys->h_waveout, i_device_id,
770 (WAVEFORMATEX *)&waveformat,
771 (DWORD_PTR)WaveOutCallback, (DWORD_PTR)p_aout,
772 CALLBACK_FUNCTION | (b_probe?WAVE_FORMAT_QUERY:0) );
773 if( result == WAVERR_BADFORMAT )
775 msg_Warn( p_aout, "waveOutOpen failed WAVERR_BADFORMAT" );
778 if( result == MMSYSERR_ALLOCATED )
780 msg_Warn( p_aout, "waveOutOpen failed WAVERR_ALLOCATED" );
783 if( result != MMSYSERR_NOERROR )
785 msg_Warn( p_aout, "waveOutOpen failed" );
789 p_aout->output.p_sys->b_chan_reorder =
790 aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
791 waveformat.dwChannelMask, i_nb_channels,
792 p_aout->output.p_sys->pi_chan_table );
794 if( p_aout->output.p_sys->b_chan_reorder )
796 msg_Dbg( p_aout, "channel reordering needed" );
805 /*****************************************************************************
806 * OpenWaveOutPCM: open a PCM waveout sound device
807 ****************************************************************************/
808 static int OpenWaveOutPCM( aout_instance_t *p_aout, uint32_t i_device_id,
809 vlc_fourcc_t *i_format,
810 int i_channels, int i_nb_channels, int i_rate,
813 bool b_use_float32 = var_CreateGetBool( p_aout, "waveout-float32");
815 if( !b_use_float32 || OpenWaveOut( p_aout, i_device_id, VLC_CODEC_FL32,
816 i_channels, i_nb_channels, i_rate, b_probe )
819 if ( OpenWaveOut( p_aout, i_device_id, VLC_CODEC_S16L,
820 i_channels, i_nb_channels, i_rate, b_probe )
827 *i_format = VLC_CODEC_S16L;
833 *i_format = VLC_CODEC_FL32;
838 /*****************************************************************************
839 * PlayWaveOut: play a buffer through the WaveOut device
840 *****************************************************************************/
841 static int PlayWaveOut( aout_instance_t *p_aout, HWAVEOUT h_waveout,
842 WAVEHDR *p_waveheader, aout_buffer_t *p_buffer,
847 /* Prepare the buffer */
848 if( p_buffer != NULL )
850 p_waveheader->lpData = p_buffer->p_buffer;
852 copy the buffer to the silence buffer :) so in case we don't
853 get the next buffer fast enough (I will repeat this one a time
854 for AC3 / DTS and SPDIF this will sound better instead of
859 vlc_memcpy( p_aout->output.p_sys->p_silence_buffer,
861 p_aout->output.p_sys->i_buffer_size );
862 p_aout->output.p_sys->i_repeat_counter = 2;
865 /* Use silence buffer instead */
866 if(p_aout->output.p_sys->i_repeat_counter)
868 p_aout->output.p_sys->i_repeat_counter--;
869 if(!p_aout->output.p_sys->i_repeat_counter)
871 vlc_memset( p_aout->output.p_sys->p_silence_buffer,
872 0x00, p_aout->output.p_sys->i_buffer_size );
875 p_waveheader->lpData = p_aout->output.p_sys->p_silence_buffer;
878 p_waveheader->dwUser = p_buffer ? (DWORD_PTR)p_buffer : (DWORD_PTR)1;
879 p_waveheader->dwBufferLength = p_aout->output.p_sys->i_buffer_size;
880 p_waveheader->dwFlags = 0;
882 result = waveOutPrepareHeader( h_waveout, p_waveheader, sizeof(WAVEHDR) );
883 if( result != MMSYSERR_NOERROR )
885 msg_Err( p_aout, "waveOutPrepareHeader failed" );
889 /* Send the buffer to the waveOut queue */
890 result = waveOutWrite( h_waveout, p_waveheader, sizeof(WAVEHDR) );
891 if( result != MMSYSERR_NOERROR )
893 msg_Err( p_aout, "waveOutWrite failed" );
900 /*****************************************************************************
901 * WaveOutCallback: what to do once WaveOut has played its sound samples
902 *****************************************************************************/
903 static void CALLBACK WaveOutCallback( HWAVEOUT h_waveout, UINT uMsg,
905 DWORD dwParam1, DWORD dwParam2 )
907 (void)h_waveout; (void)dwParam1; (void)dwParam2;
908 aout_instance_t *p_aout = (aout_instance_t *)_p_aout;
909 int i, i_queued_frames = 0;
911 if( uMsg != WOM_DONE ) return;
913 if( !vlc_object_alive (p_aout) ) return;
915 /* Find out the current latency */
916 for( i = 0; i < FRAMES_NUM; i++ )
918 /* Check if frame buf is available */
919 if( !(p_aout->output.p_sys->waveheader[i].dwFlags & WHDR_DONE) )
925 /* Don't wake up the thread too much */
926 if( i_queued_frames <= FRAMES_NUM/2 )
927 SetEvent( p_aout->output.p_sys->event );
931 /****************************************************************************
932 * WaveOutClearDoneBuffers: Clear all done marked buffers, and free aout_bufer
933 ****************************************************************************
934 * return value is the number of still playing buffers in the queue
935 ****************************************************************************/
936 static int WaveOutClearDoneBuffers(aout_sys_t *p_sys)
938 WAVEHDR *p_waveheader = p_sys->waveheader;
939 int i_queued_frames = 0;
941 for( int i = 0; i < FRAMES_NUM; i++ )
943 if( (p_waveheader[i].dwFlags & WHDR_DONE) &&
944 p_waveheader[i].dwUser )
946 aout_buffer_t *p_buffer =
947 (aout_buffer_t *)(p_waveheader[i].dwUser);
948 /* Unprepare and free the buffers which has just been played */
949 waveOutUnprepareHeader( p_sys->h_waveout, &p_waveheader[i],
952 if( p_waveheader[i].dwUser != 1 )
953 aout_BufferFree( p_buffer );
955 p_waveheader[i].dwUser = 0;
958 /* Check if frame buf is available */
959 if( !(p_waveheader[i].dwFlags & WHDR_DONE) )
964 return i_queued_frames;
967 /*****************************************************************************
968 * WaveOutThread: this thread will capture play notification events.
969 *****************************************************************************
970 * We use this thread to feed new audio samples to the sound card because
971 * we are not authorized to use waveOutWrite() directly in the waveout
973 *****************************************************************************/
974 static void* WaveOutThread( vlc_object_t *p_this )
976 notification_thread_t *p_notif = (notification_thread_t*)p_this;
977 aout_instance_t *p_aout = p_notif->p_aout;
978 aout_sys_t *p_sys = p_aout->output.p_sys;
979 aout_buffer_t *p_buffer = NULL;
980 WAVEHDR *p_waveheader = p_sys->waveheader;
981 int i, i_queued_frames;
984 uint32_t i_buffer_length = 64;
985 int canc = vlc_savecancel ();
987 /* We don't want any resampling when using S/PDIF */
988 b_sleek = p_aout->output.output.i_format == VLC_CODEC_SPDIFL;
990 // wait for first call to "play()"
991 while( !p_sys->start_date && vlc_object_alive (p_aout) )
992 WaitForSingleObject( p_sys->event, INFINITE );
993 if( !vlc_object_alive (p_aout) )
996 msg_Dbg( p_aout, "will start to play in %"PRId64" us",
997 (p_sys->start_date - AOUT_PTS_TOLERANCE/4)-mdate());
999 // than wait a short time... before grabbing first frames
1000 mwait( p_sys->start_date - AOUT_PTS_TOLERANCE/4 );
1002 #define waveout_warn(msg) msg_Warn( p_aout, "aout_OutputNextBuffer no buffer "\
1003 "got next_date=%d ms, "\
1004 "%d frames to play, "\
1005 "starving? %d, %s",(int)(next_date/(mtime_t)1000), \
1007 p_aout->output.b_starving, msg);
1008 next_date = mdate();
1010 while( vlc_object_alive (p_aout) )
1012 /* Cleanup and find out the current latency */
1013 i_queued_frames = WaveOutClearDoneBuffers( p_sys );
1015 if( !vlc_object_alive (p_aout) ) return NULL;
1017 /* Try to fill in as many frame buffers as possible */
1018 for( i = 0; i < FRAMES_NUM; i++ )
1020 /* Check if frame buf is available */
1021 if( p_waveheader[i].dwFlags & WHDR_DONE )
1023 // next_date = mdate() + 1000000 * i_queued_frames /
1024 // p_aout->output.output.i_rate * p_aout->output.i_nb_samples;
1026 // the realtime has got our back-site:) to come in sync
1027 if(next_date < mdate())
1028 next_date = mdate();
1031 /* Take into account the latency */
1032 p_buffer = aout_OutputNextBuffer( p_aout,
1039 msg_Dbg( p_aout, "aout_OutputNextBuffer no buffer "\
1040 "got next_date=%d ms, "\
1041 "%d frames to play, "\
1042 "starving? %d",(int)(next_date/(mtime_t)1000),
1044 p_aout->output.b_starving);
1046 if(p_aout->output.b_starving)
1048 // means we are too early to request a new buffer?
1049 waveout_warn("waiting...")
1050 next_date = aout_FifoFirstDate( p_aout, &p_aout->output.fifo );
1051 mwait( next_date - AOUT_PTS_TOLERANCE/4 );
1052 next_date = mdate();
1053 p_buffer = aout_OutputNextBuffer( p_aout,
1060 if( !p_buffer && i_queued_frames )
1062 /* We aren't late so no need to play a blank sample */
1068 mtime_t buffer_length = p_buffer->i_length;
1069 next_date = next_date + buffer_length;
1070 i_buffer_length = buffer_length/1000;
1073 /* Do the channel reordering */
1074 if( p_buffer && p_sys->b_chan_reorder )
1076 aout_ChannelReorder( p_buffer->p_buffer,
1078 p_sys->waveformat.Format.nChannels,
1079 p_sys->pi_chan_table,
1080 p_sys->waveformat.Format.wBitsPerSample );
1083 PlayWaveOut( p_aout, p_sys->h_waveout,
1084 &p_waveheader[i], p_buffer, b_sleek );
1090 if( !vlc_object_alive (p_aout) ) return NULL;
1093 deal with the case that the loop didn't fillup the buffer to the
1094 max - instead of waiting that half the buffer is played before
1095 fillup the waveout buffers, wait only for the next sample buffer
1096 to arrive at the play method...
1098 this will also avoid, that the last buffer is play until the
1099 end, and then trying to get more data, so it will also
1100 work - if the next buffer will arrive some ms before the
1101 last buffer is finished.
1103 if(i_queued_frames < FRAMES_NUM)
1104 WaitForSingleObject( p_sys->new_buffer_event, INFINITE );
1106 WaitForSingleObject( p_sys->event, INFINITE );
1111 vlc_restorecancel (canc);
1115 static int VolumeGet( aout_instance_t * p_aout, audio_volume_t * pi_volume )
1117 DWORD i_waveout_vol;
1120 waveOutGetVolume( 0, &i_waveout_vol );
1122 waveOutGetVolume( p_aout->output.p_sys->h_waveout, &i_waveout_vol );
1125 i_waveout_vol &= 0xFFFF;
1126 *pi_volume = p_aout->output.i_volume =
1127 (i_waveout_vol * AOUT_VOLUME_MAX + 0xFFFF /*rounding*/) / 2 / 0xFFFF;
1131 static int VolumeSet( aout_instance_t * p_aout, audio_volume_t i_volume )
1133 unsigned long i_waveout_vol = i_volume * 0xFFFF * 2 / AOUT_VOLUME_MAX;
1134 i_waveout_vol |= (i_waveout_vol << 16);
1137 waveOutSetVolume( 0, i_waveout_vol );
1139 waveOutSetVolume( p_aout->output.p_sys->h_waveout, i_waveout_vol );
1142 p_aout->output.i_volume = i_volume;
1148 reload the configuration drop down list, of the Audio Devices
1150 static int ReloadWaveoutDevices( vlc_object_t *p_this, char const *psz_name,
1151 vlc_value_t newval, vlc_value_t oldval, void *data )
1153 VLC_UNUSED( newval ); VLC_UNUSED( oldval ); VLC_UNUSED( data );
1155 module_config_t *p_item = config_FindConfig( p_this, psz_name );
1156 if( !p_item ) return VLC_SUCCESS;
1158 /* Clear-up the current list */
1159 if( p_item->i_list )
1163 /* Keep the first entry */
1164 for( i = 1; i < p_item->i_list; i++ )
1166 free((char *)(p_item->ppsz_list[i]) );
1167 free((char *)(p_item->ppsz_list_text[i]) );
1169 /* TODO: Remove when no more needed */
1170 p_item->ppsz_list[i] = NULL;
1171 p_item->ppsz_list_text[i] = NULL;
1175 int wave_devices = waveOutGetNumDevs();
1177 p_item->ppsz_list = realloc_or_free( p_item->ppsz_list,
1178 (wave_devices+2) * sizeof(char *) );
1179 assert( p_item->ppsz_list );
1180 p_item->ppsz_list_text = realloc_or_free( p_item->ppsz_list_text,
1181 (wave_devices+2) * sizeof(char *) );
1182 assert( p_item->ppsz_list_text );
1185 char sz_dev_name[MAXPNAMELEN+32];
1187 for(int i=0; i<wave_devices; i++)
1189 if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
1190 == MMSYSERR_NOERROR)
1192 sprintf( sz_dev_name, psz_device_name_fmt, caps.szPname,
1196 p_item->ppsz_list[j] = FromLocaleDup( sz_dev_name );
1197 p_item->ppsz_list_text[j] = FromLocaleDup( sz_dev_name );
1203 p_item->ppsz_list[j] = NULL;
1204 p_item->ppsz_list_text[j] = NULL;
1206 /* Signal change to the interface */
1207 p_item->b_dirty = true;
1213 convert devicename to device ID for output
1214 if device not found return WAVE_MAPPER, so let
1215 windows decide which preferred audio device
1218 static uint32_t findDeviceID(char *psz_device_name)
1220 if(!psz_device_name)
1223 uint32_t wave_devices = waveOutGetNumDevs();
1225 char sz_dev_name[MAXPNAMELEN+32];
1226 for(uint32_t i=0; i<wave_devices; i++)
1228 if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
1229 == MMSYSERR_NOERROR)
1231 sprintf(sz_dev_name, psz_device_name_fmt, caps.szPname,
1235 char *psz_temp = FromLocaleDup(sz_dev_name);
1237 if( !stricmp(psz_temp, psz_device_name) )
1239 LocaleFree( psz_temp );
1242 LocaleFree( psz_temp );