Commit 9438646c authored by André Weber's avatar André Weber

#492 bugfix, for SPDIF audio ouput of AC3 and DTS sound on Windows

(but its still critical because it happens - aout_OutputNextBuffer(...) has no buffers
available - sometime the output doesn't know until some ms before the last block
has finished to play! so each little disturbtion of the CPU or load change
leads to studdering/hickups)

#897 enhancement: give the use the option to choose its prefered audio device,
instead of useing Windows default
parent 23ce4b2c
......@@ -31,6 +31,7 @@
#include <vlc/vlc.h>
#include <vlc_aout.h>
#include <vlc_charset.h>
#include <windows.h>
#include <mmsystem.h>
......@@ -120,10 +121,12 @@ typedef struct notification_thread_t
/* local functions */
static void Probe ( aout_instance_t * );
static int OpenWaveOut ( aout_instance_t *, int, int, int, int, vlc_bool_t );
static int OpenWaveOutPCM( aout_instance_t *, int*, int, int, int, vlc_bool_t );
static int OpenWaveOut ( aout_instance_t *, uint32_t,
int, int, int, int, vlc_bool_t );
static int OpenWaveOutPCM( aout_instance_t *, uint32_t,
int*, int, int, int, vlc_bool_t );
static int PlayWaveOut ( aout_instance_t *, HWAVEOUT, WAVEHDR *,
aout_buffer_t * );
aout_buffer_t *, vlc_bool_t );
static void CALLBACK WaveOutCallback ( HWAVEOUT, UINT, DWORD, DWORD, DWORD );
static void WaveOutThread( notification_thread_t * );
......@@ -132,6 +135,19 @@ static int VolumeInfos( aout_instance_t *, audio_volume_t * );
static int VolumeGet( aout_instance_t *, audio_volume_t * );
static int VolumeSet( aout_instance_t *, audio_volume_t );
static int WaveOutClearDoneBuffers(aout_sys_t *p_sys);
static int ReloadWaveoutDevices( vlc_object_t *, char const *,
vlc_value_t, vlc_value_t, void * );
static uint32_t findDeviceID(char *);
static const char psz_device_name_fmt[] = "%s ($%x,$%x)";
static const char *ppsz_adev[] = { "wavemapper", };
static const char *ppsz_adev_text[] = { N_("Microsoft Soundmapper") };
/*****************************************************************************
* Module descriptor
*****************************************************************************/
......@@ -139,6 +155,11 @@ static int VolumeSet( aout_instance_t *, audio_volume_t );
#define FLOAT_LONGTEXT N_( \
"The option allows you to enable or disable the high-quality float32 " \
"audio output mode (which is not well supported by some soundcards)." )
#define DEVICE_TEXT N_("Select Audio Device")
#define DEVICE_LONG N_("Select special Audio device, or let windows "\
"decide (default), change needs VLC restart "\
"to apply.")
#define DEFAULT_AUDIO_DEVICE N_("Default Audio Device")
vlc_module_begin();
set_shortname( "WaveOut" );
......@@ -147,6 +168,14 @@ vlc_module_begin();
set_category( CAT_AUDIO );
set_subcategory( SUBCAT_AUDIO_AOUT );
add_bool( "waveout-float32", 1, 0, FLOAT_TEXT, FLOAT_LONGTEXT, VLC_TRUE );
add_string( "waveout-dev", "wavemapper", NULL,
DEVICE_TEXT, DEVICE_LONG, VLC_FALSE );
change_string_list( ppsz_adev, ppsz_adev_text, ReloadWaveoutDevices );
change_need_restart();
change_action_add( ReloadWaveoutDevices, N_("Refresh list") );
set_callbacks( Open, Close );
vlc_module_end();
......@@ -158,6 +187,8 @@ vlc_module_end();
*****************************************************************************/
struct aout_sys_t
{
uint32_t i_wave_device_id; /* ID of selected output device */
HWAVEOUT h_waveout; /* handle to waveout instance */
WAVEFORMATEXTENSIBLE waveformat; /* audio format */
......@@ -166,6 +197,13 @@ struct aout_sys_t
notification_thread_t *p_notif; /* WaveOutThread id */
HANDLE event;
HANDLE new_buffer_event;
// rental from alsa.c to synchronize startup of audiothread
int b_playing; /* playing status */
mtime_t start_date;
int i_repeat_counter;
int i_buffer_size;
......@@ -214,6 +252,50 @@ static int Open( vlc_object_t *p_this )
p_aout->output.pf_play = Play;
p_aout->b_die = VLC_FALSE;
/*
initialize/update Device selection List
*/
ReloadWaveoutDevices( p_this, "waveout-dev", val, val, NULL);
/*
check for configured audio device!
*/
char *psz_waveout_dev = var_CreateGetString( p_aout, "waveout-dev");
p_aout->output.p_sys->i_wave_device_id =
findDeviceID( psz_waveout_dev );
if(p_aout->output.p_sys->i_wave_device_id == WAVE_MAPPER)
{
if(psz_waveout_dev &&
stricmp(psz_waveout_dev,"wavemapper"))
{
msg_Warn( p_aout, "configured audio device '%s' not available, "\
"use default instead", psz_waveout_dev );
}
}
if(psz_waveout_dev) free( psz_waveout_dev );
WAVEOUTCAPS waveoutcaps;
if(waveOutGetDevCaps( p_aout->output.p_sys->i_wave_device_id,
&waveoutcaps,
sizeof(WAVEOUTCAPS)) == MMSYSERR_NOERROR)
{
/* log debug some infos about driver, to know who to blame
if it doesn't work */
msg_Dbg( p_aout, "Drivername: %s", waveoutcaps.szPname);
msg_Dbg( p_aout, "Driver Version: %d.%d",
(waveoutcaps.vDriverVersion>>8)&255,
waveoutcaps.vDriverVersion & 255);
msg_Dbg( p_aout, "Manufacturer identifier: 0x%x", waveoutcaps.wMid );
msg_Dbg( p_aout, "Product identifier: 0x%x", waveoutcaps.wPid );
}
if( var_Type( p_aout, "audio-device" ) == 0 )
{
Probe( p_aout );
......@@ -222,18 +304,20 @@ static int Open( vlc_object_t *p_this )
if( var_Get( p_aout, "audio-device", &val ) < 0 )
{
/* Probe() has failed. */
var_Destroy( p_aout, "waveout-device");
free( p_aout->output.p_sys );
return VLC_EGENERIC;
}
var_Create( p_aout, "waveout-float32", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
/* Open the device */
if( val.i_int == AOUT_VAR_SPDIF )
{
p_aout->output.output.i_format = VLC_FOURCC('s','p','d','i');
if( OpenWaveOut( p_aout, VLC_FOURCC('s','p','d','i'),
if( OpenWaveOut( p_aout,
p_aout->output.p_sys->i_wave_device_id,
VLC_FOURCC('s','p','d','i'),
p_aout->output.output.i_physical_channels,
aout_FormatNbChannels( &p_aout->output.output ),
p_aout->output.output.i_rate, VLC_FALSE )
......@@ -280,7 +364,9 @@ static int Open( vlc_object_t *p_this )
= AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
}
if( OpenWaveOutPCM( p_aout, &p_aout->output.output.i_format,
if( OpenWaveOutPCM( p_aout,
p_aout->output.p_sys->i_wave_device_id,
&p_aout->output.output.i_format,
p_aout->output.output.i_physical_channels,
aout_FormatNbChannels( &p_aout->output.output ),
p_aout->output.output.i_rate, VLC_FALSE )
......@@ -327,6 +413,8 @@ static int Open( vlc_object_t *p_this )
msg_Err( p_aout, "out of memory" );
return 1;
}
p_aout->output.p_sys->i_repeat_counter = 0;
/* Zero the buffer. WinCE doesn't have calloc(). */
memset( p_aout->output.p_sys->p_silence_buffer, 0,
......@@ -337,11 +425,18 @@ static int Open( vlc_object_t *p_this )
vlc_object_create( p_aout, sizeof(notification_thread_t) );
p_aout->output.p_sys->p_notif->p_aout = p_aout;
p_aout->output.p_sys->event = CreateEvent( NULL, FALSE, FALSE, NULL );
p_aout->output.p_sys->new_buffer_event = CreateEvent( NULL, FALSE, FALSE, NULL );
/* define startpoint of playback on first call to play()
like alsa does (instead of playing a blank sample) */
p_aout->output.p_sys->b_playing = 0;
p_aout->output.p_sys->start_date = 0;
/* Then launch the notification thread */
if( vlc_thread_create( p_aout->output.p_sys->p_notif,
"waveOut Notification Thread", WaveOutThread,
VLC_THREAD_PRIORITY_HIGHEST, VLC_FALSE ) )
VLC_THREAD_PRIORITY_OUTPUT, VLC_FALSE ) )
{
msg_Err( p_aout, "cannot create WaveOutThread" );
}
......@@ -353,8 +448,6 @@ static int Open( vlc_object_t *p_this )
p_aout->output.p_sys->waveheader[i].dwFlags = WHDR_DONE;
p_aout->output.p_sys->waveheader[i].dwUser = 0;
}
PlayWaveOut( p_aout, p_aout->output.p_sys->h_waveout,
&p_aout->output.p_sys->waveheader[0], NULL );
return 0;
}
......@@ -378,13 +471,15 @@ static void Probe( aout_instance_t * p_aout )
AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE;
if( p_aout->output.output.i_physical_channels == i_physical_channels )
{
if( OpenWaveOutPCM( p_aout, &i_format,
if( OpenWaveOutPCM( p_aout,
p_aout->output.p_sys->i_wave_device_id,
&i_format,
i_physical_channels, 6,
p_aout->output.output.i_rate, VLC_TRUE )
== VLC_SUCCESS )
{
val.i_int = AOUT_VAR_5_1;
text.psz_string = N_("5.1");
text.psz_string = (char *)N_("5.1");
var_Change( p_aout, "audio-device",
VLC_VAR_ADDCHOICE, &val, &text );
msg_Dbg( p_aout, "device supports 5.1 channels" );
......@@ -397,13 +492,15 @@ static void Probe( aout_instance_t * p_aout )
if( ( p_aout->output.output.i_physical_channels & i_physical_channels )
== i_physical_channels )
{
if( OpenWaveOutPCM( p_aout, &i_format,
if( OpenWaveOutPCM( p_aout,
p_aout->output.p_sys->i_wave_device_id,
&i_format,
i_physical_channels, 4,
p_aout->output.output.i_rate, VLC_TRUE )
== VLC_SUCCESS )
{
val.i_int = AOUT_VAR_2F2R;
text.psz_string = N_("2 Front 2 Rear");
text.psz_string = (char *)N_("2 Front 2 Rear");
var_Change( p_aout, "audio-device",
VLC_VAR_ADDCHOICE, &val, &text );
msg_Dbg( p_aout, "device supports 4 channels" );
......@@ -412,26 +509,30 @@ static void Probe( aout_instance_t * p_aout )
/* Test for stereo support */
i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
if( OpenWaveOutPCM( p_aout, &i_format,
if( OpenWaveOutPCM( p_aout,
p_aout->output.p_sys->i_wave_device_id,
&i_format,
i_physical_channels, 2,
p_aout->output.output.i_rate, VLC_TRUE )
== VLC_SUCCESS )
{
val.i_int = AOUT_VAR_STEREO;
text.psz_string = N_("Stereo");
text.psz_string = (char *)N_("Stereo");
var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
msg_Dbg( p_aout, "device supports 2 channels" );
}
/* Test for mono support */
i_physical_channels = AOUT_CHAN_CENTER;
if( OpenWaveOutPCM( p_aout, &i_format,
if( OpenWaveOutPCM( p_aout,
p_aout->output.p_sys->i_wave_device_id,
&i_format,
i_physical_channels, 1,
p_aout->output.output.i_rate, VLC_TRUE )
== VLC_SUCCESS )
{
val.i_int = AOUT_VAR_MONO;
text.psz_string = N_("Mono");
text.psz_string = (char *)N_("Mono");
var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
msg_Dbg( p_aout, "device supports 1 channel" );
}
......@@ -439,7 +540,9 @@ static void Probe( aout_instance_t * p_aout )
/* Test for SPDIF support */
if ( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
{
if( OpenWaveOut( p_aout, VLC_FOURCC('s','p','d','i'),
if( OpenWaveOut( p_aout,
p_aout->output.p_sys->i_wave_device_id,
VLC_FOURCC('s','p','d','i'),
p_aout->output.output.i_physical_channels,
aout_FormatNbChannels( &p_aout->output.output ),
p_aout->output.output.i_rate, VLC_TRUE )
......@@ -447,7 +550,7 @@ static void Probe( aout_instance_t * p_aout )
{
msg_Dbg( p_aout, "device supports A/52 over S/PDIF" );
val.i_int = AOUT_VAR_SPDIF;
text.psz_string = N_("A/52 over S/PDIF");
text.psz_string = (char *)N_("A/52 over S/PDIF");
var_Change( p_aout, "audio-device",
VLC_VAR_ADDCHOICE, &val, &text );
if( config_GetInt( p_aout, "spdif" ) )
......@@ -477,6 +580,21 @@ static void Probe( aout_instance_t * p_aout )
*****************************************************************************/
static void Play( aout_instance_t *_p_aout )
{
if( !_p_aout->output.p_sys->b_playing )
{
_p_aout->output.p_sys->b_playing = 1;
/* get the playing date of the first aout buffer */
_p_aout->output.p_sys->start_date =
aout_FifoFirstDate( _p_aout, &_p_aout->output.fifo );
msg_Dbg( _p_aout, "Wakeup sleeping output thread.");
/* wake up the audio output thread */
SetEvent( _p_aout->output.p_sys->event );
} else {
SetEvent( _p_aout->output.p_sys->new_buffer_event );
}
}
/*****************************************************************************
......@@ -490,20 +608,68 @@ static void Close( vlc_object_t *p_this )
/* Before calling waveOutClose we must reset the device */
vlc_object_kill( p_aout );
waveOutReset( p_sys->h_waveout );
/* wake up the audio thread */
/* wake up the audio thread, to recognize that p_aout died */
SetEvent( p_sys->event );
SetEvent( p_sys->new_buffer_event );
vlc_thread_join( p_sys->p_notif );
vlc_object_release( p_sys->p_notif );
CloseHandle( p_sys->event );
/* Close the device */
/*
kill the real output then - when the feed thread
is surely terminated!
old code could be too early in case that "feeding"
was running on termination
at this point now its sure, that there will be no new
data send to the driver, and we can cancel the last
running playbuffers
*/
MMRESULT result = waveOutReset( p_sys->h_waveout );
if(result != MMSYSERR_NOERROR)
{
msg_Err( p_aout, "waveOutReset failed 0x%x", result );
/*
now we must wait, that all buffers are played
because cancel doesn't work in this case...
*/
if(result == MMSYSERR_NOTSUPPORTED)
{
/*
clear currently played (done) buffers,
if returnvalue > 0 (means some buffer still playing)
wait for the driver event callback that one buffer
is finished with playing, and check again
the timeout of 5000ms is just, an emergency exit
of this loop, to avoid deadlock in case of other
(currently not known bugs, problems, errors cases?)
*/
while(
(WaveOutClearDoneBuffers( p_sys ) > 0)
&&
(WaitForSingleObject( p_sys->event, 5000) == WAIT_OBJECT_0)
)
{
msg_Dbg( p_aout, "Wait for waveout device...");
}
}
} else {
WaveOutClearDoneBuffers( p_sys );
}
/* now we can Close the device */
if( waveOutClose( p_sys->h_waveout ) != MMSYSERR_NOERROR )
{
msg_Err( p_aout, "waveOutClose failed" );
}
/*
because so long, the waveout device is playing, the callback
could occur and need the events
*/
CloseHandle( p_sys->event );
CloseHandle( p_sys->new_buffer_event);
free( p_sys->p_silence_buffer );
free( p_sys );
}
......@@ -511,7 +677,7 @@ static void Close( vlc_object_t *p_this )
/*****************************************************************************
* OpenWaveOut: open the waveout sound device
****************************************************************************/
static int OpenWaveOut( aout_instance_t *p_aout, int i_format,
static int OpenWaveOut( aout_instance_t *p_aout, uint32_t i_device_id, int i_format,
int i_channels, int i_nb_channels, int i_rate,
vlc_bool_t b_probe )
{
......@@ -578,8 +744,32 @@ static int OpenWaveOut( aout_instance_t *p_aout, int i_format,
sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
}
if(!b_probe) {
msg_Dbg( p_aout, "OpenWaveDevice-ID: %u", i_device_id);
msg_Dbg( p_aout,"waveformat.Format.cbSize = %d",
waveformat.Format.cbSize);
msg_Dbg( p_aout,"waveformat.Format.wFormatTag = %u",
waveformat.Format.wFormatTag);
msg_Dbg( p_aout,"waveformat.Format.nChannels = %u",
waveformat.Format.nChannels);
msg_Dbg( p_aout,"waveformat.Format.nSamplesPerSec = %d",
(int)waveformat.Format.nSamplesPerSec);
msg_Dbg( p_aout,"waveformat.Format.nAvgBytesPerSec = %u",
(int)waveformat.Format.nAvgBytesPerSec);
msg_Dbg( p_aout,"waveformat.Format.nBlockAlign = %d",
waveformat.Format.nBlockAlign);
msg_Dbg( p_aout,"waveformat.Format.wBitsPerSample = %d",
waveformat.Format.wBitsPerSample);
msg_Dbg( p_aout,"waveformat.Samples.wValidBitsPerSample = %d",
waveformat.Samples.wValidBitsPerSample);
msg_Dbg( p_aout,"waveformat.Samples.wSamplesPerBlock = %d",
waveformat.Samples.wSamplesPerBlock);
msg_Dbg( p_aout,"waveformat.dwChannelMask = %lu",
waveformat.dwChannelMask);
}
/* Open the device */
result = waveOutOpen( &p_aout->output.p_sys->h_waveout, WAVE_MAPPER,
result = waveOutOpen( &p_aout->output.p_sys->h_waveout, i_device_id,
(WAVEFORMATEX *)&waveformat,
(DWORD_PTR)WaveOutCallback, (DWORD_PTR)p_aout,
CALLBACK_FUNCTION | (b_probe?WAVE_FORMAT_QUERY:0) );
......@@ -618,19 +808,17 @@ static int OpenWaveOut( aout_instance_t *p_aout, int i_format,
/*****************************************************************************
* OpenWaveOutPCM: open a PCM waveout sound device
****************************************************************************/
static int OpenWaveOutPCM( aout_instance_t *p_aout, int *i_format,
static int OpenWaveOutPCM( aout_instance_t *p_aout, uint32_t i_device_id, int *i_format,
int i_channels, int i_nb_channels, int i_rate,
vlc_bool_t b_probe )
{
vlc_value_t val;
var_Get( p_aout, "waveout-float32", &val );
vlc_bool_t b_use_float32 = var_CreateGetBool( p_aout, "waveout-float32");
if( !val.b_bool || OpenWaveOut( p_aout, VLC_FOURCC('f','l','3','2'),
if( !b_use_float32 || OpenWaveOut( p_aout, i_device_id, VLC_FOURCC('f','l','3','2'),
i_channels, i_nb_channels, i_rate, b_probe )
!= VLC_SUCCESS )
{
if ( OpenWaveOut( p_aout, VLC_FOURCC('s','1','6','l'),
if ( OpenWaveOut( p_aout, i_device_id, VLC_FOURCC('s','1','6','l'),
i_channels, i_nb_channels, i_rate, b_probe )
!= VLC_SUCCESS )
{
......@@ -653,16 +841,43 @@ static int OpenWaveOutPCM( aout_instance_t *p_aout, int *i_format,
* PlayWaveOut: play a buffer through the WaveOut device
*****************************************************************************/
static int PlayWaveOut( aout_instance_t *p_aout, HWAVEOUT h_waveout,
WAVEHDR *p_waveheader, aout_buffer_t *p_buffer )
WAVEHDR *p_waveheader, aout_buffer_t *p_buffer,
vlc_bool_t b_spdif)
{
MMRESULT result;
/* Prepare the buffer */
if( p_buffer != NULL )
if( p_buffer != NULL )
{
p_waveheader->lpData = p_buffer->p_buffer;
else
/*
copy the buffer to the silence buffer :) so in case we don't
get the next buffer fast enough (I will repeat this one a time
for AC3 / DTS and SPDIF this will sound better instead of
a hickup)
*/
if(b_spdif)
{
p_aout->p_libvlc->pf_memcpy( p_aout->output.p_sys->p_silence_buffer,
p_buffer->p_buffer,
p_aout->output.p_sys->i_buffer_size );
p_aout->output.p_sys->i_repeat_counter = 2;
}
} else {
/* Use silence buffer instead */
if(p_aout->output.p_sys->i_repeat_counter)
{
p_aout->output.p_sys->i_repeat_counter--;
if(!p_aout->output.p_sys->i_repeat_counter)
{
p_aout->p_libvlc->pf_memset( p_aout->output.p_sys->p_silence_buffer,
0x00,
p_aout->output.p_sys->i_buffer_size
);
}
}
p_waveheader->lpData = p_aout->output.p_sys->p_silence_buffer;
}
p_waveheader->dwUser = p_buffer ? (DWORD_PTR)p_buffer : (DWORD_PTR)1;
p_waveheader->dwBufferLength = p_aout->output.p_sys->i_buffer_size;
......@@ -711,10 +926,47 @@ static void CALLBACK WaveOutCallback( HWAVEOUT h_waveout, UINT uMsg,
}
/* Don't wake up the thread too much */
if( i_queued_frames < FRAMES_NUM / 2 )
if( i_queued_frames <= FRAMES_NUM/2 )
SetEvent( p_aout->output.p_sys->event );
}
/****************************************************************************
* WaveOutClearDoneBuffers: Clear all done marked buffers, and free aout_bufer
****************************************************************************
* return value is the number of still playing buffers in the queue
****************************************************************************/
static int WaveOutClearDoneBuffers(aout_sys_t *p_sys)
{
WAVEHDR *p_waveheader = p_sys->waveheader;
int i_queued_frames = 0;
for( int i = 0; i < FRAMES_NUM; i++ )
{
if( (p_waveheader[i].dwFlags & WHDR_DONE) &&
p_waveheader[i].dwUser )
{
aout_buffer_t *p_buffer =
(aout_buffer_t *)(p_waveheader[i].dwUser);
/* Unprepare and free the buffers which has just been played */
waveOutUnprepareHeader( p_sys->h_waveout, &p_waveheader[i],
sizeof(WAVEHDR) );
if( p_waveheader[i].dwUser != 1 )
aout_BufferFree( p_buffer );
p_waveheader[i].dwUser = 0;
}
/* Check if frame buf is available */
if( !(p_waveheader[i].dwFlags & WHDR_DONE) )
{
i_queued_frames++;
}
}
return i_queued_frames;
}
/*****************************************************************************
* WaveOutThread: this thread will capture play notification events.
*****************************************************************************
......@@ -730,39 +982,36 @@ static void WaveOutThread( notification_thread_t *p_notif )
WAVEHDR *p_waveheader = p_sys->waveheader;
int i, i_queued_frames;
vlc_bool_t b_sleek;
mtime_t next_date;
uint32_t i_buffer_length = 64;
/* We don't want any resampling when using S/PDIF */
b_sleek = p_aout->output.output.i_format == VLC_FOURCC('s','p','d','i');
while( 1 )
{
WaitForSingleObject( p_sys->event, INFINITE );
// wait for first call to "play()"
while( !p_sys->start_date && !p_aout->b_die )
WaitForSingleObject( p_sys->event, INFINITE );
if( p_aout->b_die )
return;
/* Cleanup and find out the current latency */
i_queued_frames = 0;
for( i = 0; i < FRAMES_NUM; i++ )
{
if( (p_waveheader[i].dwFlags & WHDR_DONE) &&
p_waveheader[i].dwUser )
{
aout_buffer_t *p_buffer =
(aout_buffer_t *)(p_waveheader[i].dwUser);
/* Unprepare and free the buffers which has just been played */
waveOutUnprepareHeader( p_sys->h_waveout, &p_waveheader[i],
sizeof(WAVEHDR) );
msg_Dbg( p_aout, "will start to play in "I64Fd" us",
(p_sys->start_date - AOUT_PTS_TOLERANCE/4)-mdate());
if( p_waveheader[i].dwUser != 1 )
aout_BufferFree( p_buffer );
// than wait a short time... before grabbing first frames
mwait( p_sys->start_date - AOUT_PTS_TOLERANCE/4 );
p_waveheader[i].dwUser = 0;
}
#define waveout_warn(msg) msg_Warn( p_aout, "aout_OutputNextBuffer no buffer "\
"got next_date=%d ms, "\
"%d frames to play, "\
"starving? %d, %s",(int)(next_date/(mtime_t)1000), \
i_queued_frames, \
p_aout->output.b_starving, msg);
next_date = mdate();
/* Check if frame buf is available */
if( !(p_waveheader[i].dwFlags & WHDR_DONE) )
{
i_queued_frames++;
}
}
while( !p_aout->b_die )
{
/* Cleanup and find out the current latency */
i_queued_frames = WaveOutClearDoneBuffers( p_sys );
if( p_aout->b_die ) return;
......@@ -772,18 +1021,57 @@ static void WaveOutThread( notification_thread_t *p_notif )
/* Check if frame buf is available */
if( p_waveheader[i].dwFlags & WHDR_DONE )
{
// next_date = mdate() + 1000000 * i_queued_frames /
// p_aout->output.output.i_rate * p_aout->output.i_nb_samples;
// the realtime has got our back-site:) to come in sync
if(next_date < mdate())
next_date = mdate();
/* Take into account the latency */
p_buffer = aout_OutputNextBuffer( p_aout,
mdate() + 1000000 * i_queued_frames /
p_aout->output.output.i_rate * p_aout->output.i_nb_samples,
next_date,
b_sleek );
if(!p_buffer)
{
#if 0
msg_Dbg( p_aout, "aout_OutputNextBuffer no buffer "\
"got next_date=%d ms, "\
"%d frames to play, "\
"starving? %d",(int)(next_date/(mtime_t)1000),
i_queued_frames,
p_aout->output.b_starving);
#endif
if(p_aout->output.b_starving)
{
// means we are too early to request a new buffer?
waveout_warn("waiting...")
next_date = aout_FifoFirstDate( p_aout, &p_aout->output.fifo );
mwait( next_date - AOUT_PTS_TOLERANCE/4 );
next_date = mdate();
p_buffer = aout_OutputNextBuffer( p_aout,
next_date,
b_sleek
);
}
}
if( !p_buffer && i_queued_frames )
{
/* We aren't late so no need to play a blank sample */
break;
}
if( p_buffer )
{
mtime_t buffer_length = (p_buffer->end_date
- p_buffer->start_date);
next_date = next_date + buffer_length;
i_buffer_length = buffer_length/1000;
}
/* Do the channel reordering */
if( p_buffer && p_sys->b_chan_reorder )
{
......@@ -795,12 +1083,33 @@ static void WaveOutThread( notification_thread_t *p_notif )
}
PlayWaveOut( p_aout, p_sys->h_waveout,
&p_waveheader[i], p_buffer );
&p_waveheader[i], p_buffer, b_sleek );
i_queued_frames++;
}
}
if( p_aout->b_die ) return;
/*
deal with the case that the loop didn't fillup the buffer to the
max - instead of waiting that half the buffer is played before
fillup the waveout buffers, wait only for the next sample buffer
to arrive at the play method...
this will also avoid, that the last buffer is play until the
end, and then trying to get more data, so it will also
work - if the next buffer will arrive some ms before the
last buffer is finished.
*/
if(i_queued_frames < FRAMES_NUM)
WaitForSingleObject( p_sys->new_buffer_event, INFINITE );
else
WaitForSingleObject( p_sys->event, INFINITE );
}
#undef waveout_warn
}
static int VolumeInfos( aout_instance_t * p_aout, audio_volume_t * pi_soft )
......@@ -839,3 +1148,98 @@ static int VolumeSet( aout_instance_t * p_aout, audio_volume_t i_volume )
p_aout->output.i_volume = i_volume;
return 0;
}
/*
reload the configuration drop down list, of the Audio Devices
*/
static int ReloadWaveoutDevices( vlc_object_t *p_this, char const *psz_name,
vlc_value_t newval, vlc_value_t oldval, void *data )
{
int i;
module_config_t *p_item = config_FindConfig( p_this, psz_name );
if( !p_item ) return VLC_SUCCESS;
/* Clear-up the current list */
if( p_item->i_list )
{
/* Keep the first entry */
for( i = 1; i < p_item->i_list; i++ )
{
free((char *)(p_item->ppsz_list[i]) );
free((char *)(p_item->ppsz_list_text[i]) );
}
/* TODO: Remove when no more needed */
p_item->ppsz_list[i] = NULL;
p_item->ppsz_list_text[i] = NULL;
}
p_item->i_list = 1;
int wave_devices = waveOutGetNumDevs();
p_item->ppsz_list =
(char **)realloc( p_item->ppsz_list,
(wave_devices+2) * sizeof(char *) );
p_item->ppsz_list_text =
(char **)realloc( p_item->ppsz_list_text,
(wave_devices+2) * sizeof(char *) );
WAVEOUTCAPS caps;
char sz_dev_name[MAXPNAMELEN+32];
int j=1;
for(int i=0; i<wave_devices; i++)
{
if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
== MMSYSERR_NOERROR)
{
sprintf(sz_dev_name,psz_device_name_fmt,caps.szPname,
caps.wMid,
caps.wPid
);
p_item->ppsz_list[j] = strdup( sz_dev_name );
p_item->ppsz_list_text[j] = FromLocaleDup( sz_dev_name );
p_item->i_list++;
j++;
}
}
p_item->ppsz_list[j] = NULL;
p_item->ppsz_list_text[j] = NULL;
/* Signal change to the interface */
p_item->b_dirty = VLC_TRUE;
return VLC_SUCCESS;
}
/*
convert devicename to device ID for output
if device not found return WAVE_MAPPER, so let
windows decide which prefered audio device
should be used.
*/
static uint32_t findDeviceID(char *psz_device_name)
{
if(!psz_device_name)
return WAVE_MAPPER;
uint32_t wave_devices = waveOutGetNumDevs();
WAVEOUTCAPS caps;
char sz_dev_name[MAXPNAMELEN+32];
for(uint32_t i=0; i<wave_devices; i++)
{
if(waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS))
== MMSYSERR_NOERROR)
{
sprintf(sz_dev_name,psz_device_name_fmt,caps.szPname,
caps.wMid,
caps.wPid
);
if(!stricmp(sz_dev_name,psz_device_name))
return i;
}
}
return WAVE_MAPPER;
}
This source diff could not be displayed because it is too large. You can view the blob instead.
VLC_ICON ICON "vlc48x48.ico"
#ifndef VERSION_NUMBER
#define VERSION_NUMBER 0,0,0,0
#endif
#ifndef VERSION
#define VERSION 0.0.0
#endif
#define STRINGIFY( z ) UGLY_KLUDGE( z )
#define UGLY_KLUDGE( z ) #z
1 VERSIONINFO
FILETYPE 1
FILEOS 4
PRODUCTVERSION VERSION_NUMBER
FILEVERSION VERSION_NUMBER
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904E4"
BEGIN
VALUE "CompanyName", "VideoLAN Team"
VALUE "FileVersion", STRINGIFY( VERSION )
VALUE "FileDescription", "VLC media player"
VALUE "LegalCopyright", "(c) 1996-2006 VideoLAN"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
VLC_ICON ICON "../../share/vlc48x48.ico"
#ifndef VERSION_NUMBER
#define VERSION_NUMBER 0,0,0,0
#endif
#ifndef VERSION
#define VERSION 0.0.0
#endif
#define STRINGIFY( z ) UGLY_KLUDGE( z )
#define UGLY_KLUDGE( z ) #z
1 VERSIONINFO
FILETYPE 1
FILEOS 4
PRODUCTVERSION VERSION_NUMBER
FILEVERSION VERSION_NUMBER
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904E4"
BEGIN
VALUE "CompanyName", "VideoLAN Team"
VALUE "FileVersion", STRINGIFY( VERSION )
VALUE "FileDescription", "VLC media player"
VALUE "LegalCopyright", "(c) 1996-2006 VideoLAN"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment