1 /*****************************************************************************
2 * waveout.c : Windows waveOut plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2001-2009 the VideoLAN team
7 * Authors: Gildas Bazin <gbazin@videolan.org>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
36 #include <vlc_charset.h>
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 VolumeGet( aout_instance_t *, audio_volume_t * );
72 static int VolumeSet( aout_instance_t *, audio_volume_t );
74 static int WaveOutClearDoneBuffers(aout_sys_t *p_sys);
76 static int ReloadWaveoutDevices( vlc_object_t *, char const *,
77 vlc_value_t, vlc_value_t, void * );
78 static uint32_t findDeviceID(char *);
80 static const char psz_device_name_fmt[] = "%s ($%x,$%x)";
82 static const char *const ppsz_adev[] = { "wavemapper", };
83 static const char *const ppsz_adev_text[] = { N_("Microsoft Soundmapper") };
87 /*****************************************************************************
89 *****************************************************************************/
90 #define DEVICE_TEXT N_("Select Audio Device")
91 #define DEVICE_LONG N_("Select special Audio device, or let windows "\
92 "decide (default), change needs VLC restart "\
94 #define DEFAULT_AUDIO_DEVICE N_("Default Audio Device")
97 set_shortname( "WaveOut" )
98 set_description( N_("Win32 waveOut extension output") )
99 set_capability( "audio output", 50 )
100 set_category( CAT_AUDIO )
101 set_subcategory( SUBCAT_AUDIO_AOUT )
102 add_bool( "waveout-float32", true, NULL, FLOAT_TEXT, FLOAT_LONGTEXT, true )
104 add_string( "waveout-audio-device", "wavemapper", NULL,
105 DEVICE_TEXT, DEVICE_LONG, false )
106 add_deprecated_alias( "waveout-dev" ) /* deprecated since 0.9.3 */
107 change_string_list( ppsz_adev, ppsz_adev_text, ReloadWaveoutDevices )
108 change_need_restart ()
109 change_action_add( ReloadWaveoutDevices, N_("Refresh list") )
112 set_callbacks( Open, Close )
115 /*****************************************************************************
116 * aout_sys_t: waveOut audio output method descriptor
117 *****************************************************************************
118 * This structure is part of the audio output thread descriptor.
119 * It describes the waveOut specific properties of an audio device.
120 *****************************************************************************/
123 uint32_t i_wave_device_id; /* ID of selected output device */
125 HWAVEOUT h_waveout; /* handle to waveout instance */
127 WAVEFORMATEXTENSIBLE waveformat; /* audio format */
129 WAVEHDR waveheader[FRAMES_NUM];
131 notification_thread_t *p_notif; /* WaveOutThread id */
133 HANDLE new_buffer_event;
135 // rental from alsa.c to synchronize startup of audiothread
136 int b_playing; /* playing status */
139 int i_repeat_counter;
143 uint8_t *p_silence_buffer; /* buffer we use to play silence */
145 bool b_chan_reorder; /* do we need channel reordering */
146 int pi_chan_table[AOUT_CHAN_MAX];
149 /*****************************************************************************
150 * Open: open the audio device
151 *****************************************************************************
152 * This function opens and setups Win32 waveOut
153 *****************************************************************************/
154 static int Open( vlc_object_t *p_this )
156 aout_instance_t *p_aout = (aout_instance_t *)p_this;
160 /* Allocate structure */
161 p_aout->output.p_sys = malloc( sizeof( aout_sys_t ) );
163 if( p_aout->output.p_sys == NULL )
166 p_aout->output.pf_play = Play;
167 p_aout->b_die = false;
171 initialize/update Device selection List
173 ReloadWaveoutDevices( p_this, "waveout-audio-device", val, val, NULL);
177 check for configured audio device!
179 char *psz_waveout_dev = var_CreateGetString( p_aout, "waveout-audio-device");
181 p_aout->output.p_sys->i_wave_device_id =
182 findDeviceID( psz_waveout_dev );
184 if(p_aout->output.p_sys->i_wave_device_id == WAVE_MAPPER)
186 if(psz_waveout_dev &&
187 stricmp(psz_waveout_dev,"wavemapper"))
189 msg_Warn( p_aout, "configured audio device '%s' not available, "\
190 "use default instead", psz_waveout_dev );
193 free( psz_waveout_dev );
196 WAVEOUTCAPS waveoutcaps;
197 if(waveOutGetDevCaps( p_aout->output.p_sys->i_wave_device_id,
199 sizeof(WAVEOUTCAPS)) == MMSYSERR_NOERROR)
201 /* log debug some infos about driver, to know who to blame
202 if it doesn't work */
203 msg_Dbg( p_aout, "Drivername: %s", waveoutcaps.szPname);
204 msg_Dbg( p_aout, "Driver Version: %d.%d",
205 (waveoutcaps.vDriverVersion>>8)&255,
206 waveoutcaps.vDriverVersion & 255);
207 msg_Dbg( p_aout, "Manufacturer identifier: 0x%x", waveoutcaps.wMid );
208 msg_Dbg( p_aout, "Product identifier: 0x%x", waveoutcaps.wPid );
213 if( var_Type( p_aout, "audio-device" ) == 0 )
218 if( var_Get( p_aout, "audio-device", &val ) < 0 )
220 /* Probe() has failed. */
221 var_Destroy( p_aout, "waveout-audio-device");
222 free( p_aout->output.p_sys );
227 /* Open the device */
228 if( val.i_int == AOUT_VAR_SPDIF )
230 p_aout->output.output.i_format = VLC_CODEC_SPDIFL;
232 if( OpenWaveOut( p_aout,
233 p_aout->output.p_sys->i_wave_device_id,
235 p_aout->output.output.i_physical_channels,
236 aout_FormatNbChannels( &p_aout->output.output ),
237 p_aout->output.output.i_rate, false )
240 msg_Err( p_aout, "cannot open waveout audio device" );
241 free( p_aout->output.p_sys );
245 /* Calculate the frame size in bytes */
246 p_aout->output.i_nb_samples = A52_FRAME_NB;
247 p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
248 p_aout->output.output.i_frame_length = A52_FRAME_NB;
249 p_aout->output.p_sys->i_buffer_size =
250 p_aout->output.output.i_bytes_per_frame;
252 aout_VolumeNoneInit( p_aout );
261 p_aout->output.output.i_physical_channels
262 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
263 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
267 p_aout->output.output.i_physical_channels
268 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
269 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
272 p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
275 p_aout->output.output.i_physical_channels
276 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
279 if( OpenWaveOutPCM( p_aout,
280 p_aout->output.p_sys->i_wave_device_id,
281 &p_aout->output.output.i_format,
282 p_aout->output.output.i_physical_channels,
283 aout_FormatNbChannels( &p_aout->output.output ),
284 p_aout->output.output.i_rate, false )
287 msg_Err( p_aout, "cannot open waveout audio device" );
288 free( p_aout->output.p_sys );
292 /* Calculate the frame size in bytes */
293 p_aout->output.i_nb_samples = FRAME_SIZE;
294 aout_FormatPrepare( &p_aout->output.output );
295 p_aout->output.p_sys->i_buffer_size = FRAME_SIZE *
296 p_aout->output.output.i_bytes_per_frame;
298 aout_VolumeSoftInit( p_aout );
300 /* Check for hardware volume support */
301 if( waveOutGetDevCaps( (UINT_PTR)p_aout->output.p_sys->h_waveout,
302 &wocaps, sizeof(wocaps) ) == MMSYSERR_NOERROR &&
303 wocaps.dwSupport & WAVECAPS_VOLUME )
306 if( waveOutGetVolume( p_aout->output.p_sys->h_waveout, &i_dummy )
307 == MMSYSERR_NOERROR )
309 p_aout->output.pf_volume_get = VolumeGet;
310 p_aout->output.pf_volume_set = VolumeSet;
316 waveOutReset( p_aout->output.p_sys->h_waveout );
318 /* Allocate silence buffer */
319 p_aout->output.p_sys->p_silence_buffer =
320 malloc( p_aout->output.p_sys->i_buffer_size );
321 if( p_aout->output.p_sys->p_silence_buffer == NULL )
323 free( p_aout->output.p_sys );
326 p_aout->output.p_sys->i_repeat_counter = 0;
329 /* Zero the buffer. WinCE doesn't have calloc(). */
330 memset( p_aout->output.p_sys->p_silence_buffer, 0,
331 p_aout->output.p_sys->i_buffer_size );
333 /* Now we need to setup our waveOut play notification structure */
334 p_aout->output.p_sys->p_notif =
335 vlc_object_create( p_aout, sizeof(notification_thread_t) );
336 p_aout->output.p_sys->p_notif->p_aout = p_aout;
337 p_aout->output.p_sys->event = CreateEvent( NULL, FALSE, FALSE, NULL );
338 p_aout->output.p_sys->new_buffer_event = CreateEvent( NULL, FALSE, FALSE, NULL );
340 /* define startpoint of playback on first call to play()
341 like alsa does (instead of playing a blank sample) */
342 p_aout->output.p_sys->b_playing = 0;
343 p_aout->output.p_sys->start_date = 0;
346 /* Then launch the notification thread */
347 if( vlc_thread_create( p_aout->output.p_sys->p_notif,
348 "waveOut Notification Thread", WaveOutThread,
349 VLC_THREAD_PRIORITY_OUTPUT ) )
351 msg_Err( p_aout, "cannot create WaveOutThread" );
354 /* We need to kick off the playback in order to have the callback properly
356 for( i = 0; i < FRAMES_NUM; i++ )
358 p_aout->output.p_sys->waveheader[i].dwFlags = WHDR_DONE;
359 p_aout->output.p_sys->waveheader[i].dwUser = 0;
365 /*****************************************************************************
366 * Probe: probe the audio device for available formats and channels
367 *****************************************************************************/
368 static void Probe( aout_instance_t * p_aout )
370 vlc_value_t val, text;
371 vlc_fourcc_t i_format;
372 unsigned int i_physical_channels;
374 var_Create( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
375 text.psz_string = _("Audio Device");
376 var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
378 /* Test for 5.1 support */
379 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
380 AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
381 AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE;
382 if( p_aout->output.output.i_physical_channels == i_physical_channels )
384 if( OpenWaveOutPCM( p_aout,
385 p_aout->output.p_sys->i_wave_device_id,
387 i_physical_channels, 6,
388 p_aout->output.output.i_rate, true )
391 val.i_int = AOUT_VAR_5_1;
392 text.psz_string = (char *)_("5.1");
393 var_Change( p_aout, "audio-device",
394 VLC_VAR_ADDCHOICE, &val, &text );
395 msg_Dbg( p_aout, "device supports 5.1 channels" );
399 /* Test for 2 Front 2 Rear support */
400 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
401 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
402 if( ( p_aout->output.output.i_physical_channels & i_physical_channels )
403 == i_physical_channels )
405 if( OpenWaveOutPCM( p_aout,
406 p_aout->output.p_sys->i_wave_device_id,
408 i_physical_channels, 4,
409 p_aout->output.output.i_rate, true )
412 val.i_int = AOUT_VAR_2F2R;
413 text.psz_string = (char *)_("2 Front 2 Rear");
414 var_Change( p_aout, "audio-device",
415 VLC_VAR_ADDCHOICE, &val, &text );
416 msg_Dbg( p_aout, "device supports 4 channels" );
420 /* Test for stereo support */
421 i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
422 if( OpenWaveOutPCM( p_aout,
423 p_aout->output.p_sys->i_wave_device_id,
425 i_physical_channels, 2,
426 p_aout->output.output.i_rate, true )
429 val.i_int = AOUT_VAR_STEREO;
430 text.psz_string = (char *)_("Stereo");
431 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
432 msg_Dbg( p_aout, "device supports 2 channels" );
435 /* Test for mono support */
436 i_physical_channels = AOUT_CHAN_CENTER;
437 if( OpenWaveOutPCM( p_aout,
438 p_aout->output.p_sys->i_wave_device_id,
440 i_physical_channels, 1,
441 p_aout->output.output.i_rate, true )
444 val.i_int = AOUT_VAR_MONO;
445 text.psz_string = (char *)_("Mono");
446 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
447 msg_Dbg( p_aout, "device supports 1 channel" );
450 /* Test for SPDIF support */
451 if ( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
453 if( OpenWaveOut( p_aout,
454 p_aout->output.p_sys->i_wave_device_id,
456 p_aout->output.output.i_physical_channels,
457 aout_FormatNbChannels( &p_aout->output.output ),
458 p_aout->output.output.i_rate, true )
461 msg_Dbg( p_aout, "device supports A/52 over S/PDIF" );
462 val.i_int = AOUT_VAR_SPDIF;
463 text.psz_string = (char *)_("A/52 over S/PDIF");
464 var_Change( p_aout, "audio-device",
465 VLC_VAR_ADDCHOICE, &val, &text );
466 if( config_GetInt( p_aout, "spdif" ) )
467 var_Set( p_aout, "audio-device", val );
471 var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
474 /* Probe() has failed. */
475 var_Destroy( p_aout, "audio-device" );
479 var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
480 var_SetBool( p_aout, "intf-change", true );
483 /*****************************************************************************
484 * Play: play a sound buffer
485 *****************************************************************************
486 * This doesn't actually play the buffer. This just stores the buffer so it
487 * can be played by the callback thread.
488 *****************************************************************************/
489 static void Play( aout_instance_t *_p_aout )
491 if( !_p_aout->output.p_sys->b_playing )
493 _p_aout->output.p_sys->b_playing = 1;
495 /* get the playing date of the first aout buffer */
496 _p_aout->output.p_sys->start_date =
497 aout_FifoFirstDate( _p_aout, &_p_aout->output.fifo );
499 msg_Dbg( _p_aout, "Wakeup sleeping output thread.");
501 /* wake up the audio output thread */
502 SetEvent( _p_aout->output.p_sys->event );
504 SetEvent( _p_aout->output.p_sys->new_buffer_event );
508 /*****************************************************************************
509 * Close: close the audio device
510 *****************************************************************************/
511 static void Close( vlc_object_t *p_this )
513 aout_instance_t *p_aout = (aout_instance_t *)p_this;
514 aout_sys_t *p_sys = p_aout->output.p_sys;
516 /* Before calling waveOutClose we must reset the device */
517 vlc_object_kill( p_aout );
519 /* wake up the audio thread, to recognize that p_aout died */
520 SetEvent( p_sys->event );
521 SetEvent( p_sys->new_buffer_event );
523 vlc_thread_join( p_sys->p_notif );
524 vlc_object_release( p_sys->p_notif );
527 kill the real output then - when the feed thread
528 is surely terminated!
529 old code could be too early in case that "feeding"
530 was running on termination
532 at this point now its sure, that there will be no new
533 data send to the driver, and we can cancel the last
536 MMRESULT result = waveOutReset( p_sys->h_waveout );
537 if(result != MMSYSERR_NOERROR)
539 msg_Err( p_aout, "waveOutReset failed 0x%x", result );
541 now we must wait, that all buffers are played
542 because cancel doesn't work in this case...
544 if(result == MMSYSERR_NOTSUPPORTED)
547 clear currently played (done) buffers,
548 if returnvalue > 0 (means some buffer still playing)
549 wait for the driver event callback that one buffer
550 is finished with playing, and check again
551 the timeout of 5000ms is just, an emergency exit
552 of this loop, to avoid deadlock in case of other
553 (currently not known bugs, problems, errors cases?)
556 (WaveOutClearDoneBuffers( p_sys ) > 0)
558 (WaitForSingleObject( p_sys->event, 5000) == WAIT_OBJECT_0)
561 msg_Dbg( p_aout, "Wait for waveout device...");
565 WaveOutClearDoneBuffers( p_sys );
568 /* now we can Close the device */
569 if( waveOutClose( p_sys->h_waveout ) != MMSYSERR_NOERROR )
571 msg_Err( p_aout, "waveOutClose failed" );
575 because so long, the waveout device is playing, the callback
576 could occur and need the events
578 CloseHandle( p_sys->event );
579 CloseHandle( p_sys->new_buffer_event);
581 free( p_sys->p_silence_buffer );
585 /*****************************************************************************
586 * OpenWaveOut: open the waveout sound device
587 ****************************************************************************/
588 static int OpenWaveOut( aout_instance_t *p_aout, uint32_t i_device_id, int i_format,
589 int i_channels, int i_nb_channels, int i_rate,
595 /* Set sound format */
597 #define waveformat p_aout->output.p_sys->waveformat
599 waveformat.dwChannelMask = 0;
600 for( i = 0; i < sizeof(pi_channels_src)/sizeof(uint32_t); i++ )
602 if( i_channels & pi_channels_src[i] )
603 waveformat.dwChannelMask |= pi_channels_in[i];
608 case VLC_CODEC_SPDIFL:
610 /* To prevent channel re-ordering */
611 waveformat.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
612 waveformat.Format.wBitsPerSample = 16;
613 waveformat.Samples.wValidBitsPerSample =
614 waveformat.Format.wBitsPerSample;
615 waveformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
616 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF;
620 waveformat.Format.wBitsPerSample = sizeof(float) * 8;
621 waveformat.Samples.wValidBitsPerSample =
622 waveformat.Format.wBitsPerSample;
623 waveformat.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
624 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
628 waveformat.Format.wBitsPerSample = 16;
629 waveformat.Samples.wValidBitsPerSample =
630 waveformat.Format.wBitsPerSample;
631 waveformat.Format.wFormatTag = WAVE_FORMAT_PCM;
632 waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_PCM;
636 waveformat.Format.nChannels = i_nb_channels;
637 waveformat.Format.nSamplesPerSec = i_rate;
638 waveformat.Format.nBlockAlign =
639 waveformat.Format.wBitsPerSample / 8 * i_nb_channels;
640 waveformat.Format.nAvgBytesPerSec =
641 waveformat.Format.nSamplesPerSec * waveformat.Format.nBlockAlign;
643 /* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */
644 if( i_nb_channels <= 2 )
646 waveformat.Format.cbSize = 0;
650 waveformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
651 waveformat.Format.cbSize =
652 sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
656 msg_Dbg( p_aout, "OpenWaveDevice-ID: %u", i_device_id);
657 msg_Dbg( p_aout,"waveformat.Format.cbSize = %d",
658 waveformat.Format.cbSize);
659 msg_Dbg( p_aout,"waveformat.Format.wFormatTag = %u",
660 waveformat.Format.wFormatTag);
661 msg_Dbg( p_aout,"waveformat.Format.nChannels = %u",
662 waveformat.Format.nChannels);
663 msg_Dbg( p_aout,"waveformat.Format.nSamplesPerSec = %d",
664 (int)waveformat.Format.nSamplesPerSec);
665 msg_Dbg( p_aout,"waveformat.Format.nAvgBytesPerSec = %u",
666 (int)waveformat.Format.nAvgBytesPerSec);
667 msg_Dbg( p_aout,"waveformat.Format.nBlockAlign = %d",
668 waveformat.Format.nBlockAlign);
669 msg_Dbg( p_aout,"waveformat.Format.wBitsPerSample = %d",
670 waveformat.Format.wBitsPerSample);
671 msg_Dbg( p_aout,"waveformat.Samples.wValidBitsPerSample = %d",
672 waveformat.Samples.wValidBitsPerSample);
673 msg_Dbg( p_aout,"waveformat.Samples.wSamplesPerBlock = %d",
674 waveformat.Samples.wSamplesPerBlock);
675 msg_Dbg( p_aout,"waveformat.dwChannelMask = %lu",
676 waveformat.dwChannelMask);
679 /* Open the device */
680 result = waveOutOpen( &p_aout->output.p_sys->h_waveout, i_device_id,
681 (WAVEFORMATEX *)&waveformat,
682 (DWORD_PTR)WaveOutCallback, (DWORD_PTR)p_aout,
683 CALLBACK_FUNCTION | (b_probe?WAVE_FORMAT_QUERY:0) );
684 if( result == WAVERR_BADFORMAT )
686 msg_Warn( p_aout, "waveOutOpen failed WAVERR_BADFORMAT" );
689 if( result == MMSYSERR_ALLOCATED )
691 msg_Warn( p_aout, "waveOutOpen failed WAVERR_ALLOCATED" );
694 if( result != MMSYSERR_NOERROR )
696 msg_Warn( p_aout, "waveOutOpen failed" );
700 p_aout->output.p_sys->b_chan_reorder =
701 aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
702 waveformat.dwChannelMask, i_nb_channels,
703 p_aout->output.p_sys->pi_chan_table );
705 if( p_aout->output.p_sys->b_chan_reorder )
707 msg_Dbg( p_aout, "channel reordering needed" );
716 /*****************************************************************************
717 * OpenWaveOutPCM: open a PCM waveout sound device
718 ****************************************************************************/
719 static int OpenWaveOutPCM( aout_instance_t *p_aout, uint32_t i_device_id,
720 vlc_fourcc_t *i_format,
721 int i_channels, int i_nb_channels, int i_rate,
724 bool b_use_float32 = var_CreateGetBool( p_aout, "waveout-float32");
726 if( !b_use_float32 || OpenWaveOut( p_aout, i_device_id, VLC_CODEC_FL32,
727 i_channels, i_nb_channels, i_rate, b_probe )
730 if ( OpenWaveOut( p_aout, i_device_id, VLC_CODEC_S16L,
731 i_channels, i_nb_channels, i_rate, b_probe )
738 *i_format = VLC_CODEC_S16L;
744 *i_format = VLC_CODEC_FL32;
749 /*****************************************************************************
750 * PlayWaveOut: play a buffer through the WaveOut device
751 *****************************************************************************/
752 static int PlayWaveOut( aout_instance_t *p_aout, HWAVEOUT h_waveout,
753 WAVEHDR *p_waveheader, aout_buffer_t *p_buffer,
758 /* Prepare the buffer */
759 if( p_buffer != NULL )
761 p_waveheader->lpData = p_buffer->p_buffer;
763 copy the buffer to the silence buffer :) so in case we don't
764 get the next buffer fast enough (I will repeat this one a time
765 for AC3 / DTS and SPDIF this will sound better instead of
770 vlc_memcpy( p_aout->output.p_sys->p_silence_buffer,
772 p_aout->output.p_sys->i_buffer_size );
773 p_aout->output.p_sys->i_repeat_counter = 2;
776 /* Use silence buffer instead */
777 if(p_aout->output.p_sys->i_repeat_counter)
779 p_aout->output.p_sys->i_repeat_counter--;
780 if(!p_aout->output.p_sys->i_repeat_counter)
782 vlc_memset( p_aout->output.p_sys->p_silence_buffer,
783 0x00, p_aout->output.p_sys->i_buffer_size );
786 p_waveheader->lpData = p_aout->output.p_sys->p_silence_buffer;
789 p_waveheader->dwUser = p_buffer ? (DWORD_PTR)p_buffer : (DWORD_PTR)1;
790 p_waveheader->dwBufferLength = p_aout->output.p_sys->i_buffer_size;
791 p_waveheader->dwFlags = 0;
793 result = waveOutPrepareHeader( h_waveout, p_waveheader, sizeof(WAVEHDR) );
794 if( result != MMSYSERR_NOERROR )
796 msg_Err( p_aout, "waveOutPrepareHeader failed" );
800 /* Send the buffer to the waveOut queue */
801 result = waveOutWrite( h_waveout, p_waveheader, sizeof(WAVEHDR) );
802 if( result != MMSYSERR_NOERROR )
804 msg_Err( p_aout, "waveOutWrite failed" );
811 /*****************************************************************************
812 * WaveOutCallback: what to do once WaveOut has played its sound samples
813 *****************************************************************************/
814 static void CALLBACK WaveOutCallback( HWAVEOUT h_waveout, UINT uMsg,
816 DWORD dwParam1, DWORD dwParam2 )
818 (void)h_waveout; (void)dwParam1; (void)dwParam2;
819 aout_instance_t *p_aout = (aout_instance_t *)_p_aout;
820 int i, i_queued_frames = 0;
822 if( uMsg != WOM_DONE ) return;
824 if( !vlc_object_alive (p_aout) ) return;
826 /* Find out the current latency */
827 for( i = 0; i < FRAMES_NUM; i++ )
829 /* Check if frame buf is available */
830 if( !(p_aout->output.p_sys->waveheader[i].dwFlags & WHDR_DONE) )
836 /* Don't wake up the thread too much */
837 if( i_queued_frames <= FRAMES_NUM/2 )
838 SetEvent( p_aout->output.p_sys->event );
842 /****************************************************************************
843 * WaveOutClearDoneBuffers: Clear all done marked buffers, and free aout_bufer
844 ****************************************************************************
845 * return value is the number of still playing buffers in the queue
846 ****************************************************************************/
847 static int WaveOutClearDoneBuffers(aout_sys_t *p_sys)
849 WAVEHDR *p_waveheader = p_sys->waveheader;
850 int i_queued_frames = 0;
852 for( int i = 0; i < FRAMES_NUM; i++ )
854 if( (p_waveheader[i].dwFlags & WHDR_DONE) &&
855 p_waveheader[i].dwUser )
857 aout_buffer_t *p_buffer =
858 (aout_buffer_t *)(p_waveheader[i].dwUser);
859 /* Unprepare and free the buffers which has just been played */
860 waveOutUnprepareHeader( p_sys->h_waveout, &p_waveheader[i],
863 if( p_waveheader[i].dwUser != 1 )
864 aout_BufferFree( p_buffer );
866 p_waveheader[i].dwUser = 0;
869 /* Check if frame buf is available */
870 if( !(p_waveheader[i].dwFlags & WHDR_DONE) )
875 return i_queued_frames;
878 /*****************************************************************************
879 * WaveOutThread: this thread will capture play notification events.
880 *****************************************************************************
881 * We use this thread to feed new audio samples to the sound card because
882 * we are not authorized to use waveOutWrite() directly in the waveout
884 *****************************************************************************/
885 static void* WaveOutThread( vlc_object_t *p_this )
887 notification_thread_t *p_notif = (notification_thread_t*)p_this;
888 aout_instance_t *p_aout = p_notif->p_aout;
889 aout_sys_t *p_sys = p_aout->output.p_sys;
890 aout_buffer_t *p_buffer = NULL;
891 WAVEHDR *p_waveheader = p_sys->waveheader;
892 int i, i_queued_frames;
895 uint32_t i_buffer_length = 64;
896 int canc = vlc_savecancel ();
898 /* We don't want any resampling when using S/PDIF */
899 b_sleek = p_aout->output.output.i_format == VLC_CODEC_SPDIFL;
901 // wait for first call to "play()"
902 while( !p_sys->start_date && vlc_object_alive (p_aout) )
903 WaitForSingleObject( p_sys->event, INFINITE );
904 if( !vlc_object_alive (p_aout) )
907 msg_Dbg( p_aout, "will start to play in %"PRId64" us",
908 (p_sys->start_date - AOUT_PTS_TOLERANCE/4)-mdate());
910 // than wait a short time... before grabbing first frames
911 mwait( p_sys->start_date - AOUT_PTS_TOLERANCE/4 );
913 #define waveout_warn(msg) msg_Warn( p_aout, "aout_OutputNextBuffer no buffer "\
914 "got next_date=%d ms, "\
915 "%d frames to play, "\
916 "starving? %d, %s",(int)(next_date/(mtime_t)1000), \
918 p_aout->output.b_starving, msg);
921 while( vlc_object_alive (p_aout) )
923 /* Cleanup and find out the current latency */
924 i_queued_frames = WaveOutClearDoneBuffers( p_sys );
926 if( !vlc_object_alive (p_aout) ) return NULL;
928 /* Try to fill in as many frame buffers as possible */
929 for( i = 0; i < FRAMES_NUM; i++ )
931 /* Check if frame buf is available */
932 if( p_waveheader[i].dwFlags & WHDR_DONE )
934 // next_date = mdate() + 1000000 * i_queued_frames /
935 // p_aout->output.output.i_rate * p_aout->output.i_nb_samples;
937 // the realtime has got our back-site:) to come in sync
938 if(next_date < mdate())
942 /* Take into account the latency */
943 p_buffer = aout_OutputNextBuffer( p_aout,
950 msg_Dbg( p_aout, "aout_OutputNextBuffer no buffer "\
951 "got next_date=%d ms, "\
952 "%d frames to play, "\
953 "starving? %d",(int)(next_date/(mtime_t)1000),
955 p_aout->output.b_starving);
957 if(p_aout->output.b_starving)
959 // means we are too early to request a new buffer?
960 waveout_warn("waiting...")
961 next_date = aout_FifoFirstDate( p_aout, &p_aout->output.fifo );
962 mwait( next_date - AOUT_PTS_TOLERANCE/4 );
964 p_buffer = aout_OutputNextBuffer( p_aout,
971 if( !p_buffer && i_queued_frames )
973 /* We aren't late so no need to play a blank sample */
979 mtime_t buffer_length = p_buffer->i_length;
980 next_date = next_date + buffer_length;
981 i_buffer_length = buffer_length/1000;
984 /* Do the channel reordering */
985 if( p_buffer && p_sys->b_chan_reorder )
987 aout_ChannelReorder( p_buffer->p_buffer,
989 p_sys->waveformat.Format.nChannels,
990 p_sys->pi_chan_table,
991 p_sys->waveformat.Format.wBitsPerSample );
994 PlayWaveOut( p_aout, p_sys->h_waveout,
995 &p_waveheader[i], p_buffer, b_sleek );
1001 if( !vlc_object_alive (p_aout) ) return NULL;
1004 deal with the case that the loop didn't fillup the buffer to the
1005 max - instead of waiting that half the buffer is played before
1006 fillup the waveout buffers, wait only for the next sample buffer
1007 to arrive at the play method...
1009 this will also avoid, that the last buffer is play until the
1010 end, and then trying to get more data, so it will also
1011 work - if the next buffer will arrive some ms before the
1012 last buffer is finished.
1014 if(i_queued_frames < FRAMES_NUM)
1015 WaitForSingleObject( p_sys->new_buffer_event, INFINITE );
1017 WaitForSingleObject( p_sys->event, INFINITE );
1022 vlc_restorecancel (canc);
1026 static int VolumeGet( aout_instance_t * p_aout, audio_volume_t * pi_volume )
1028 DWORD i_waveout_vol;
1031 waveOutGetVolume( 0, &i_waveout_vol );
1033 waveOutGetVolume( p_aout->output.p_sys->h_waveout, &i_waveout_vol );
1036 i_waveout_vol &= 0xFFFF;
1037 *pi_volume = p_aout->output.i_volume =
1038 (i_waveout_vol * AOUT_VOLUME_MAX + 0xFFFF /*rounding*/) / 2 / 0xFFFF;
1042 static int VolumeSet( aout_instance_t * p_aout, audio_volume_t i_volume )
1044 unsigned long i_waveout_vol = i_volume * 0xFFFF * 2 / AOUT_VOLUME_MAX;
1045 i_waveout_vol |= (i_waveout_vol << 16);
1048 waveOutSetVolume( 0, i_waveout_vol );
1050 waveOutSetVolume( p_aout->output.p_sys->h_waveout, i_waveout_vol );
1053 p_aout->output.i_volume = i_volume;
1059 reload the configuration drop down list, of the Audio Devices
1061 static int ReloadWaveoutDevices( vlc_object_t *p_this, char const *psz_name,
1062 vlc_value_t newval, vlc_value_t oldval, void *data )
1064 VLC_UNUSED( newval ); VLC_UNUSED( oldval ); VLC_UNUSED( data );
1066 module_config_t *p_item = config_FindConfig( p_this, psz_name );
1067 if( !p_item ) return VLC_SUCCESS;
1069 /* Clear-up the current list */
1070 if( p_item->i_list )
1074 /* Keep the first entry */
1075 for( i = 1; i < p_item->i_list; i++ )
1077 free((char *)(p_item->ppsz_list[i]) );
1078 free((char *)(p_item->ppsz_list_text[i]) );
1080 /* TODO: Remove when no more needed */
1081 p_item->ppsz_list[i] = NULL;
1082 p_item->ppsz_list_text[i] = NULL;
1086 int wave_devices = waveOutGetNumDevs();
1088 p_item->ppsz_list = xrealloc( p_item->ppsz_list,
1089 (wave_devices+2) * sizeof(char *) );
1090 p_item->ppsz_list_text = xrealloc( p_item->ppsz_list_text,
1091 (wave_devices+2) * sizeof(char *) );
1094 char sz_dev_name[MAXPNAMELEN+32];
1096 for(int i=0; i<wave_devices; i++)
1098 if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
1099 == MMSYSERR_NOERROR)
1101 sprintf( sz_dev_name, psz_device_name_fmt, caps.szPname,
1105 p_item->ppsz_list[j] = FromLocaleDup( sz_dev_name );
1106 p_item->ppsz_list_text[j] = FromLocaleDup( sz_dev_name );
1112 p_item->ppsz_list[j] = NULL;
1113 p_item->ppsz_list_text[j] = NULL;
1115 /* Signal change to the interface */
1116 p_item->b_dirty = true;
1122 convert devicename to device ID for output
1123 if device not found return WAVE_MAPPER, so let
1124 windows decide which preferred audio device
1127 static uint32_t findDeviceID(char *psz_device_name)
1129 if(!psz_device_name)
1132 uint32_t wave_devices = waveOutGetNumDevs();
1134 char sz_dev_name[MAXPNAMELEN+32];
1135 for(uint32_t i=0; i<wave_devices; i++)
1137 if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
1138 == MMSYSERR_NOERROR)
1140 sprintf(sz_dev_name, psz_device_name_fmt, caps.szPname,
1144 char *psz_temp = FromLocaleDup(sz_dev_name);
1146 if( !stricmp(psz_temp, psz_device_name) )
1148 LocaleFree( psz_temp );
1151 LocaleFree( psz_temp );