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( notification_thread_t * );
135 static int VolumeInfos( aout_instance_t *, audio_volume_t * );
136 static int VolumeGet( aout_instance_t *, audio_volume_t * );
137 static int VolumeSet( aout_instance_t *, audio_volume_t );
139 static int WaveOutClearDoneBuffers(aout_sys_t *p_sys);
141 static int ReloadWaveoutDevices( vlc_object_t *, char const *,
142 vlc_value_t, vlc_value_t, void * );
143 static uint32_t findDeviceID(char *);
145 static const char psz_device_name_fmt[] = "%s ($%x,$%x)";
147 static const char *const ppsz_adev[] = { "wavemapper", };
148 static const char *const ppsz_adev_text[] = { N_("Microsoft Soundmapper") };
152 /*****************************************************************************
154 *****************************************************************************/
155 #define FLOAT_TEXT N_("Use float32 output")
156 #define FLOAT_LONGTEXT N_( \
157 "The option allows you to enable or disable the high-quality float32 " \
158 "audio output mode (which is not well supported by some soundcards)." )
159 #define DEVICE_TEXT N_("Select Audio Device")
160 #define DEVICE_LONG N_("Select special Audio device, or let windows "\
161 "decide (default), change needs VLC restart "\
163 #define DEFAULT_AUDIO_DEVICE N_("Default Audio Device")
166 set_shortname( "WaveOut" );
167 set_description( N_("Win32 waveOut extension output") );
168 set_capability( "audio output", 50 );
169 set_category( CAT_AUDIO );
170 set_subcategory( SUBCAT_AUDIO_AOUT );
171 add_bool( "waveout-float32", 1, 0, FLOAT_TEXT, FLOAT_LONGTEXT, true );
173 add_string( "waveout-dev", "wavemapper", NULL,
174 DEVICE_TEXT, DEVICE_LONG, false );
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,
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,
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,
231 SPEAKER_SIDE_LEFT, SPEAKER_SIDE_RIGHT, 0 };
233 /*****************************************************************************
234 * Open: open the audio device
235 *****************************************************************************
236 * This function opens and setups Win32 waveOut
237 *****************************************************************************/
238 static int Open( vlc_object_t *p_this )
240 aout_instance_t *p_aout = (aout_instance_t *)p_this;
244 /* Allocate structure */
245 p_aout->output.p_sys = malloc( sizeof( aout_sys_t ) );
247 if( p_aout->output.p_sys == NULL )
250 p_aout->output.pf_play = Play;
251 p_aout->b_die = false;
255 initialize/update Device selection List
257 ReloadWaveoutDevices( p_this, "waveout-dev", val, val, NULL);
261 check for configured audio device!
263 char *psz_waveout_dev = var_CreateGetString( p_aout, "waveout-dev");
265 p_aout->output.p_sys->i_wave_device_id =
266 findDeviceID( psz_waveout_dev );
268 if(p_aout->output.p_sys->i_wave_device_id == WAVE_MAPPER)
270 if(psz_waveout_dev &&
271 stricmp(psz_waveout_dev,"wavemapper"))
273 msg_Warn( p_aout, "configured audio device '%s' not available, "\
274 "use default instead", psz_waveout_dev );
277 free( psz_waveout_dev );
280 WAVEOUTCAPS waveoutcaps;
281 if(waveOutGetDevCaps( p_aout->output.p_sys->i_wave_device_id,
283 sizeof(WAVEOUTCAPS)) == MMSYSERR_NOERROR)
285 /* log debug some infos about driver, to know who to blame
286 if it doesn't work */
287 msg_Dbg( p_aout, "Drivername: %s", waveoutcaps.szPname);
288 msg_Dbg( p_aout, "Driver Version: %d.%d",
289 (waveoutcaps.vDriverVersion>>8)&255,
290 waveoutcaps.vDriverVersion & 255);
291 msg_Dbg( p_aout, "Manufacturer identifier: 0x%x", waveoutcaps.wMid );
292 msg_Dbg( p_aout, "Product identifier: 0x%x", waveoutcaps.wPid );
297 if( var_Type( p_aout, "audio-device" ) == 0 )
302 if( var_Get( p_aout, "audio-device", &val ) < 0 )
304 /* Probe() has failed. */
305 var_Destroy( p_aout, "waveout-device");
306 free( p_aout->output.p_sys );
311 /* Open the device */
312 if( val.i_int == AOUT_VAR_SPDIF )
314 p_aout->output.output.i_format = VLC_FOURCC('s','p','d','i');
316 if( OpenWaveOut( p_aout,
317 p_aout->output.p_sys->i_wave_device_id,
318 VLC_FOURCC('s','p','d','i'),
319 p_aout->output.output.i_physical_channels,
320 aout_FormatNbChannels( &p_aout->output.output ),
321 p_aout->output.output.i_rate, false )
324 msg_Err( p_aout, "cannot open waveout audio device" );
325 free( p_aout->output.p_sys );
329 /* Calculate the frame size in bytes */
330 p_aout->output.i_nb_samples = A52_FRAME_NB;
331 p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
332 p_aout->output.output.i_frame_length = A52_FRAME_NB;
333 p_aout->output.p_sys->i_buffer_size =
334 p_aout->output.output.i_bytes_per_frame;
336 aout_VolumeNoneInit( p_aout );
342 if( val.i_int == AOUT_VAR_5_1 )
344 p_aout->output.output.i_physical_channels
345 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
346 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
349 else if( val.i_int == AOUT_VAR_2F2R )
351 p_aout->output.output.i_physical_channels
352 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
353 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
355 else if( val.i_int == AOUT_VAR_MONO )
357 p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
361 p_aout->output.output.i_physical_channels
362 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
365 if( OpenWaveOutPCM( p_aout,
366 p_aout->output.p_sys->i_wave_device_id,
367 &p_aout->output.output.i_format,
368 p_aout->output.output.i_physical_channels,
369 aout_FormatNbChannels( &p_aout->output.output ),
370 p_aout->output.output.i_rate, false )
373 msg_Err( p_aout, "cannot open waveout audio device" );
374 free( p_aout->output.p_sys );
378 /* Calculate the frame size in bytes */
379 p_aout->output.i_nb_samples = FRAME_SIZE;
380 aout_FormatPrepare( &p_aout->output.output );
381 p_aout->output.p_sys->i_buffer_size = FRAME_SIZE *
382 p_aout->output.output.i_bytes_per_frame;
384 aout_VolumeSoftInit( p_aout );
386 /* Check for hardware volume support */
387 if( waveOutGetDevCaps( (UINT_PTR)p_aout->output.p_sys->h_waveout,
388 &wocaps, sizeof(wocaps) ) == MMSYSERR_NOERROR &&
389 wocaps.dwSupport & WAVECAPS_VOLUME )
392 if( waveOutGetVolume( p_aout->output.p_sys->h_waveout, &i_dummy )
393 == MMSYSERR_NOERROR )
395 p_aout->output.pf_volume_infos = VolumeInfos;
396 p_aout->output.pf_volume_get = VolumeGet;
397 p_aout->output.pf_volume_set = VolumeSet;
403 waveOutReset( p_aout->output.p_sys->h_waveout );
405 /* Allocate silence buffer */
406 p_aout->output.p_sys->p_silence_buffer =
407 malloc( p_aout->output.p_sys->i_buffer_size );
408 if( p_aout->output.p_sys->p_silence_buffer == NULL )
410 free( p_aout->output.p_sys );
413 p_aout->output.p_sys->i_repeat_counter = 0;
416 /* Zero the buffer. WinCE doesn't have calloc(). */
417 memset( p_aout->output.p_sys->p_silence_buffer, 0,
418 p_aout->output.p_sys->i_buffer_size );
420 /* Now we need to setup our waveOut play notification structure */
421 p_aout->output.p_sys->p_notif =
422 vlc_object_create( p_aout, sizeof(notification_thread_t) );
423 p_aout->output.p_sys->p_notif->p_aout = p_aout;
424 p_aout->output.p_sys->event = CreateEvent( NULL, FALSE, FALSE, NULL );
425 p_aout->output.p_sys->new_buffer_event = CreateEvent( NULL, FALSE, FALSE, NULL );
427 /* define startpoint of playback on first call to play()
428 like alsa does (instead of playing a blank sample) */
429 p_aout->output.p_sys->b_playing = 0;
430 p_aout->output.p_sys->start_date = 0;
433 /* Then launch the notification thread */
434 if( vlc_thread_create( p_aout->output.p_sys->p_notif,
435 "waveOut Notification Thread", WaveOutThread,
436 VLC_THREAD_PRIORITY_OUTPUT, false ) )
438 msg_Err( p_aout, "cannot create WaveOutThread" );
441 /* We need to kick off the playback in order to have the callback properly
443 for( i = 0; i < FRAMES_NUM; i++ )
445 p_aout->output.p_sys->waveheader[i].dwFlags = WHDR_DONE;
446 p_aout->output.p_sys->waveheader[i].dwUser = 0;
452 /*****************************************************************************
453 * Probe: probe the audio device for available formats and channels
454 *****************************************************************************/
455 static void Probe( aout_instance_t * p_aout )
457 vlc_value_t val, text;
459 unsigned int i_physical_channels;
461 var_Create( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
462 text.psz_string = _("Audio Device");
463 var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
465 /* Test for 5.1 support */
466 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
467 AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
468 AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE;
469 if( p_aout->output.output.i_physical_channels == i_physical_channels )
471 if( OpenWaveOutPCM( p_aout,
472 p_aout->output.p_sys->i_wave_device_id,
474 i_physical_channels, 6,
475 p_aout->output.output.i_rate, true )
478 val.i_int = AOUT_VAR_5_1;
479 text.psz_string = (char *)N_("5.1");
480 var_Change( p_aout, "audio-device",
481 VLC_VAR_ADDCHOICE, &val, &text );
482 msg_Dbg( p_aout, "device supports 5.1 channels" );
486 /* Test for 2 Front 2 Rear support */
487 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
488 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
489 if( ( p_aout->output.output.i_physical_channels & i_physical_channels )
490 == i_physical_channels )
492 if( OpenWaveOutPCM( p_aout,
493 p_aout->output.p_sys->i_wave_device_id,
495 i_physical_channels, 4,
496 p_aout->output.output.i_rate, true )
499 val.i_int = AOUT_VAR_2F2R;
500 text.psz_string = (char *)N_("2 Front 2 Rear");
501 var_Change( p_aout, "audio-device",
502 VLC_VAR_ADDCHOICE, &val, &text );
503 msg_Dbg( p_aout, "device supports 4 channels" );
507 /* Test for stereo support */
508 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
509 if( OpenWaveOutPCM( p_aout,
510 p_aout->output.p_sys->i_wave_device_id,
512 i_physical_channels, 2,
513 p_aout->output.output.i_rate, true )
516 val.i_int = AOUT_VAR_STEREO;
517 text.psz_string = (char *)N_("Stereo");
518 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
519 msg_Dbg( p_aout, "device supports 2 channels" );
522 /* Test for mono support */
523 i_physical_channels = AOUT_CHAN_CENTER;
524 if( OpenWaveOutPCM( p_aout,
525 p_aout->output.p_sys->i_wave_device_id,
527 i_physical_channels, 1,
528 p_aout->output.output.i_rate, true )
531 val.i_int = AOUT_VAR_MONO;
532 text.psz_string = (char *)N_("Mono");
533 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
534 msg_Dbg( p_aout, "device supports 1 channel" );
537 /* Test for SPDIF support */
538 if ( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
540 if( OpenWaveOut( p_aout,
541 p_aout->output.p_sys->i_wave_device_id,
542 VLC_FOURCC('s','p','d','i'),
543 p_aout->output.output.i_physical_channels,
544 aout_FormatNbChannels( &p_aout->output.output ),
545 p_aout->output.output.i_rate, true )
548 msg_Dbg( p_aout, "device supports A/52 over S/PDIF" );
549 val.i_int = AOUT_VAR_SPDIF;
550 text.psz_string = (char *)N_("A/52 over S/PDIF");
551 var_Change( p_aout, "audio-device",
552 VLC_VAR_ADDCHOICE, &val, &text );
553 if( config_GetInt( p_aout, "spdif" ) )
554 var_Set( p_aout, "audio-device", val );
558 var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
561 /* Probe() has failed. */
562 var_Destroy( p_aout, "audio-device" );
566 var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
569 var_Set( p_aout, "intf-change", val );
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_FOURCC('s','p','d','i'):
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;
708 case VLC_FOURCC('f','l','3','2'):
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;
716 case VLC_FOURCC('s','1','6','l'):
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, int *i_format,
809 int i_channels, int i_nb_channels, int i_rate,
812 bool b_use_float32 = var_CreateGetBool( p_aout, "waveout-float32");
814 if( !b_use_float32 || OpenWaveOut( p_aout, i_device_id, VLC_FOURCC('f','l','3','2'),
815 i_channels, i_nb_channels, i_rate, b_probe )
818 if ( OpenWaveOut( p_aout, i_device_id, VLC_FOURCC('s','1','6','l'),
819 i_channels, i_nb_channels, i_rate, b_probe )
826 *i_format = VLC_FOURCC('s','1','6','l');
832 *i_format = VLC_FOURCC('f','l','3','2');
837 /*****************************************************************************
838 * PlayWaveOut: play a buffer through the WaveOut device
839 *****************************************************************************/
840 static int PlayWaveOut( aout_instance_t *p_aout, HWAVEOUT h_waveout,
841 WAVEHDR *p_waveheader, aout_buffer_t *p_buffer,
846 /* Prepare the buffer */
847 if( p_buffer != NULL )
849 p_waveheader->lpData = p_buffer->p_buffer;
851 copy the buffer to the silence buffer :) so in case we don't
852 get the next buffer fast enough (I will repeat this one a time
853 for AC3 / DTS and SPDIF this will sound better instead of
858 vlc_memcpy( p_aout->output.p_sys->p_silence_buffer,
860 p_aout->output.p_sys->i_buffer_size );
861 p_aout->output.p_sys->i_repeat_counter = 2;
864 /* Use silence buffer instead */
865 if(p_aout->output.p_sys->i_repeat_counter)
867 p_aout->output.p_sys->i_repeat_counter--;
868 if(!p_aout->output.p_sys->i_repeat_counter)
870 vlc_memset( p_aout->output.p_sys->p_silence_buffer,
871 0x00, p_aout->output.p_sys->i_buffer_size );
874 p_waveheader->lpData = p_aout->output.p_sys->p_silence_buffer;
877 p_waveheader->dwUser = p_buffer ? (DWORD_PTR)p_buffer : (DWORD_PTR)1;
878 p_waveheader->dwBufferLength = p_aout->output.p_sys->i_buffer_size;
879 p_waveheader->dwFlags = 0;
881 result = waveOutPrepareHeader( h_waveout, p_waveheader, sizeof(WAVEHDR) );
882 if( result != MMSYSERR_NOERROR )
884 msg_Err( p_aout, "waveOutPrepareHeader failed" );
888 /* Send the buffer to the waveOut queue */
889 result = waveOutWrite( h_waveout, p_waveheader, sizeof(WAVEHDR) );
890 if( result != MMSYSERR_NOERROR )
892 msg_Err( p_aout, "waveOutWrite failed" );
899 /*****************************************************************************
900 * WaveOutCallback: what to do once WaveOut has played its sound samples
901 *****************************************************************************/
902 static void CALLBACK WaveOutCallback( HWAVEOUT h_waveout, UINT uMsg,
904 DWORD dwParam1, DWORD dwParam2 )
906 aout_instance_t *p_aout = (aout_instance_t *)_p_aout;
907 int i, i_queued_frames = 0;
909 if( uMsg != WOM_DONE ) return;
911 if( !vlc_object_alive (p_aout) ) return;
913 /* Find out the current latency */
914 for( i = 0; i < FRAMES_NUM; i++ )
916 /* Check if frame buf is available */
917 if( !(p_aout->output.p_sys->waveheader[i].dwFlags & WHDR_DONE) )
923 /* Don't wake up the thread too much */
924 if( i_queued_frames <= FRAMES_NUM/2 )
925 SetEvent( p_aout->output.p_sys->event );
929 /****************************************************************************
930 * WaveOutClearDoneBuffers: Clear all done marked buffers, and free aout_bufer
931 ****************************************************************************
932 * return value is the number of still playing buffers in the queue
933 ****************************************************************************/
934 static int WaveOutClearDoneBuffers(aout_sys_t *p_sys)
936 WAVEHDR *p_waveheader = p_sys->waveheader;
937 int i_queued_frames = 0;
939 for( int i = 0; i < FRAMES_NUM; i++ )
941 if( (p_waveheader[i].dwFlags & WHDR_DONE) &&
942 p_waveheader[i].dwUser )
944 aout_buffer_t *p_buffer =
945 (aout_buffer_t *)(p_waveheader[i].dwUser);
946 /* Unprepare and free the buffers which has just been played */
947 waveOutUnprepareHeader( p_sys->h_waveout, &p_waveheader[i],
950 if( p_waveheader[i].dwUser != 1 )
951 aout_BufferFree( p_buffer );
953 p_waveheader[i].dwUser = 0;
956 /* Check if frame buf is available */
957 if( !(p_waveheader[i].dwFlags & WHDR_DONE) )
962 return i_queued_frames;
965 /*****************************************************************************
966 * WaveOutThread: this thread will capture play notification events.
967 *****************************************************************************
968 * We use this thread to feed new audio samples to the sound card because
969 * we are not authorized to use waveOutWrite() directly in the waveout
971 *****************************************************************************/
972 static void WaveOutThread( notification_thread_t *p_notif )
974 aout_instance_t *p_aout = p_notif->p_aout;
975 aout_sys_t *p_sys = p_aout->output.p_sys;
976 aout_buffer_t *p_buffer = NULL;
977 WAVEHDR *p_waveheader = p_sys->waveheader;
978 int i, i_queued_frames;
981 uint32_t i_buffer_length = 64;
983 /* We don't want any resampling when using S/PDIF */
984 b_sleek = p_aout->output.output.i_format == VLC_FOURCC('s','p','d','i');
986 // wait for first call to "play()"
987 while( !p_sys->start_date && vlc_object_alive (p_aout) )
988 WaitForSingleObject( p_sys->event, INFINITE );
989 if( !vlc_object_alive (p_aout) )
992 msg_Dbg( p_aout, "will start to play in %"PRId64" us",
993 (p_sys->start_date - AOUT_PTS_TOLERANCE/4)-mdate());
995 // than wait a short time... before grabbing first frames
996 mwait( p_sys->start_date - AOUT_PTS_TOLERANCE/4 );
998 #define waveout_warn(msg) msg_Warn( p_aout, "aout_OutputNextBuffer no buffer "\
999 "got next_date=%d ms, "\
1000 "%d frames to play, "\
1001 "starving? %d, %s",(int)(next_date/(mtime_t)1000), \
1003 p_aout->output.b_starving, msg);
1004 next_date = mdate();
1006 while( vlc_object_alive (p_aout) )
1008 /* Cleanup and find out the current latency */
1009 i_queued_frames = WaveOutClearDoneBuffers( p_sys );
1011 if( !vlc_object_alive (p_aout) ) return;
1013 /* Try to fill in as many frame buffers as possible */
1014 for( i = 0; i < FRAMES_NUM; i++ )
1016 /* Check if frame buf is available */
1017 if( p_waveheader[i].dwFlags & WHDR_DONE )
1019 // next_date = mdate() + 1000000 * i_queued_frames /
1020 // p_aout->output.output.i_rate * p_aout->output.i_nb_samples;
1022 // the realtime has got our back-site:) to come in sync
1023 if(next_date < mdate())
1024 next_date = mdate();
1027 /* Take into account the latency */
1028 p_buffer = aout_OutputNextBuffer( p_aout,
1035 msg_Dbg( p_aout, "aout_OutputNextBuffer no buffer "\
1036 "got next_date=%d ms, "\
1037 "%d frames to play, "\
1038 "starving? %d",(int)(next_date/(mtime_t)1000),
1040 p_aout->output.b_starving);
1042 if(p_aout->output.b_starving)
1044 // means we are too early to request a new buffer?
1045 waveout_warn("waiting...")
1046 next_date = aout_FifoFirstDate( p_aout, &p_aout->output.fifo );
1047 mwait( next_date - AOUT_PTS_TOLERANCE/4 );
1048 next_date = mdate();
1049 p_buffer = aout_OutputNextBuffer( p_aout,
1056 if( !p_buffer && i_queued_frames )
1058 /* We aren't late so no need to play a blank sample */
1064 mtime_t buffer_length = (p_buffer->end_date
1065 - p_buffer->start_date);
1066 next_date = next_date + buffer_length;
1067 i_buffer_length = buffer_length/1000;
1070 /* Do the channel reordering */
1071 if( p_buffer && p_sys->b_chan_reorder )
1073 aout_ChannelReorder( p_buffer->p_buffer,
1074 p_buffer->i_nb_bytes,
1075 p_sys->waveformat.Format.nChannels,
1076 p_sys->pi_chan_table,
1077 p_sys->waveformat.Format.wBitsPerSample );
1080 PlayWaveOut( p_aout, p_sys->h_waveout,
1081 &p_waveheader[i], p_buffer, b_sleek );
1087 if( !vlc_object_alive (p_aout) ) return;
1090 deal with the case that the loop didn't fillup the buffer to the
1091 max - instead of waiting that half the buffer is played before
1092 fillup the waveout buffers, wait only for the next sample buffer
1093 to arrive at the play method...
1095 this will also avoid, that the last buffer is play until the
1096 end, and then trying to get more data, so it will also
1097 work - if the next buffer will arrive some ms before the
1098 last buffer is finished.
1100 if(i_queued_frames < FRAMES_NUM)
1101 WaitForSingleObject( p_sys->new_buffer_event, INFINITE );
1103 WaitForSingleObject( p_sys->event, INFINITE );
1110 static int VolumeInfos( aout_instance_t * p_aout, audio_volume_t * pi_soft )
1112 *pi_soft = AOUT_VOLUME_MAX / 2;
1116 static int VolumeGet( aout_instance_t * p_aout, audio_volume_t * pi_volume )
1118 DWORD i_waveout_vol;
1121 waveOutGetVolume( 0, &i_waveout_vol );
1123 waveOutGetVolume( p_aout->output.p_sys->h_waveout, &i_waveout_vol );
1126 i_waveout_vol &= 0xFFFF;
1127 *pi_volume = p_aout->output.i_volume =
1128 (i_waveout_vol * AOUT_VOLUME_MAX + 0xFFFF /*rounding*/) / 2 / 0xFFFF;
1132 static int VolumeSet( aout_instance_t * p_aout, audio_volume_t i_volume )
1134 unsigned long i_waveout_vol = i_volume * 0xFFFF * 2 / AOUT_VOLUME_MAX;
1135 i_waveout_vol |= (i_waveout_vol << 16);
1138 waveOutSetVolume( 0, i_waveout_vol );
1140 waveOutSetVolume( p_aout->output.p_sys->h_waveout, i_waveout_vol );
1143 p_aout->output.i_volume = i_volume;
1149 reload the configuration drop down list, of the Audio Devices
1151 static int ReloadWaveoutDevices( vlc_object_t *p_this, char const *psz_name,
1152 vlc_value_t newval, vlc_value_t oldval, void *data )
1156 module_config_t *p_item = config_FindConfig( p_this, psz_name );
1157 if( !p_item ) return VLC_SUCCESS;
1159 /* Clear-up the current list */
1160 if( p_item->i_list )
1162 /* Keep the first entry */
1163 for( i = 1; i < p_item->i_list; i++ )
1165 free((char *)(p_item->ppsz_list[i]) );
1166 free((char *)(p_item->ppsz_list_text[i]) );
1168 /* TODO: Remove when no more needed */
1169 p_item->ppsz_list[i] = NULL;
1170 p_item->ppsz_list_text[i] = NULL;
1174 int wave_devices = waveOutGetNumDevs();
1177 (char **)realloc( p_item->ppsz_list,
1178 (wave_devices+2) * sizeof(char *) );
1179 p_item->ppsz_list_text =
1180 (char **)realloc( p_item->ppsz_list_text,
1181 (wave_devices+2) * sizeof(char *) );
1184 char sz_dev_name[MAXPNAMELEN+32];
1186 for(int i=0; i<wave_devices; i++)
1188 if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
1189 == MMSYSERR_NOERROR)
1191 sprintf( sz_dev_name, psz_device_name_fmt, caps.szPname,
1195 p_item->ppsz_list[j] = FromLocaleDup( sz_dev_name );
1196 p_item->ppsz_list_text[j] = FromLocaleDup( sz_dev_name );
1202 p_item->ppsz_list[j] = NULL;
1203 p_item->ppsz_list_text[j] = NULL;
1205 /* Signal change to the interface */
1206 p_item->b_dirty = true;
1212 convert devicename to device ID for output
1213 if device not found return WAVE_MAPPER, so let
1214 windows decide which preferred audio device
1217 static uint32_t findDeviceID(char *psz_device_name)
1219 if(!psz_device_name)
1222 uint32_t wave_devices = waveOutGetNumDevs();
1224 char sz_dev_name[MAXPNAMELEN+32];
1225 for(uint32_t i=0; i<wave_devices; i++)
1227 if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
1228 == MMSYSERR_NOERROR)
1230 sprintf(sz_dev_name, psz_device_name_fmt, caps.szPname,
1234 char *psz_temp = FromLocaleDup(sz_dev_name);
1236 if( !stricmp(psz_temp, psz_device_name) )
1238 LocaleFree( psz_temp );
1241 LocaleFree( psz_temp );