1 /*****************************************************************************
2 * waveout.c : Windows waveOut plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2001-2009 the VideoLAN team
7 * Authors: Gildas Bazin <gbazin@videolan.org>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
36 #include <vlc_charset.h> /* FromLocaleDup, LocaleFree */
38 #include "windows_audio_common.h"
40 #define FRAME_SIZE 4096 /* The size is in samples, not in bytes */
42 /*****************************************************************************
44 *****************************************************************************/
45 static int Open ( vlc_object_t * );
46 static void Close ( vlc_object_t * );
47 static void Play ( aout_instance_t * );
49 /*****************************************************************************
50 * notification_thread_t: waveOut event thread
51 *****************************************************************************/
52 typedef struct notification_thread_t
55 aout_instance_t *p_aout;
57 } notification_thread_t;
60 static void Probe ( aout_instance_t * );
61 static int OpenWaveOut ( aout_instance_t *, uint32_t,
62 int, int, int, int, bool );
63 static int OpenWaveOutPCM( aout_instance_t *, uint32_t,
64 vlc_fourcc_t*, int, int, int, bool );
65 static int PlayWaveOut ( aout_instance_t *, HWAVEOUT, WAVEHDR *,
66 aout_buffer_t *, bool );
68 static void CALLBACK WaveOutCallback ( HWAVEOUT, UINT, DWORD, DWORD, DWORD );
69 static void* WaveOutThread( vlc_object_t * );
71 static int VolumeSet( aout_instance_t *, audio_volume_t, bool );
73 static int WaveOutClearDoneBuffers(aout_sys_t *p_sys);
75 static int ReloadWaveoutDevices( vlc_object_t *, char const *,
76 vlc_value_t, vlc_value_t, void * );
77 static uint32_t findDeviceID(char *);
79 static const char psz_device_name_fmt[] = "%s ($%x,$%x)";
81 static const char *const ppsz_adev[] = { "wavemapper", };
82 static const char *const ppsz_adev_text[] = { N_("Microsoft Soundmapper") };
85 /*****************************************************************************
87 *****************************************************************************/
88 #define DEVICE_TEXT N_("Select Audio Device")
89 #define DEVICE_LONG N_("Select special Audio device, or let windows "\
90 "decide (default), change needs VLC restart "\
92 #define DEFAULT_AUDIO_DEVICE N_("Default Audio Device")
95 set_shortname( "WaveOut" )
96 set_description( N_("Win32 waveOut extension output") )
97 set_capability( "audio output", 50 )
98 set_category( CAT_AUDIO )
99 set_subcategory( SUBCAT_AUDIO_AOUT )
100 add_bool( "waveout-float32", true, FLOAT_TEXT, FLOAT_LONGTEXT, true )
102 add_string( "waveout-audio-device", "wavemapper",
103 DEVICE_TEXT, DEVICE_LONG, false )
104 add_deprecated_alias( "waveout-dev" ) /* deprecated since 0.9.3 */
105 change_string_list( ppsz_adev, ppsz_adev_text, ReloadWaveoutDevices )
106 change_need_restart ()
107 change_action_add( ReloadWaveoutDevices, N_("Refresh list") )
109 set_callbacks( Open, Close )
112 /*****************************************************************************
113 * aout_sys_t: waveOut audio output method descriptor
114 *****************************************************************************
115 * This structure is part of the audio output thread descriptor.
116 * It describes the waveOut specific properties of an audio device.
117 *****************************************************************************/
120 uint32_t i_wave_device_id; /* ID of selected output device */
122 HWAVEOUT h_waveout; /* handle to waveout instance */
124 WAVEFORMATEXTENSIBLE waveformat; /* audio format */
126 WAVEHDR waveheader[FRAMES_NUM];
128 notification_thread_t *p_notif; /* WaveOutThread id */
130 HANDLE new_buffer_event;
132 // rental from alsa.c to synchronize startup of audiothread
133 int b_playing; /* playing status */
136 int i_repeat_counter;
140 uint8_t *p_silence_buffer; /* buffer we use to play silence */
142 bool b_chan_reorder; /* do we need channel reordering */
143 int pi_chan_table[AOUT_CHAN_MAX];
146 /*****************************************************************************
147 * Open: open the audio device
148 *****************************************************************************
149 * This function opens and setups Win32 waveOut
150 *****************************************************************************/
151 static int Open( vlc_object_t *p_this )
153 aout_instance_t *p_aout = (aout_instance_t *)p_this;
156 /* Allocate structure */
157 p_aout->output.p_sys = malloc( sizeof( aout_sys_t ) );
159 if( p_aout->output.p_sys == NULL )
162 p_aout->output.pf_play = Play;
163 p_aout->b_die = false;
167 initialize/update Device selection List
169 ReloadWaveoutDevices( p_this, "waveout-audio-device", val, val, NULL);
173 check for configured audio device!
175 char *psz_waveout_dev = var_CreateGetString( p_aout, "waveout-audio-device");
177 p_aout->output.p_sys->i_wave_device_id =
178 findDeviceID( psz_waveout_dev );
180 if(p_aout->output.p_sys->i_wave_device_id == WAVE_MAPPER)
182 if(psz_waveout_dev &&
183 stricmp(psz_waveout_dev,"wavemapper"))
185 msg_Warn( p_aout, "configured audio device '%s' not available, "\
186 "use default instead", psz_waveout_dev );
189 free( psz_waveout_dev );
192 WAVEOUTCAPS waveoutcaps;
193 if(waveOutGetDevCaps( p_aout->output.p_sys->i_wave_device_id,
195 sizeof(WAVEOUTCAPS)) == MMSYSERR_NOERROR)
197 /* log debug some infos about driver, to know who to blame
198 if it doesn't work */
199 msg_Dbg( p_aout, "Drivername: %s", waveoutcaps.szPname);
200 msg_Dbg( p_aout, "Driver Version: %d.%d",
201 (waveoutcaps.vDriverVersion>>8)&255,
202 waveoutcaps.vDriverVersion & 255);
203 msg_Dbg( p_aout, "Manufacturer identifier: 0x%x", waveoutcaps.wMid );
204 msg_Dbg( p_aout, "Product identifier: 0x%x", waveoutcaps.wPid );
209 if( var_Type( p_aout, "audio-device" ) == 0 )
214 if( var_Get( p_aout, "audio-device", &val ) < 0 )
216 /* Probe() has failed. */
217 var_Destroy( p_aout, "waveout-audio-device");
218 free( p_aout->output.p_sys );
223 /* Open the device */
224 if( val.i_int == AOUT_VAR_SPDIF )
226 p_aout->output.output.i_format = VLC_CODEC_SPDIFL;
228 if( OpenWaveOut( p_aout,
229 p_aout->output.p_sys->i_wave_device_id,
231 p_aout->output.output.i_physical_channels,
232 aout_FormatNbChannels( &p_aout->output.output ),
233 p_aout->output.output.i_rate, false )
236 msg_Err( p_aout, "cannot open waveout audio device" );
237 free( p_aout->output.p_sys );
241 /* Calculate the frame size in bytes */
242 p_aout->output.i_nb_samples = A52_FRAME_NB;
243 p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
244 p_aout->output.output.i_frame_length = A52_FRAME_NB;
245 p_aout->output.p_sys->i_buffer_size =
246 p_aout->output.output.i_bytes_per_frame;
248 aout_VolumeNoneInit( p_aout );
257 p_aout->output.output.i_physical_channels
258 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
259 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
263 p_aout->output.output.i_physical_channels
264 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
265 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
268 p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
271 p_aout->output.output.i_physical_channels
272 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
275 if( OpenWaveOutPCM( p_aout,
276 p_aout->output.p_sys->i_wave_device_id,
277 &p_aout->output.output.i_format,
278 p_aout->output.output.i_physical_channels,
279 aout_FormatNbChannels( &p_aout->output.output ),
280 p_aout->output.output.i_rate, false )
283 msg_Err( p_aout, "cannot open waveout audio device" );
284 free( p_aout->output.p_sys );
288 /* Calculate the frame size in bytes */
289 p_aout->output.i_nb_samples = FRAME_SIZE;
290 aout_FormatPrepare( &p_aout->output.output );
291 p_aout->output.p_sys->i_buffer_size = FRAME_SIZE *
292 p_aout->output.output.i_bytes_per_frame;
294 aout_VolumeSoftInit( p_aout );
296 /* Check for hardware volume support */
297 if( waveOutGetDevCaps( (UINT_PTR)p_aout->output.p_sys->h_waveout,
298 &wocaps, sizeof(wocaps) ) == MMSYSERR_NOERROR &&
299 wocaps.dwSupport & WAVECAPS_VOLUME )
302 if( waveOutGetVolume( p_aout->output.p_sys->h_waveout, &i_dummy )
303 == MMSYSERR_NOERROR )
305 p_aout->output.pf_volume_set = VolumeSet;
311 waveOutReset( p_aout->output.p_sys->h_waveout );
313 /* Allocate silence buffer */
314 p_aout->output.p_sys->p_silence_buffer =
315 malloc( p_aout->output.p_sys->i_buffer_size );
316 if( p_aout->output.p_sys->p_silence_buffer == NULL )
318 free( p_aout->output.p_sys );
321 p_aout->output.p_sys->i_repeat_counter = 0;
324 /* Zero the buffer. WinCE doesn't have calloc(). */
325 memset( p_aout->output.p_sys->p_silence_buffer, 0,
326 p_aout->output.p_sys->i_buffer_size );
328 /* Now we need to setup our waveOut play notification structure */
329 p_aout->output.p_sys->p_notif =
330 vlc_object_create( p_aout, sizeof(notification_thread_t) );
331 p_aout->output.p_sys->p_notif->p_aout = p_aout;
332 p_aout->output.p_sys->event = CreateEvent( NULL, FALSE, FALSE, NULL );
333 p_aout->output.p_sys->new_buffer_event = CreateEvent( NULL, FALSE, FALSE, NULL );
335 /* define startpoint of playback on first call to play()
336 like alsa does (instead of playing a blank sample) */
337 p_aout->output.p_sys->b_playing = 0;
338 p_aout->output.p_sys->start_date = 0;
341 /* Then launch the notification thread */
342 if( vlc_thread_create( p_aout->output.p_sys->p_notif,
343 WaveOutThread, VLC_THREAD_PRIORITY_OUTPUT ) )
345 msg_Err( p_aout, "cannot create WaveOutThread" );
348 /* We need to kick off the playback in order to have the callback properly
350 for( int i = 0; i < FRAMES_NUM; i++ )
352 p_aout->output.p_sys->waveheader[i].dwFlags = WHDR_DONE;
353 p_aout->output.p_sys->waveheader[i].dwUser = 0;
359 /*****************************************************************************
360 * Probe: probe the audio device for available formats and channels
361 *****************************************************************************/
362 static void Probe( aout_instance_t * p_aout )
364 vlc_value_t val, text;
365 vlc_fourcc_t i_format;
366 unsigned int i_physical_channels;
368 var_Create( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
369 text.psz_string = _("Audio Device");
370 var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
372 /* Test for 5.1 support */
373 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
374 AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
375 AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE;
376 if( p_aout->output.output.i_physical_channels == i_physical_channels )
378 if( OpenWaveOutPCM( p_aout,
379 p_aout->output.p_sys->i_wave_device_id,
381 i_physical_channels, 6,
382 p_aout->output.output.i_rate, true )
385 val.i_int = AOUT_VAR_5_1;
386 text.psz_string = (char *)_("5.1");
387 var_Change( p_aout, "audio-device",
388 VLC_VAR_ADDCHOICE, &val, &text );
389 msg_Dbg( p_aout, "device supports 5.1 channels" );
393 /* Test for 2 Front 2 Rear support */
394 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
395 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
396 if( ( p_aout->output.output.i_physical_channels & i_physical_channels )
397 == i_physical_channels )
399 if( OpenWaveOutPCM( p_aout,
400 p_aout->output.p_sys->i_wave_device_id,
402 i_physical_channels, 4,
403 p_aout->output.output.i_rate, true )
406 val.i_int = AOUT_VAR_2F2R;
407 text.psz_string = (char *)_("2 Front 2 Rear");
408 var_Change( p_aout, "audio-device",
409 VLC_VAR_ADDCHOICE, &val, &text );
410 msg_Dbg( p_aout, "device supports 4 channels" );
414 /* Test for stereo support */
415 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
416 if( OpenWaveOutPCM( p_aout,
417 p_aout->output.p_sys->i_wave_device_id,
419 i_physical_channels, 2,
420 p_aout->output.output.i_rate, true )
423 val.i_int = AOUT_VAR_STEREO;
424 text.psz_string = (char *)_("Stereo");
425 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
426 msg_Dbg( p_aout, "device supports 2 channels" );
429 /* Test for mono support */
430 i_physical_channels = AOUT_CHAN_CENTER;
431 if( OpenWaveOutPCM( p_aout,
432 p_aout->output.p_sys->i_wave_device_id,
434 i_physical_channels, 1,
435 p_aout->output.output.i_rate, true )
438 val.i_int = AOUT_VAR_MONO;
439 text.psz_string = (char *)_("Mono");
440 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
441 msg_Dbg( p_aout, "device supports 1 channel" );
444 /* Test for SPDIF support */
445 if ( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
447 if( OpenWaveOut( p_aout,
448 p_aout->output.p_sys->i_wave_device_id,
450 p_aout->output.output.i_physical_channels,
451 aout_FormatNbChannels( &p_aout->output.output ),
452 p_aout->output.output.i_rate, true )
455 msg_Dbg( p_aout, "device supports A/52 over S/PDIF" );
456 val.i_int = AOUT_VAR_SPDIF;
457 text.psz_string = (char *)_("A/52 over S/PDIF");
458 var_Change( p_aout, "audio-device",
459 VLC_VAR_ADDCHOICE, &val, &text );
460 if( var_InheritBool( p_aout, "spdif" ) )
461 var_Set( p_aout, "audio-device", val );
465 var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
468 /* Probe() has failed. */
469 var_Destroy( p_aout, "audio-device" );
473 var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
474 var_TriggerCallback( p_aout, "intf-change" );
477 /*****************************************************************************
478 * Play: play a sound buffer
479 *****************************************************************************
480 * This doesn't actually play the buffer. This just stores the buffer so it
481 * can be played by the callback thread.
482 *****************************************************************************/
483 static void Play( aout_instance_t *_p_aout )
485 if( !_p_aout->output.p_sys->b_playing )
487 _p_aout->output.p_sys->b_playing = 1;
489 /* get the playing date of the first aout buffer */
490 _p_aout->output.p_sys->start_date =
491 aout_FifoFirstDate( _p_aout, &_p_aout->output.fifo );
493 msg_Dbg( _p_aout, "Wakeup sleeping output thread.");
495 /* wake up the audio output thread */
496 SetEvent( _p_aout->output.p_sys->event );
498 SetEvent( _p_aout->output.p_sys->new_buffer_event );
502 /*****************************************************************************
503 * Close: close the audio device
504 *****************************************************************************/
505 static void Close( vlc_object_t *p_this )
507 aout_instance_t *p_aout = (aout_instance_t *)p_this;
508 aout_sys_t *p_sys = p_aout->output.p_sys;
510 /* Before calling waveOutClose we must reset the device */
511 vlc_object_kill( p_aout );
513 /* wake up the audio thread, to recognize that p_aout died */
514 SetEvent( p_sys->event );
515 SetEvent( p_sys->new_buffer_event );
517 vlc_thread_join( p_sys->p_notif );
518 vlc_object_release( p_sys->p_notif );
521 kill the real output then - when the feed thread
522 is surely terminated!
523 old code could be too early in case that "feeding"
524 was running on termination
526 at this point now its sure, that there will be no new
527 data send to the driver, and we can cancel the last
530 MMRESULT result = waveOutReset( p_sys->h_waveout );
531 if(result != MMSYSERR_NOERROR)
533 msg_Err( p_aout, "waveOutReset failed 0x%x", result );
535 now we must wait, that all buffers are played
536 because cancel doesn't work in this case...
538 if(result == MMSYSERR_NOTSUPPORTED)
541 clear currently played (done) buffers,
542 if returnvalue > 0 (means some buffer still playing)
543 wait for the driver event callback that one buffer
544 is finished with playing, and check again
545 the timeout of 5000ms is just, an emergency exit
546 of this loop, to avoid deadlock in case of other
547 (currently not known bugs, problems, errors cases?)
550 (WaveOutClearDoneBuffers( p_sys ) > 0)
552 (WaitForSingleObject( p_sys->event, 5000) == WAIT_OBJECT_0)
555 msg_Dbg( p_aout, "Wait for waveout device...");
559 WaveOutClearDoneBuffers( p_sys );
562 /* now we can Close the device */
563 if( waveOutClose( p_sys->h_waveout ) != MMSYSERR_NOERROR )
565 msg_Err( p_aout, "waveOutClose failed" );
569 because so long, the waveout device is playing, the callback
570 could occur and need the events
572 CloseHandle( p_sys->event );
573 CloseHandle( p_sys->new_buffer_event);
575 free( p_sys->p_silence_buffer );
579 /*****************************************************************************
580 * OpenWaveOut: open the waveout sound device
581 ****************************************************************************/
582 static int OpenWaveOut( aout_instance_t *p_aout, uint32_t i_device_id, int i_format,
583 int i_channels, int i_nb_channels, int i_rate,
588 /* Set sound format */
590 #define waveformat p_aout->output.p_sys->waveformat
592 waveformat.dwChannelMask = 0;
593 for( unsigned i = 0; i < sizeof(pi_channels_src)/sizeof(uint32_t); i++ )
595 if( i_channels & pi_channels_src[i] )
596 waveformat.dwChannelMask |= pi_channels_in[i];
601 case VLC_CODEC_SPDIFL:
603 /* To prevent channel re-ordering */
604 waveformat.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
605 waveformat.Format.wBitsPerSample = 16;
606 waveformat.Samples.wValidBitsPerSample =
607 waveformat.Format.wBitsPerSample;
608 waveformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
609 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF;
613 waveformat.Format.wBitsPerSample = sizeof(float) * 8;
614 waveformat.Samples.wValidBitsPerSample =
615 waveformat.Format.wBitsPerSample;
616 waveformat.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
617 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
621 waveformat.Format.wBitsPerSample = 16;
622 waveformat.Samples.wValidBitsPerSample =
623 waveformat.Format.wBitsPerSample;
624 waveformat.Format.wFormatTag = WAVE_FORMAT_PCM;
625 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_PCM;
629 waveformat.Format.nChannels = i_nb_channels;
630 waveformat.Format.nSamplesPerSec = i_rate;
631 waveformat.Format.nBlockAlign =
632 waveformat.Format.wBitsPerSample / 8 * i_nb_channels;
633 waveformat.Format.nAvgBytesPerSec =
634 waveformat.Format.nSamplesPerSec * waveformat.Format.nBlockAlign;
636 /* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */
637 if( i_nb_channels <= 2 )
639 waveformat.Format.cbSize = 0;
643 waveformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
644 waveformat.Format.cbSize =
645 sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
649 msg_Dbg( p_aout, "OpenWaveDevice-ID: %u", i_device_id);
650 msg_Dbg( p_aout,"waveformat.Format.cbSize = %d",
651 waveformat.Format.cbSize);
652 msg_Dbg( p_aout,"waveformat.Format.wFormatTag = %u",
653 waveformat.Format.wFormatTag);
654 msg_Dbg( p_aout,"waveformat.Format.nChannels = %u",
655 waveformat.Format.nChannels);
656 msg_Dbg( p_aout,"waveformat.Format.nSamplesPerSec = %d",
657 (int)waveformat.Format.nSamplesPerSec);
658 msg_Dbg( p_aout,"waveformat.Format.nAvgBytesPerSec = %u",
659 (int)waveformat.Format.nAvgBytesPerSec);
660 msg_Dbg( p_aout,"waveformat.Format.nBlockAlign = %d",
661 waveformat.Format.nBlockAlign);
662 msg_Dbg( p_aout,"waveformat.Format.wBitsPerSample = %d",
663 waveformat.Format.wBitsPerSample);
664 msg_Dbg( p_aout,"waveformat.Samples.wValidBitsPerSample = %d",
665 waveformat.Samples.wValidBitsPerSample);
666 msg_Dbg( p_aout,"waveformat.Samples.wSamplesPerBlock = %d",
667 waveformat.Samples.wSamplesPerBlock);
668 msg_Dbg( p_aout,"waveformat.dwChannelMask = %lu",
669 waveformat.dwChannelMask);
672 /* Open the device */
673 result = waveOutOpen( &p_aout->output.p_sys->h_waveout, i_device_id,
674 (WAVEFORMATEX *)&waveformat,
675 (DWORD_PTR)WaveOutCallback, (DWORD_PTR)p_aout,
676 CALLBACK_FUNCTION | (b_probe?WAVE_FORMAT_QUERY:0) );
677 if( result == WAVERR_BADFORMAT )
679 msg_Warn( p_aout, "waveOutOpen failed WAVERR_BADFORMAT" );
682 if( result == MMSYSERR_ALLOCATED )
684 msg_Warn( p_aout, "waveOutOpen failed WAVERR_ALLOCATED" );
687 if( result != MMSYSERR_NOERROR )
689 msg_Warn( p_aout, "waveOutOpen failed" );
693 p_aout->output.p_sys->b_chan_reorder =
694 aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
695 waveformat.dwChannelMask, i_nb_channels,
696 p_aout->output.p_sys->pi_chan_table );
698 if( p_aout->output.p_sys->b_chan_reorder )
700 msg_Dbg( p_aout, "channel reordering needed" );
709 /*****************************************************************************
710 * OpenWaveOutPCM: open a PCM waveout sound device
711 ****************************************************************************/
712 static int OpenWaveOutPCM( aout_instance_t *p_aout, uint32_t i_device_id,
713 vlc_fourcc_t *i_format,
714 int i_channels, int i_nb_channels, int i_rate,
717 bool b_use_float32 = var_CreateGetBool( p_aout, "waveout-float32");
719 if( !b_use_float32 || OpenWaveOut( p_aout, i_device_id, VLC_CODEC_FL32,
720 i_channels, i_nb_channels, i_rate, b_probe )
723 if ( OpenWaveOut( p_aout, i_device_id, VLC_CODEC_S16L,
724 i_channels, i_nb_channels, i_rate, b_probe )
731 *i_format = VLC_CODEC_S16L;
737 *i_format = VLC_CODEC_FL32;
742 /*****************************************************************************
743 * PlayWaveOut: play a buffer through the WaveOut device
744 *****************************************************************************/
745 static int PlayWaveOut( aout_instance_t *p_aout, HWAVEOUT h_waveout,
746 WAVEHDR *p_waveheader, aout_buffer_t *p_buffer,
751 /* Prepare the buffer */
752 if( p_buffer != NULL )
754 p_waveheader->lpData = (LPSTR)p_buffer->p_buffer;
756 copy the buffer to the silence buffer :) so in case we don't
757 get the next buffer fast enough (I will repeat this one a time
758 for AC3 / DTS and SPDIF this will sound better instead of
763 vlc_memcpy( p_aout->output.p_sys->p_silence_buffer,
765 p_aout->output.p_sys->i_buffer_size );
766 p_aout->output.p_sys->i_repeat_counter = 2;
769 /* Use silence buffer instead */
770 if(p_aout->output.p_sys->i_repeat_counter)
772 p_aout->output.p_sys->i_repeat_counter--;
773 if(!p_aout->output.p_sys->i_repeat_counter)
775 vlc_memset( p_aout->output.p_sys->p_silence_buffer,
776 0x00, p_aout->output.p_sys->i_buffer_size );
779 p_waveheader->lpData = (LPSTR)p_aout->output.p_sys->p_silence_buffer;
782 p_waveheader->dwUser = p_buffer ? (DWORD_PTR)p_buffer : (DWORD_PTR)1;
783 p_waveheader->dwBufferLength = p_aout->output.p_sys->i_buffer_size;
784 p_waveheader->dwFlags = 0;
786 result = waveOutPrepareHeader( h_waveout, p_waveheader, sizeof(WAVEHDR) );
787 if( result != MMSYSERR_NOERROR )
789 msg_Err( p_aout, "waveOutPrepareHeader failed" );
793 /* Send the buffer to the waveOut queue */
794 result = waveOutWrite( h_waveout, p_waveheader, sizeof(WAVEHDR) );
795 if( result != MMSYSERR_NOERROR )
797 msg_Err( p_aout, "waveOutWrite failed" );
804 /*****************************************************************************
805 * WaveOutCallback: what to do once WaveOut has played its sound samples
806 *****************************************************************************/
807 static void CALLBACK WaveOutCallback( HWAVEOUT h_waveout, UINT uMsg,
809 DWORD dwParam1, DWORD dwParam2 )
811 (void)h_waveout; (void)dwParam1; (void)dwParam2;
812 aout_instance_t *p_aout = (aout_instance_t *)_p_aout;
813 int i_queued_frames = 0;
815 if( uMsg != WOM_DONE ) return;
817 if( !vlc_object_alive (p_aout) ) return;
819 /* Find out the current latency */
820 for( int i = 0; i < FRAMES_NUM; i++ )
822 /* Check if frame buf is available */
823 if( !(p_aout->output.p_sys->waveheader[i].dwFlags & WHDR_DONE) )
829 /* Don't wake up the thread too much */
830 if( i_queued_frames <= FRAMES_NUM/2 )
831 SetEvent( p_aout->output.p_sys->event );
835 /****************************************************************************
836 * WaveOutClearDoneBuffers: Clear all done marked buffers, and free aout_bufer
837 ****************************************************************************
838 * return value is the number of still playing buffers in the queue
839 ****************************************************************************/
840 static int WaveOutClearDoneBuffers(aout_sys_t *p_sys)
842 WAVEHDR *p_waveheader = p_sys->waveheader;
843 int i_queued_frames = 0;
845 for( int i = 0; i < FRAMES_NUM; i++ )
847 if( (p_waveheader[i].dwFlags & WHDR_DONE) &&
848 p_waveheader[i].dwUser )
850 aout_buffer_t *p_buffer =
851 (aout_buffer_t *)(p_waveheader[i].dwUser);
852 /* Unprepare and free the buffers which has just been played */
853 waveOutUnprepareHeader( p_sys->h_waveout, &p_waveheader[i],
856 if( p_waveheader[i].dwUser != 1 )
857 aout_BufferFree( p_buffer );
859 p_waveheader[i].dwUser = 0;
862 /* Check if frame buf is available */
863 if( !(p_waveheader[i].dwFlags & WHDR_DONE) )
868 return i_queued_frames;
871 /*****************************************************************************
872 * WaveOutThread: this thread will capture play notification events.
873 *****************************************************************************
874 * We use this thread to feed new audio samples to the sound card because
875 * we are not authorized to use waveOutWrite() directly in the waveout
877 *****************************************************************************/
878 static void* WaveOutThread( vlc_object_t *p_this )
880 notification_thread_t *p_notif = (notification_thread_t*)p_this;
881 aout_instance_t *p_aout = p_notif->p_aout;
882 aout_sys_t *p_sys = p_aout->output.p_sys;
883 aout_buffer_t *p_buffer = NULL;
884 WAVEHDR *p_waveheader = p_sys->waveheader;
885 int i, i_queued_frames;
888 uint32_t i_buffer_length = 64;
889 int canc = vlc_savecancel ();
891 /* We don't want any resampling when using S/PDIF */
892 b_sleek = p_aout->output.output.i_format == VLC_CODEC_SPDIFL;
894 // wait for first call to "play()"
895 while( !p_sys->start_date && vlc_object_alive (p_aout) )
896 WaitForSingleObject( p_sys->event, INFINITE );
897 if( !vlc_object_alive (p_aout) )
900 msg_Dbg( p_aout, "will start to play in %"PRId64" us",
901 (p_sys->start_date - AOUT_PTS_TOLERANCE/4)-mdate());
903 // than wait a short time... before grabbing first frames
904 mwait( p_sys->start_date - AOUT_PTS_TOLERANCE/4 );
906 #define waveout_warn(msg) msg_Warn( p_aout, "aout_OutputNextBuffer no buffer "\
907 "got next_date=%d ms, "\
908 "%d frames to play, "\
909 "starving? %d, %s",(int)(next_date/(mtime_t)1000), \
911 p_aout->output.b_starving, msg);
914 while( vlc_object_alive (p_aout) )
916 /* Cleanup and find out the current latency */
917 i_queued_frames = WaveOutClearDoneBuffers( p_sys );
919 if( !vlc_object_alive (p_aout) ) return NULL;
921 /* Try to fill in as many frame buffers as possible */
922 for( i = 0; i < FRAMES_NUM; i++ )
924 /* Check if frame buf is available */
925 if( p_waveheader[i].dwFlags & WHDR_DONE )
927 // next_date = mdate() + 1000000 * i_queued_frames /
928 // p_aout->output.output.i_rate * p_aout->output.i_nb_samples;
930 // the realtime has got our back-site:) to come in sync
931 if(next_date < mdate())
935 /* Take into account the latency */
936 p_buffer = aout_OutputNextBuffer( p_aout,
943 msg_Dbg( p_aout, "aout_OutputNextBuffer no buffer "\
944 "got next_date=%d ms, "\
945 "%d frames to play, "\
946 "starving? %d",(int)(next_date/(mtime_t)1000),
948 p_aout->output.b_starving);
950 if(p_aout->output.b_starving)
952 // means we are too early to request a new buffer?
953 waveout_warn("waiting...")
954 next_date = aout_FifoFirstDate( p_aout, &p_aout->output.fifo );
955 mwait( next_date - AOUT_PTS_TOLERANCE/4 );
957 p_buffer = aout_OutputNextBuffer( p_aout,
964 if( !p_buffer && i_queued_frames )
966 /* We aren't late so no need to play a blank sample */
972 mtime_t buffer_length = p_buffer->i_length;
973 next_date = next_date + buffer_length;
974 i_buffer_length = buffer_length/1000;
977 /* Do the channel reordering */
978 if( p_buffer && p_sys->b_chan_reorder )
980 aout_ChannelReorder( p_buffer->p_buffer,
982 p_sys->waveformat.Format.nChannels,
983 p_sys->pi_chan_table,
984 p_sys->waveformat.Format.wBitsPerSample );
987 PlayWaveOut( p_aout, p_sys->h_waveout,
988 &p_waveheader[i], p_buffer, b_sleek );
994 if( !vlc_object_alive (p_aout) ) return NULL;
997 deal with the case that the loop didn't fillup the buffer to the
998 max - instead of waiting that half the buffer is played before
999 fillup the waveout buffers, wait only for the next sample buffer
1000 to arrive at the play method...
1002 this will also avoid, that the last buffer is play until the
1003 end, and then trying to get more data, so it will also
1004 work - if the next buffer will arrive some ms before the
1005 last buffer is finished.
1007 if(i_queued_frames < FRAMES_NUM)
1008 WaitForSingleObject( p_sys->new_buffer_event, INFINITE );
1010 WaitForSingleObject( p_sys->event, INFINITE );
1015 vlc_restorecancel (canc);
1019 static int VolumeSet( aout_instance_t * p_aout, audio_volume_t i_volume,
1023 i_volume = AOUT_VOLUME_MIN;
1025 unsigned long i_waveout_vol = i_volume * 0xFFFF * 2 / AOUT_VOLUME_MAX;
1026 i_waveout_vol |= (i_waveout_vol << 16);
1029 waveOutSetVolume( 0, i_waveout_vol );
1031 waveOutSetVolume( p_aout->output.p_sys->h_waveout, i_waveout_vol );
1038 reload the configuration drop down list, of the Audio Devices
1040 static int ReloadWaveoutDevices( vlc_object_t *p_this, char const *psz_name,
1041 vlc_value_t newval, vlc_value_t oldval, void *data )
1043 VLC_UNUSED( newval ); VLC_UNUSED( oldval ); VLC_UNUSED( data );
1045 module_config_t *p_item = config_FindConfig( p_this, psz_name );
1046 if( !p_item ) return VLC_SUCCESS;
1048 /* Clear-up the current list */
1049 if( p_item->i_list )
1053 /* Keep the first entry */
1054 for( i = 1; i < p_item->i_list; i++ )
1056 free((char *)(p_item->ppsz_list[i]) );
1057 free((char *)(p_item->ppsz_list_text[i]) );
1059 /* TODO: Remove when no more needed */
1060 p_item->ppsz_list[i] = NULL;
1061 p_item->ppsz_list_text[i] = NULL;
1065 int wave_devices = waveOutGetNumDevs();
1067 p_item->ppsz_list = xrealloc( p_item->ppsz_list,
1068 (wave_devices+2) * sizeof(char *) );
1069 p_item->ppsz_list_text = xrealloc( p_item->ppsz_list_text,
1070 (wave_devices+2) * sizeof(char *) );
1073 char sz_dev_name[MAXPNAMELEN+32];
1075 for(int i=0; i<wave_devices; i++)
1077 if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
1078 == MMSYSERR_NOERROR)
1080 sprintf( sz_dev_name, psz_device_name_fmt, caps.szPname,
1084 p_item->ppsz_list[j] = FromLocaleDup( sz_dev_name );
1085 p_item->ppsz_list_text[j] = FromLocaleDup( sz_dev_name );
1091 p_item->ppsz_list[j] = NULL;
1092 p_item->ppsz_list_text[j] = NULL;
1094 /* Signal change to the interface */
1095 p_item->b_dirty = true;
1101 convert devicename to device ID for output
1102 if device not found return WAVE_MAPPER, so let
1103 windows decide which preferred audio device
1106 static uint32_t findDeviceID(char *psz_device_name)
1108 if( !psz_device_name )
1111 uint32_t wave_devices = waveOutGetNumDevs();
1113 char sz_dev_name[MAXPNAMELEN+32];
1115 for( uint32_t i = 0; i < wave_devices; i++ )
1117 if( waveOutGetDevCaps( i, &caps, sizeof(WAVEOUTCAPS) )
1118 == MMSYSERR_NOERROR)
1120 sprintf( sz_dev_name, psz_device_name_fmt, caps.szPname,
1124 char *psz_temp = FromLocaleDup(sz_dev_name);
1126 if( !stricmp(psz_temp, psz_device_name) )
1128 LocaleFree( psz_temp );
1131 LocaleFree( psz_temp );