1 /*****************************************************************************
2 * waveout.c : Windows waveOut plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2001 the VideoLAN team
7 * Authors: Gildas Bazin <gbazin@videolan.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
35 #include <vlc_charset.h>
40 #define FRAME_SIZE 4096 /* The size is in samples, not in bytes */
43 /*****************************************************************************
45 *****************************************************************************/
47 # define DWORD_PTR DWORD
48 # ifdef waveOutGetDevCaps
49 # undef waveOutGetDevCaps
50 MMRESULT WINAPI waveOutGetDevCaps(UINT, LPWAVEOUTCAPS, UINT);
54 #ifndef WAVE_FORMAT_IEEE_FLOAT
55 # define WAVE_FORMAT_IEEE_FLOAT 0x0003
58 #ifndef WAVE_FORMAT_DOLBY_AC3_SPDIF
59 # define WAVE_FORMAT_DOLBY_AC3_SPDIF 0x0092
62 #ifndef WAVE_FORMAT_EXTENSIBLE
63 #define WAVE_FORMAT_EXTENSIBLE 0xFFFE
66 #ifndef SPEAKER_FRONT_LEFT
67 # define SPEAKER_FRONT_LEFT 0x1
68 # define SPEAKER_FRONT_RIGHT 0x2
69 # define SPEAKER_FRONT_CENTER 0x4
70 # define SPEAKER_LOW_FREQUENCY 0x8
71 # define SPEAKER_BACK_LEFT 0x10
72 # define SPEAKER_BACK_RIGHT 0x20
73 # define SPEAKER_FRONT_LEFT_OF_CENTER 0x40
74 # define SPEAKER_FRONT_RIGHT_OF_CENTER 0x80
75 # define SPEAKER_BACK_CENTER 0x100
76 # define SPEAKER_SIDE_LEFT 0x200
77 # define SPEAKER_SIDE_RIGHT 0x400
78 # define SPEAKER_TOP_CENTER 0x800
79 # define SPEAKER_TOP_FRONT_LEFT 0x1000
80 # define SPEAKER_TOP_FRONT_CENTER 0x2000
81 # define SPEAKER_TOP_FRONT_RIGHT 0x4000
82 # define SPEAKER_TOP_BACK_LEFT 0x8000
83 # define SPEAKER_TOP_BACK_CENTER 0x10000
84 # define SPEAKER_TOP_BACK_RIGHT 0x20000
85 # define SPEAKER_RESERVED 0x80000000
88 #ifndef _WAVEFORMATEXTENSIBLE_
92 WORD wValidBitsPerSample; /* bits of precision */
93 WORD wSamplesPerBlock; /* valid if wBitsPerSample==0 */
94 WORD wReserved; /* If neither applies, set to zero. */
96 DWORD dwChannelMask; /* which channels are */
97 /* present in stream */
99 } WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE;
102 static const GUID __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = {WAVE_FORMAT_IEEE_FLOAT, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
103 static const GUID __KSDATAFORMAT_SUBTYPE_PCM = {WAVE_FORMAT_PCM, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
104 static const GUID __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF = {WAVE_FORMAT_DOLBY_AC3_SPDIF, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
106 /*****************************************************************************
108 *****************************************************************************/
109 static int Open ( vlc_object_t * );
110 static void Close ( vlc_object_t * );
111 static void Play ( aout_instance_t * );
113 /*****************************************************************************
114 * notification_thread_t: waveOut event thread
115 *****************************************************************************/
116 typedef struct notification_thread_t
119 aout_instance_t *p_aout;
121 } notification_thread_t;
123 /* local functions */
124 static void Probe ( aout_instance_t * );
125 static int OpenWaveOut ( aout_instance_t *, uint32_t,
126 int, int, int, int, bool );
127 static int OpenWaveOutPCM( aout_instance_t *, uint32_t,
128 int*, int, int, int, bool );
129 static int PlayWaveOut ( aout_instance_t *, HWAVEOUT, WAVEHDR *,
130 aout_buffer_t *, bool );
132 static void CALLBACK WaveOutCallback ( HWAVEOUT, UINT, DWORD, DWORD, DWORD );
133 static void* WaveOutThread( vlc_object_t * );
135 static int VolumeGet( aout_instance_t *, audio_volume_t * );
136 static int VolumeSet( aout_instance_t *, audio_volume_t );
138 static int WaveOutClearDoneBuffers(aout_sys_t *p_sys);
140 static int ReloadWaveoutDevices( vlc_object_t *, char const *,
141 vlc_value_t, vlc_value_t, void * );
142 static uint32_t findDeviceID(char *);
144 static const char psz_device_name_fmt[] = "%s ($%x,$%x)";
146 static const char *const ppsz_adev[] = { "wavemapper", };
147 static const char *const ppsz_adev_text[] = { N_("Microsoft Soundmapper") };
151 /*****************************************************************************
153 *****************************************************************************/
154 #define FLOAT_TEXT N_("Use float32 output")
155 #define FLOAT_LONGTEXT N_( \
156 "The option allows you to enable or disable the high-quality float32 " \
157 "audio output mode (which is not well supported by some soundcards)." )
158 #define DEVICE_TEXT N_("Select Audio Device")
159 #define DEVICE_LONG N_("Select special Audio device, or let windows "\
160 "decide (default), change needs VLC restart "\
162 #define DEFAULT_AUDIO_DEVICE N_("Default Audio Device")
165 set_shortname( "WaveOut" )
166 set_description( N_("Win32 waveOut extension output") )
167 set_capability( "audio output", 50 )
168 set_category( CAT_AUDIO )
169 set_subcategory( SUBCAT_AUDIO_AOUT )
170 add_bool( "waveout-float32", 1, 0, FLOAT_TEXT, FLOAT_LONGTEXT, true )
172 add_string( "waveout-audio-device", "wavemapper", NULL,
173 DEVICE_TEXT, DEVICE_LONG, false )
174 add_deprecated_alias( "waveout-dev" ) /* deprecated since 0.9.3 */
175 change_string_list( ppsz_adev, ppsz_adev_text, ReloadWaveoutDevices )
176 change_need_restart ()
177 change_action_add( ReloadWaveoutDevices, N_("Refresh list") )
180 set_callbacks( Open, Close )
183 /*****************************************************************************
184 * aout_sys_t: waveOut audio output method descriptor
185 *****************************************************************************
186 * This structure is part of the audio output thread descriptor.
187 * It describes the waveOut specific properties of an audio device.
188 *****************************************************************************/
191 uint32_t i_wave_device_id; /* ID of selected output device */
193 HWAVEOUT h_waveout; /* handle to waveout instance */
195 WAVEFORMATEXTENSIBLE waveformat; /* audio format */
197 WAVEHDR waveheader[FRAMES_NUM];
199 notification_thread_t *p_notif; /* WaveOutThread id */
201 HANDLE new_buffer_event;
203 // rental from alsa.c to synchronize startup of audiothread
204 int b_playing; /* playing status */
207 int i_repeat_counter;
211 uint8_t *p_silence_buffer; /* buffer we use to play silence */
213 bool b_chan_reorder; /* do we need channel reordering */
214 int pi_chan_table[AOUT_CHAN_MAX];
217 static const uint32_t pi_channels_src[] =
218 { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT,
219 AOUT_CHAN_MIDDLELEFT, AOUT_CHAN_MIDDLERIGHT,
220 AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT, AOUT_CHAN_REARCENTER,
221 AOUT_CHAN_CENTER, AOUT_CHAN_LFE, 0 };
222 static const uint32_t pi_channels_in[] =
223 { SPEAKER_FRONT_LEFT, SPEAKER_FRONT_RIGHT,
224 SPEAKER_SIDE_LEFT, SPEAKER_SIDE_RIGHT,
225 SPEAKER_BACK_LEFT, SPEAKER_BACK_RIGHT, SPEAKER_BACK_CENTER,
226 SPEAKER_FRONT_CENTER, SPEAKER_LOW_FREQUENCY, 0 };
227 static const uint32_t pi_channels_out[] =
228 { SPEAKER_FRONT_LEFT, SPEAKER_FRONT_RIGHT,
229 SPEAKER_FRONT_CENTER, SPEAKER_LOW_FREQUENCY,
230 SPEAKER_BACK_LEFT, SPEAKER_BACK_RIGHT,
232 SPEAKER_SIDE_LEFT, SPEAKER_SIDE_RIGHT, 0 };
234 /*****************************************************************************
235 * Open: open the audio device
236 *****************************************************************************
237 * This function opens and setups Win32 waveOut
238 *****************************************************************************/
239 static int Open( vlc_object_t *p_this )
241 aout_instance_t *p_aout = (aout_instance_t *)p_this;
245 /* Allocate structure */
246 p_aout->output.p_sys = malloc( sizeof( aout_sys_t ) );
248 if( p_aout->output.p_sys == NULL )
251 p_aout->output.pf_play = Play;
252 p_aout->b_die = false;
256 initialize/update Device selection List
258 ReloadWaveoutDevices( p_this, "waveout-audio-device", val, val, NULL);
262 check for configured audio device!
264 char *psz_waveout_dev = var_CreateGetString( p_aout, "waveout-audio-device");
266 p_aout->output.p_sys->i_wave_device_id =
267 findDeviceID( psz_waveout_dev );
269 if(p_aout->output.p_sys->i_wave_device_id == WAVE_MAPPER)
271 if(psz_waveout_dev &&
272 stricmp(psz_waveout_dev,"wavemapper"))
274 msg_Warn( p_aout, "configured audio device '%s' not available, "\
275 "use default instead", psz_waveout_dev );
278 free( psz_waveout_dev );
281 WAVEOUTCAPS waveoutcaps;
282 if(waveOutGetDevCaps( p_aout->output.p_sys->i_wave_device_id,
284 sizeof(WAVEOUTCAPS)) == MMSYSERR_NOERROR)
286 /* log debug some infos about driver, to know who to blame
287 if it doesn't work */
288 msg_Dbg( p_aout, "Drivername: %s", waveoutcaps.szPname);
289 msg_Dbg( p_aout, "Driver Version: %d.%d",
290 (waveoutcaps.vDriverVersion>>8)&255,
291 waveoutcaps.vDriverVersion & 255);
292 msg_Dbg( p_aout, "Manufacturer identifier: 0x%x", waveoutcaps.wMid );
293 msg_Dbg( p_aout, "Product identifier: 0x%x", waveoutcaps.wPid );
298 if( var_Type( p_aout, "audio-device" ) == 0 )
303 if( var_Get( p_aout, "audio-device", &val ) < 0 )
305 /* Probe() has failed. */
306 var_Destroy( p_aout, "waveout-audio-device");
307 free( p_aout->output.p_sys );
312 /* Open the device */
313 if( val.i_int == AOUT_VAR_SPDIF )
315 p_aout->output.output.i_format = VLC_CODEC_SPDIFL;
317 if( OpenWaveOut( p_aout,
318 p_aout->output.p_sys->i_wave_device_id,
320 p_aout->output.output.i_physical_channels,
321 aout_FormatNbChannels( &p_aout->output.output ),
322 p_aout->output.output.i_rate, false )
325 msg_Err( p_aout, "cannot open waveout audio device" );
326 free( p_aout->output.p_sys );
330 /* Calculate the frame size in bytes */
331 p_aout->output.i_nb_samples = A52_FRAME_NB;
332 p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
333 p_aout->output.output.i_frame_length = A52_FRAME_NB;
334 p_aout->output.p_sys->i_buffer_size =
335 p_aout->output.output.i_bytes_per_frame;
337 aout_VolumeNoneInit( p_aout );
346 p_aout->output.output.i_physical_channels
347 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
348 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
352 p_aout->output.output.i_physical_channels
353 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
354 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
357 p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
360 p_aout->output.output.i_physical_channels
361 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
364 if( OpenWaveOutPCM( p_aout,
365 p_aout->output.p_sys->i_wave_device_id,
366 &p_aout->output.output.i_format,
367 p_aout->output.output.i_physical_channels,
368 aout_FormatNbChannels( &p_aout->output.output ),
369 p_aout->output.output.i_rate, false )
372 msg_Err( p_aout, "cannot open waveout audio device" );
373 free( p_aout->output.p_sys );
377 /* Calculate the frame size in bytes */
378 p_aout->output.i_nb_samples = FRAME_SIZE;
379 aout_FormatPrepare( &p_aout->output.output );
380 p_aout->output.p_sys->i_buffer_size = FRAME_SIZE *
381 p_aout->output.output.i_bytes_per_frame;
383 aout_VolumeSoftInit( p_aout );
385 /* Check for hardware volume support */
386 if( waveOutGetDevCaps( (UINT_PTR)p_aout->output.p_sys->h_waveout,
387 &wocaps, sizeof(wocaps) ) == MMSYSERR_NOERROR &&
388 wocaps.dwSupport & WAVECAPS_VOLUME )
391 if( waveOutGetVolume( p_aout->output.p_sys->h_waveout, &i_dummy )
392 == MMSYSERR_NOERROR )
394 p_aout->output.pf_volume_get = VolumeGet;
395 p_aout->output.pf_volume_set = VolumeSet;
401 waveOutReset( p_aout->output.p_sys->h_waveout );
403 /* Allocate silence buffer */
404 p_aout->output.p_sys->p_silence_buffer =
405 malloc( p_aout->output.p_sys->i_buffer_size );
406 if( p_aout->output.p_sys->p_silence_buffer == NULL )
408 free( p_aout->output.p_sys );
411 p_aout->output.p_sys->i_repeat_counter = 0;
414 /* Zero the buffer. WinCE doesn't have calloc(). */
415 memset( p_aout->output.p_sys->p_silence_buffer, 0,
416 p_aout->output.p_sys->i_buffer_size );
418 /* Now we need to setup our waveOut play notification structure */
419 p_aout->output.p_sys->p_notif =
420 vlc_object_create( p_aout, sizeof(notification_thread_t) );
421 p_aout->output.p_sys->p_notif->p_aout = p_aout;
422 p_aout->output.p_sys->event = CreateEvent( NULL, FALSE, FALSE, NULL );
423 p_aout->output.p_sys->new_buffer_event = CreateEvent( NULL, FALSE, FALSE, NULL );
425 /* define startpoint of playback on first call to play()
426 like alsa does (instead of playing a blank sample) */
427 p_aout->output.p_sys->b_playing = 0;
428 p_aout->output.p_sys->start_date = 0;
431 /* Then launch the notification thread */
432 if( vlc_thread_create( p_aout->output.p_sys->p_notif,
433 "waveOut Notification Thread", WaveOutThread,
434 VLC_THREAD_PRIORITY_OUTPUT ) )
436 msg_Err( p_aout, "cannot create WaveOutThread" );
439 /* We need to kick off the playback in order to have the callback properly
441 for( i = 0; i < FRAMES_NUM; i++ )
443 p_aout->output.p_sys->waveheader[i].dwFlags = WHDR_DONE;
444 p_aout->output.p_sys->waveheader[i].dwUser = 0;
450 /*****************************************************************************
451 * Probe: probe the audio device for available formats and channels
452 *****************************************************************************/
453 static void Probe( aout_instance_t * p_aout )
455 vlc_value_t val, text;
457 unsigned int i_physical_channels;
459 var_Create( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
460 text.psz_string = _("Audio Device");
461 var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
463 /* Test for 5.1 support */
464 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
465 AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
466 AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE;
467 if( p_aout->output.output.i_physical_channels == i_physical_channels )
469 if( OpenWaveOutPCM( p_aout,
470 p_aout->output.p_sys->i_wave_device_id,
472 i_physical_channels, 6,
473 p_aout->output.output.i_rate, true )
476 val.i_int = AOUT_VAR_5_1;
477 text.psz_string = (char *)_("5.1");
478 var_Change( p_aout, "audio-device",
479 VLC_VAR_ADDCHOICE, &val, &text );
480 msg_Dbg( p_aout, "device supports 5.1 channels" );
484 /* Test for 2 Front 2 Rear support */
485 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
486 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
487 if( ( p_aout->output.output.i_physical_channels & i_physical_channels )
488 == i_physical_channels )
490 if( OpenWaveOutPCM( p_aout,
491 p_aout->output.p_sys->i_wave_device_id,
493 i_physical_channels, 4,
494 p_aout->output.output.i_rate, true )
497 val.i_int = AOUT_VAR_2F2R;
498 text.psz_string = (char *)_("2 Front 2 Rear");
499 var_Change( p_aout, "audio-device",
500 VLC_VAR_ADDCHOICE, &val, &text );
501 msg_Dbg( p_aout, "device supports 4 channels" );
505 /* Test for stereo support */
506 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
507 if( OpenWaveOutPCM( p_aout,
508 p_aout->output.p_sys->i_wave_device_id,
510 i_physical_channels, 2,
511 p_aout->output.output.i_rate, true )
514 val.i_int = AOUT_VAR_STEREO;
515 text.psz_string = (char *)_("Stereo");
516 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
517 msg_Dbg( p_aout, "device supports 2 channels" );
520 /* Test for mono support */
521 i_physical_channels = AOUT_CHAN_CENTER;
522 if( OpenWaveOutPCM( p_aout,
523 p_aout->output.p_sys->i_wave_device_id,
525 i_physical_channels, 1,
526 p_aout->output.output.i_rate, true )
529 val.i_int = AOUT_VAR_MONO;
530 text.psz_string = (char *)_("Mono");
531 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
532 msg_Dbg( p_aout, "device supports 1 channel" );
535 /* Test for SPDIF support */
536 if ( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
538 if( OpenWaveOut( p_aout,
539 p_aout->output.p_sys->i_wave_device_id,
541 p_aout->output.output.i_physical_channels,
542 aout_FormatNbChannels( &p_aout->output.output ),
543 p_aout->output.output.i_rate, true )
546 msg_Dbg( p_aout, "device supports A/52 over S/PDIF" );
547 val.i_int = AOUT_VAR_SPDIF;
548 text.psz_string = (char *)_("A/52 over S/PDIF");
549 var_Change( p_aout, "audio-device",
550 VLC_VAR_ADDCHOICE, &val, &text );
551 if( config_GetInt( p_aout, "spdif" ) )
552 var_Set( p_aout, "audio-device", val );
556 var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
559 /* Probe() has failed. */
560 var_Destroy( p_aout, "audio-device" );
564 var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
565 var_SetBool( p_aout, "intf-change", true );
568 /*****************************************************************************
569 * Play: play a sound buffer
570 *****************************************************************************
571 * This doesn't actually play the buffer. This just stores the buffer so it
572 * can be played by the callback thread.
573 *****************************************************************************/
574 static void Play( aout_instance_t *_p_aout )
576 if( !_p_aout->output.p_sys->b_playing )
578 _p_aout->output.p_sys->b_playing = 1;
580 /* get the playing date of the first aout buffer */
581 _p_aout->output.p_sys->start_date =
582 aout_FifoFirstDate( _p_aout, &_p_aout->output.fifo );
584 msg_Dbg( _p_aout, "Wakeup sleeping output thread.");
586 /* wake up the audio output thread */
587 SetEvent( _p_aout->output.p_sys->event );
589 SetEvent( _p_aout->output.p_sys->new_buffer_event );
593 /*****************************************************************************
594 * Close: close the audio device
595 *****************************************************************************/
596 static void Close( vlc_object_t *p_this )
598 aout_instance_t *p_aout = (aout_instance_t *)p_this;
599 aout_sys_t *p_sys = p_aout->output.p_sys;
601 /* Before calling waveOutClose we must reset the device */
602 vlc_object_kill( p_aout );
604 /* wake up the audio thread, to recognize that p_aout died */
605 SetEvent( p_sys->event );
606 SetEvent( p_sys->new_buffer_event );
608 vlc_thread_join( p_sys->p_notif );
609 vlc_object_release( p_sys->p_notif );
612 kill the real output then - when the feed thread
613 is surely terminated!
614 old code could be too early in case that "feeding"
615 was running on termination
617 at this point now its sure, that there will be no new
618 data send to the driver, and we can cancel the last
621 MMRESULT result = waveOutReset( p_sys->h_waveout );
622 if(result != MMSYSERR_NOERROR)
624 msg_Err( p_aout, "waveOutReset failed 0x%x", result );
626 now we must wait, that all buffers are played
627 because cancel doesn't work in this case...
629 if(result == MMSYSERR_NOTSUPPORTED)
632 clear currently played (done) buffers,
633 if returnvalue > 0 (means some buffer still playing)
634 wait for the driver event callback that one buffer
635 is finished with playing, and check again
636 the timeout of 5000ms is just, an emergency exit
637 of this loop, to avoid deadlock in case of other
638 (currently not known bugs, problems, errors cases?)
641 (WaveOutClearDoneBuffers( p_sys ) > 0)
643 (WaitForSingleObject( p_sys->event, 5000) == WAIT_OBJECT_0)
646 msg_Dbg( p_aout, "Wait for waveout device...");
650 WaveOutClearDoneBuffers( p_sys );
653 /* now we can Close the device */
654 if( waveOutClose( p_sys->h_waveout ) != MMSYSERR_NOERROR )
656 msg_Err( p_aout, "waveOutClose failed" );
660 because so long, the waveout device is playing, the callback
661 could occur and need the events
663 CloseHandle( p_sys->event );
664 CloseHandle( p_sys->new_buffer_event);
666 free( p_sys->p_silence_buffer );
670 /*****************************************************************************
671 * OpenWaveOut: open the waveout sound device
672 ****************************************************************************/
673 static int OpenWaveOut( aout_instance_t *p_aout, uint32_t i_device_id, int i_format,
674 int i_channels, int i_nb_channels, int i_rate,
680 /* Set sound format */
682 #define waveformat p_aout->output.p_sys->waveformat
684 waveformat.dwChannelMask = 0;
685 for( i = 0; i < sizeof(pi_channels_src)/sizeof(uint32_t); i++ )
687 if( i_channels & pi_channels_src[i] )
688 waveformat.dwChannelMask |= pi_channels_in[i];
693 case VLC_CODEC_SPDIFL:
695 /* To prevent channel re-ordering */
696 waveformat.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
697 waveformat.Format.wBitsPerSample = 16;
698 waveformat.Samples.wValidBitsPerSample =
699 waveformat.Format.wBitsPerSample;
700 waveformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
701 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF;
705 waveformat.Format.wBitsPerSample = sizeof(float) * 8;
706 waveformat.Samples.wValidBitsPerSample =
707 waveformat.Format.wBitsPerSample;
708 waveformat.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
709 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
713 waveformat.Format.wBitsPerSample = 16;
714 waveformat.Samples.wValidBitsPerSample =
715 waveformat.Format.wBitsPerSample;
716 waveformat.Format.wFormatTag = WAVE_FORMAT_PCM;
717 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_PCM;
721 waveformat.Format.nChannels = i_nb_channels;
722 waveformat.Format.nSamplesPerSec = i_rate;
723 waveformat.Format.nBlockAlign =
724 waveformat.Format.wBitsPerSample / 8 * i_nb_channels;
725 waveformat.Format.nAvgBytesPerSec =
726 waveformat.Format.nSamplesPerSec * waveformat.Format.nBlockAlign;
728 /* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */
729 if( i_nb_channels <= 2 )
731 waveformat.Format.cbSize = 0;
735 waveformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
736 waveformat.Format.cbSize =
737 sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
741 msg_Dbg( p_aout, "OpenWaveDevice-ID: %u", i_device_id);
742 msg_Dbg( p_aout,"waveformat.Format.cbSize = %d",
743 waveformat.Format.cbSize);
744 msg_Dbg( p_aout,"waveformat.Format.wFormatTag = %u",
745 waveformat.Format.wFormatTag);
746 msg_Dbg( p_aout,"waveformat.Format.nChannels = %u",
747 waveformat.Format.nChannels);
748 msg_Dbg( p_aout,"waveformat.Format.nSamplesPerSec = %d",
749 (int)waveformat.Format.nSamplesPerSec);
750 msg_Dbg( p_aout,"waveformat.Format.nAvgBytesPerSec = %u",
751 (int)waveformat.Format.nAvgBytesPerSec);
752 msg_Dbg( p_aout,"waveformat.Format.nBlockAlign = %d",
753 waveformat.Format.nBlockAlign);
754 msg_Dbg( p_aout,"waveformat.Format.wBitsPerSample = %d",
755 waveformat.Format.wBitsPerSample);
756 msg_Dbg( p_aout,"waveformat.Samples.wValidBitsPerSample = %d",
757 waveformat.Samples.wValidBitsPerSample);
758 msg_Dbg( p_aout,"waveformat.Samples.wSamplesPerBlock = %d",
759 waveformat.Samples.wSamplesPerBlock);
760 msg_Dbg( p_aout,"waveformat.dwChannelMask = %lu",
761 waveformat.dwChannelMask);
764 /* Open the device */
765 result = waveOutOpen( &p_aout->output.p_sys->h_waveout, i_device_id,
766 (WAVEFORMATEX *)&waveformat,
767 (DWORD_PTR)WaveOutCallback, (DWORD_PTR)p_aout,
768 CALLBACK_FUNCTION | (b_probe?WAVE_FORMAT_QUERY:0) );
769 if( result == WAVERR_BADFORMAT )
771 msg_Warn( p_aout, "waveOutOpen failed WAVERR_BADFORMAT" );
774 if( result == MMSYSERR_ALLOCATED )
776 msg_Warn( p_aout, "waveOutOpen failed WAVERR_ALLOCATED" );
779 if( result != MMSYSERR_NOERROR )
781 msg_Warn( p_aout, "waveOutOpen failed" );
785 p_aout->output.p_sys->b_chan_reorder =
786 aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
787 waveformat.dwChannelMask, i_nb_channels,
788 p_aout->output.p_sys->pi_chan_table );
790 if( p_aout->output.p_sys->b_chan_reorder )
792 msg_Dbg( p_aout, "channel reordering needed" );
801 /*****************************************************************************
802 * OpenWaveOutPCM: open a PCM waveout sound device
803 ****************************************************************************/
804 static int OpenWaveOutPCM( aout_instance_t *p_aout, uint32_t i_device_id, int *i_format,
805 int i_channels, int i_nb_channels, int i_rate,
808 bool b_use_float32 = var_CreateGetBool( p_aout, "waveout-float32");
810 if( !b_use_float32 || OpenWaveOut( p_aout, i_device_id, VLC_CODEC_FL32,
811 i_channels, i_nb_channels, i_rate, b_probe )
814 if ( OpenWaveOut( p_aout, i_device_id, VLC_CODEC_S16L,
815 i_channels, i_nb_channels, i_rate, b_probe )
822 *i_format = VLC_CODEC_S16L;
828 *i_format = VLC_CODEC_FL32;
833 /*****************************************************************************
834 * PlayWaveOut: play a buffer through the WaveOut device
835 *****************************************************************************/
836 static int PlayWaveOut( aout_instance_t *p_aout, HWAVEOUT h_waveout,
837 WAVEHDR *p_waveheader, aout_buffer_t *p_buffer,
842 /* Prepare the buffer */
843 if( p_buffer != NULL )
845 p_waveheader->lpData = p_buffer->p_buffer;
847 copy the buffer to the silence buffer :) so in case we don't
848 get the next buffer fast enough (I will repeat this one a time
849 for AC3 / DTS and SPDIF this will sound better instead of
854 vlc_memcpy( p_aout->output.p_sys->p_silence_buffer,
856 p_aout->output.p_sys->i_buffer_size );
857 p_aout->output.p_sys->i_repeat_counter = 2;
860 /* Use silence buffer instead */
861 if(p_aout->output.p_sys->i_repeat_counter)
863 p_aout->output.p_sys->i_repeat_counter--;
864 if(!p_aout->output.p_sys->i_repeat_counter)
866 vlc_memset( p_aout->output.p_sys->p_silence_buffer,
867 0x00, p_aout->output.p_sys->i_buffer_size );
870 p_waveheader->lpData = p_aout->output.p_sys->p_silence_buffer;
873 p_waveheader->dwUser = p_buffer ? (DWORD_PTR)p_buffer : (DWORD_PTR)1;
874 p_waveheader->dwBufferLength = p_aout->output.p_sys->i_buffer_size;
875 p_waveheader->dwFlags = 0;
877 result = waveOutPrepareHeader( h_waveout, p_waveheader, sizeof(WAVEHDR) );
878 if( result != MMSYSERR_NOERROR )
880 msg_Err( p_aout, "waveOutPrepareHeader failed" );
884 /* Send the buffer to the waveOut queue */
885 result = waveOutWrite( h_waveout, p_waveheader, sizeof(WAVEHDR) );
886 if( result != MMSYSERR_NOERROR )
888 msg_Err( p_aout, "waveOutWrite failed" );
895 /*****************************************************************************
896 * WaveOutCallback: what to do once WaveOut has played its sound samples
897 *****************************************************************************/
898 static void CALLBACK WaveOutCallback( HWAVEOUT h_waveout, UINT uMsg,
900 DWORD dwParam1, DWORD dwParam2 )
902 (void)h_waveout; (void)dwParam1; (void)dwParam2;
903 aout_instance_t *p_aout = (aout_instance_t *)_p_aout;
904 int i, i_queued_frames = 0;
906 if( uMsg != WOM_DONE ) return;
908 if( !vlc_object_alive (p_aout) ) return;
910 /* Find out the current latency */
911 for( i = 0; i < FRAMES_NUM; i++ )
913 /* Check if frame buf is available */
914 if( !(p_aout->output.p_sys->waveheader[i].dwFlags & WHDR_DONE) )
920 /* Don't wake up the thread too much */
921 if( i_queued_frames <= FRAMES_NUM/2 )
922 SetEvent( p_aout->output.p_sys->event );
926 /****************************************************************************
927 * WaveOutClearDoneBuffers: Clear all done marked buffers, and free aout_bufer
928 ****************************************************************************
929 * return value is the number of still playing buffers in the queue
930 ****************************************************************************/
931 static int WaveOutClearDoneBuffers(aout_sys_t *p_sys)
933 WAVEHDR *p_waveheader = p_sys->waveheader;
934 int i_queued_frames = 0;
936 for( int i = 0; i < FRAMES_NUM; i++ )
938 if( (p_waveheader[i].dwFlags & WHDR_DONE) &&
939 p_waveheader[i].dwUser )
941 aout_buffer_t *p_buffer =
942 (aout_buffer_t *)(p_waveheader[i].dwUser);
943 /* Unprepare and free the buffers which has just been played */
944 waveOutUnprepareHeader( p_sys->h_waveout, &p_waveheader[i],
947 if( p_waveheader[i].dwUser != 1 )
948 aout_BufferFree( p_buffer );
950 p_waveheader[i].dwUser = 0;
953 /* Check if frame buf is available */
954 if( !(p_waveheader[i].dwFlags & WHDR_DONE) )
959 return i_queued_frames;
962 /*****************************************************************************
963 * WaveOutThread: this thread will capture play notification events.
964 *****************************************************************************
965 * We use this thread to feed new audio samples to the sound card because
966 * we are not authorized to use waveOutWrite() directly in the waveout
968 *****************************************************************************/
969 static void* WaveOutThread( vlc_object_t *p_this )
971 notification_thread_t *p_notif = (notification_thread_t*)p_this;
972 aout_instance_t *p_aout = p_notif->p_aout;
973 aout_sys_t *p_sys = p_aout->output.p_sys;
974 aout_buffer_t *p_buffer = NULL;
975 WAVEHDR *p_waveheader = p_sys->waveheader;
976 int i, i_queued_frames;
979 uint32_t i_buffer_length = 64;
980 int canc = vlc_savecancel ();
982 /* We don't want any resampling when using S/PDIF */
983 b_sleek = p_aout->output.output.i_format == VLC_CODEC_SPDIFL;
985 // wait for first call to "play()"
986 while( !p_sys->start_date && vlc_object_alive (p_aout) )
987 WaitForSingleObject( p_sys->event, INFINITE );
988 if( !vlc_object_alive (p_aout) )
991 msg_Dbg( p_aout, "will start to play in %"PRId64" us",
992 (p_sys->start_date - AOUT_PTS_TOLERANCE/4)-mdate());
994 // than wait a short time... before grabbing first frames
995 mwait( p_sys->start_date - AOUT_PTS_TOLERANCE/4 );
997 #define waveout_warn(msg) msg_Warn( p_aout, "aout_OutputNextBuffer no buffer "\
998 "got next_date=%d ms, "\
999 "%d frames to play, "\
1000 "starving? %d, %s",(int)(next_date/(mtime_t)1000), \
1002 p_aout->output.b_starving, msg);
1003 next_date = mdate();
1005 while( vlc_object_alive (p_aout) )
1007 /* Cleanup and find out the current latency */
1008 i_queued_frames = WaveOutClearDoneBuffers( p_sys );
1010 if( !vlc_object_alive (p_aout) ) return NULL;
1012 /* Try to fill in as many frame buffers as possible */
1013 for( i = 0; i < FRAMES_NUM; i++ )
1015 /* Check if frame buf is available */
1016 if( p_waveheader[i].dwFlags & WHDR_DONE )
1018 // next_date = mdate() + 1000000 * i_queued_frames /
1019 // p_aout->output.output.i_rate * p_aout->output.i_nb_samples;
1021 // the realtime has got our back-site:) to come in sync
1022 if(next_date < mdate())
1023 next_date = mdate();
1026 /* Take into account the latency */
1027 p_buffer = aout_OutputNextBuffer( p_aout,
1034 msg_Dbg( p_aout, "aout_OutputNextBuffer no buffer "\
1035 "got next_date=%d ms, "\
1036 "%d frames to play, "\
1037 "starving? %d",(int)(next_date/(mtime_t)1000),
1039 p_aout->output.b_starving);
1041 if(p_aout->output.b_starving)
1043 // means we are too early to request a new buffer?
1044 waveout_warn("waiting...")
1045 next_date = aout_FifoFirstDate( p_aout, &p_aout->output.fifo );
1046 mwait( next_date - AOUT_PTS_TOLERANCE/4 );
1047 next_date = mdate();
1048 p_buffer = aout_OutputNextBuffer( p_aout,
1055 if( !p_buffer && i_queued_frames )
1057 /* We aren't late so no need to play a blank sample */
1063 mtime_t buffer_length = (p_buffer->end_date
1064 - p_buffer->start_date);
1065 next_date = next_date + buffer_length;
1066 i_buffer_length = buffer_length/1000;
1069 /* Do the channel reordering */
1070 if( p_buffer && p_sys->b_chan_reorder )
1072 aout_ChannelReorder( p_buffer->p_buffer,
1073 p_buffer->i_nb_bytes,
1074 p_sys->waveformat.Format.nChannels,
1075 p_sys->pi_chan_table,
1076 p_sys->waveformat.Format.wBitsPerSample );
1079 PlayWaveOut( p_aout, p_sys->h_waveout,
1080 &p_waveheader[i], p_buffer, b_sleek );
1086 if( !vlc_object_alive (p_aout) ) return NULL;
1089 deal with the case that the loop didn't fillup the buffer to the
1090 max - instead of waiting that half the buffer is played before
1091 fillup the waveout buffers, wait only for the next sample buffer
1092 to arrive at the play method...
1094 this will also avoid, that the last buffer is play until the
1095 end, and then trying to get more data, so it will also
1096 work - if the next buffer will arrive some ms before the
1097 last buffer is finished.
1099 if(i_queued_frames < FRAMES_NUM)
1100 WaitForSingleObject( p_sys->new_buffer_event, INFINITE );
1102 WaitForSingleObject( p_sys->event, INFINITE );
1107 vlc_restorecancel (canc);
1111 static int VolumeGet( aout_instance_t * p_aout, audio_volume_t * pi_volume )
1113 DWORD i_waveout_vol;
1116 waveOutGetVolume( 0, &i_waveout_vol );
1118 waveOutGetVolume( p_aout->output.p_sys->h_waveout, &i_waveout_vol );
1121 i_waveout_vol &= 0xFFFF;
1122 *pi_volume = p_aout->output.i_volume =
1123 (i_waveout_vol * AOUT_VOLUME_MAX + 0xFFFF /*rounding*/) / 2 / 0xFFFF;
1127 static int VolumeSet( aout_instance_t * p_aout, audio_volume_t i_volume )
1129 unsigned long i_waveout_vol = i_volume * 0xFFFF * 2 / AOUT_VOLUME_MAX;
1130 i_waveout_vol |= (i_waveout_vol << 16);
1133 waveOutSetVolume( 0, i_waveout_vol );
1135 waveOutSetVolume( p_aout->output.p_sys->h_waveout, i_waveout_vol );
1138 p_aout->output.i_volume = i_volume;
1144 reload the configuration drop down list, of the Audio Devices
1146 static int ReloadWaveoutDevices( vlc_object_t *p_this, char const *psz_name,
1147 vlc_value_t newval, vlc_value_t oldval, void *data )
1151 module_config_t *p_item = config_FindConfig( p_this, psz_name );
1152 if( !p_item ) return VLC_SUCCESS;
1154 /* Clear-up the current list */
1155 if( p_item->i_list )
1157 /* Keep the first entry */
1158 for( i = 1; i < p_item->i_list; i++ )
1160 free((char *)(p_item->ppsz_list[i]) );
1161 free((char *)(p_item->ppsz_list_text[i]) );
1163 /* TODO: Remove when no more needed */
1164 p_item->ppsz_list[i] = NULL;
1165 p_item->ppsz_list_text[i] = NULL;
1169 int wave_devices = waveOutGetNumDevs();
1172 (char **)realloc( p_item->ppsz_list,
1173 (wave_devices+2) * sizeof(char *) );
1174 p_item->ppsz_list_text =
1175 (char **)realloc( p_item->ppsz_list_text,
1176 (wave_devices+2) * sizeof(char *) );
1179 char sz_dev_name[MAXPNAMELEN+32];
1181 for(int i=0; i<wave_devices; i++)
1183 if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
1184 == MMSYSERR_NOERROR)
1186 sprintf( sz_dev_name, psz_device_name_fmt, caps.szPname,
1190 p_item->ppsz_list[j] = FromLocaleDup( sz_dev_name );
1191 p_item->ppsz_list_text[j] = FromLocaleDup( sz_dev_name );
1197 p_item->ppsz_list[j] = NULL;
1198 p_item->ppsz_list_text[j] = NULL;
1200 /* Signal change to the interface */
1201 p_item->b_dirty = true;
1207 convert devicename to device ID for output
1208 if device not found return WAVE_MAPPER, so let
1209 windows decide which preferred audio device
1212 static uint32_t findDeviceID(char *psz_device_name)
1214 if(!psz_device_name)
1217 uint32_t wave_devices = waveOutGetNumDevs();
1219 char sz_dev_name[MAXPNAMELEN+32];
1220 for(uint32_t i=0; i<wave_devices; i++)
1222 if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
1223 == MMSYSERR_NOERROR)
1225 sprintf(sz_dev_name, psz_device_name_fmt, caps.szPname,
1229 char *psz_temp = FromLocaleDup(sz_dev_name);
1231 if( !stricmp(psz_temp, psz_device_name) )
1233 LocaleFree( psz_temp );
1236 LocaleFree( psz_temp );