Commit 21e2557b authored by Denis Charmet's avatar Denis Charmet

Remove aout_Packet from directsound audio output

parent 8cbd52ac
......@@ -35,25 +35,10 @@
#include <vlc_plugin.h>
#include <vlc_aout.h>
#include <vlc_charset.h>
#include <vlc_atomic.h>
#include "windows_audio_common.h"
/*****************************************************************************
* notification_thread_t: DirectX event thread
*****************************************************************************/
typedef struct notification_thread_t
{
int i_frame_size; /* size in bytes of one frame */
int i_write_slot; /* current write position in our circular buffer */
mtime_t start_date;
HANDLE event;
vlc_thread_t thread;
vlc_atomic_t abort;
} notification_thread_t;
#define DS_BUF_SIZE (1024*1024)
/*****************************************************************************
* aout_sys_t: directx audio output method descriptor
......@@ -63,23 +48,24 @@ typedef struct notification_thread_t
*****************************************************************************/
struct aout_sys_t
{
aout_packet_t packet;
HINSTANCE hdsound_dll; /* handle of the opened dsound dll */
LPDIRECTSOUND p_dsobject; /* main Direct Sound object */
LPDIRECTSOUNDBUFFER p_dsbuffer; /* the sound buffer we use (direct sound
* takes care of mixing all the
* secondary buffers into the primary) */
LPDIRECTSOUNDNOTIFY p_notify;
HANDLE hnotify_evt;
struct
{
LONG volume;
float volume;
LONG mb;
bool mute;
} volume;
notification_thread_t notif; /* DirectSoundThread id */
int i_frame_size; /* Size in bytes of one frame */
int i_bytes_per_sample; /* Size in bytes of one frame */
int i_rate; /* Sample rate */
int i_speaker_setup; /* Speaker setup override */
......@@ -87,6 +73,8 @@ struct aout_sys_t
uint8_t chan_table[AOUT_CHAN_MAX];
uint32_t i_channel_mask;
vlc_fourcc_t format;
size_t i_write;
};
/*****************************************************************************
......@@ -95,18 +83,20 @@ struct aout_sys_t
static int Open( vlc_object_t * );
static void Close( vlc_object_t * );
static void Stop( audio_output_t * );
static void Play ( audio_output_t *, block_t * );
static int VolumeSet ( audio_output_t *, float );
static int MuteSet ( audio_output_t *, bool );
static void Play( audio_output_t *, block_t * );
static int VolumeSet( audio_output_t *, float );
static int MuteSet( audio_output_t *, bool );
static void Flush( audio_output_t *, bool );
static void Pause( audio_output_t *, bool, mtime_t );
static int TimeGet( audio_output_t *, mtime_t *);
/* local functions */
static void Probe( audio_output_t *, const audio_sample_format_t * );
static int InitDirectSound ( audio_output_t * );
static int CreateDSBuffer ( audio_output_t *, int, int, int, int, int, bool );
static int CreateDSBuffer ( audio_output_t *, int, int, int, int, bool );
static int CreateDSBufferPCM ( audio_output_t *, vlc_fourcc_t*, int, int, bool );
static void DestroyDSBuffer ( audio_output_t * );
static void* DirectSoundThread( void * );
static int FillBuffer ( audio_output_t *, int, block_t * );
static int FillBuffer ( audio_output_t *, block_t * );
static int ReloadDirectXDevices( vlc_object_t *, const char *,
char ***, char *** );
......@@ -145,7 +135,7 @@ vlc_module_begin ()
add_string( "directx-audio-speaker", "Windows default",
SPEAKER_TEXT, SPEAKER_LONGTEXT, true )
change_string_list( speaker_list, speaker_list )
add_integer( "directx-volume", DSBVOLUME_MAX,
add_float( "directx-volume", 1.0f,
VOLUME_TEXT, VOLUME_LONGTEXT, true )
change_integer_range( DSBVOLUME_MIN, DSBVOLUME_MAX )
......@@ -216,19 +206,15 @@ static int Start( audio_output_t *p_aout, audio_sample_format_t *restrict fmt )
/* Calculate the frame size in bytes */
fmt->i_bytes_per_frame = AOUT_SPDIF_SIZE;
fmt->i_frame_length = A52_FRAME_NB;
p_aout->sys->i_frame_size = fmt->i_bytes_per_frame;
if( CreateDSBuffer( p_aout, VLC_CODEC_SPDIFL,
fmt->i_physical_channels,
aout_FormatNbChannels( fmt ), fmt->i_rate,
p_aout->sys->i_frame_size, false )
aout_FormatNbChannels( fmt ), fmt->i_rate, false )
!= VLC_SUCCESS )
{
msg_Err( p_aout, "cannot open directx audio device" );
goto error;
}
aout_PacketInit( p_aout, &p_aout->sys->packet, A52_FRAME_NB, fmt );
}
else
{
......@@ -254,37 +240,19 @@ static int Start( audio_output_t *p_aout, audio_sample_format_t *restrict fmt )
msg_Err( p_aout, "cannot open directx audio device" );
goto error;
}
/* Calculate the frame size in bytes */
aout_PacketInit( p_aout, &p_aout->sys->packet, fmt->i_rate / 20, fmt );
}
p_aout->sys->i_write = 0;
/* Force volume update in thread. TODO: use session volume on Vista+ */
p_aout->sys->volume.volume = p_aout->sys->volume.mb;
/* Now we need to setup our DirectSound play notification structure */
vlc_atomic_set(&p_aout->sys->notif.abort, 0);
p_aout->sys->notif.event = CreateEvent( 0, FALSE, FALSE, 0 );
if( unlikely(p_aout->sys->notif.event == NULL) )
abort();
p_aout->sys->notif.i_frame_size = p_aout->sys->i_frame_size;
/* Force volume update */
VolumeSet( p_aout, p_aout->sys->volume.volume );
MuteSet( p_aout, p_aout->sys->volume.mute );
/* then launch the notification thread */
msg_Dbg( p_aout, "creating DirectSoundThread" );
if( vlc_clone( &p_aout->sys->notif.thread, DirectSoundThread, p_aout,
VLC_THREAD_PRIORITY_HIGHEST ) )
{
msg_Err( p_aout, "cannot create DirectSoundThread" );
CloseHandle( p_aout->sys->notif.event );
p_aout->sys->notif.event = NULL;
aout_PacketDestroy( p_aout );
goto error;
}
p_aout->time_get = aout_PacketTimeGet;
p_aout->time_get = TimeGet;
p_aout->play = Play;
p_aout->pause = NULL;
p_aout->flush = aout_PacketFlush;
p_aout->pause = Pause;
p_aout->flush = Flush;
return VLC_SUCCESS;
error:
......@@ -479,8 +447,7 @@ static void Probe( audio_output_t * p_aout, const audio_sample_format_t *fmt )
{
if( CreateDSBuffer( p_aout, VLC_CODEC_SPDIFL,
fmt->i_physical_channels,
aout_FormatNbChannels( fmt ), fmt->i_rate,
AOUT_SPDIF_SIZE, true )
aout_FormatNbChannels( fmt ), fmt->i_rate, true )
== VLC_SUCCESS )
{
msg_Dbg( p_aout, "device supports A/52 over S/PDIF" );
......@@ -511,26 +478,29 @@ static void Probe( audio_output_t * p_aout, const audio_sample_format_t *fmt )
*****************************************************************************/
static void Play( audio_output_t *p_aout, block_t *p_buffer )
{
/* get the playing date of the first aout buffer */
p_aout->sys->notif.start_date = p_buffer->i_pts;
/* fill in the first samples (zeroes) */
FillBuffer( p_aout, 0, NULL );
/* wake up the audio output thread */
SetEvent( p_aout->sys->notif.event );
aout_PacketPlay( p_aout, p_buffer );
p_aout->play = aout_PacketPlay;
if( FillBuffer( p_aout, p_buffer ) == VLC_SUCCESS )
{
/* start playing the buffer */
HRESULT dsresult = IDirectSoundBuffer_Play( p_aout->sys->p_dsbuffer,
0, 0, DSBPLAY_LOOPING );
if( dsresult == DSERR_BUFFERLOST )
{
IDirectSoundBuffer_Restore( p_aout->sys->p_dsbuffer );
dsresult = IDirectSoundBuffer_Play( p_aout->sys->p_dsbuffer,
0, 0, DSBPLAY_LOOPING );
}
if( dsresult != DS_OK )
msg_Err( p_aout, "cannot start playing buffer" );
}
}
static int VolumeSet( audio_output_t *p_aout, float vol )
static int VolumeSet( audio_output_t *p_aout, float volume )
{
aout_sys_t *sys = p_aout->sys;
int ret = 0;
/* Convert UI volume to linear factor (cube) */
vol = vol * vol * vol;
float vol = volume * volume * volume;
/* millibels from linear amplification */
LONG mb = lroundf(2000.f * log10f(vol));
......@@ -546,28 +516,31 @@ static int VolumeSet( audio_output_t *p_aout, float vol )
mb = DSBVOLUME_MIN;
sys->volume.mb = mb;
if (!sys->volume.mute)
InterlockedExchange(&sys->volume.volume, mb);
sys->volume.volume = volume;
if( !sys->volume.mute && sys->p_dsbuffer &&
IDirectSoundBuffer_SetVolume( sys->p_dsbuffer, mb ) != DS_OK )
return -1;
/* Convert back to UI volume */
vol = cbrtf(powf(10.f, ((float)mb) / 2000.f));
aout_VolumeReport( p_aout, vol );
aout_VolumeReport( p_aout, volume );
if( var_InheritBool( p_aout, "volume-save" ) )
config_PutInt( p_aout, "directx-volume", mb );
config_PutFloat( p_aout, "directx-volume", volume );
return ret;
}
static int MuteSet( audio_output_t *p_aout, bool mute )
{
HRESULT res = DS_OK;
aout_sys_t *sys = p_aout->sys;
sys->volume.mute = mute;
InterlockedExchange(&sys->volume.volume,
mute ? DSBVOLUME_MIN : sys->volume.mb);
if( sys->p_dsbuffer )
res = IDirectSoundBuffer_SetVolume( sys->p_dsbuffer,
mute? DSBVOLUME_MIN : sys->volume.mb );
aout_MuteReport( p_aout, mute );
return 0;
return (res != DS_OK);
}
/*****************************************************************************
......@@ -576,27 +549,19 @@ static int MuteSet( audio_output_t *p_aout, bool mute )
static void Stop( audio_output_t *p_aout )
{
aout_sys_t *p_sys = p_aout->sys;
msg_Dbg( p_aout, "closing audio device" );
/* kill the position notification thread, if any */
if( p_sys->notif.event != NULL )
{
vlc_atomic_set(&p_aout->sys->notif.abort, 1);
/* wake up the audio thread if needed */
if( p_aout->play == Play )
SetEvent( p_sys->notif.event );
vlc_join( p_sys->notif.thread, NULL );
CloseHandle( p_sys->notif.event );
aout_PacketDestroy( p_aout );
}
if( p_sys->p_notify )
IDirectSoundNotify_Release(p_sys->p_notify );
p_sys->p_notify = NULL;
IDirectSoundBuffer_Stop( p_sys->p_dsbuffer );
/* release the secondary buffer */
DestroyDSBuffer( p_aout );
/* finally release the DirectSound object */
if( p_sys->p_dsobject ) IDirectSound_Release( p_sys->p_dsobject );
if( p_sys->p_dsobject )
IDirectSound_Release( p_sys->p_dsobject );
}
/*****************************************************************************
......@@ -675,7 +640,7 @@ static int InitDirectSound( audio_output_t *p_aout )
*****************************************************************************/
static int CreateDSBuffer( audio_output_t *p_aout, int i_format,
int i_channels, int i_nb_channels, int i_rate,
int i_bytes_per_frame, bool b_probe )
bool b_probe )
{
WAVEFORMATEXTENSIBLE waveformat;
DSBUFFERDESC dsbdesc;
......@@ -723,14 +688,16 @@ static int CreateDSBuffer( audio_output_t *p_aout, int i_format,
waveformat.Format.nAvgBytesPerSec =
waveformat.Format.nSamplesPerSec * waveformat.Format.nBlockAlign;
p_aout->sys->i_bytes_per_sample = waveformat.Format.nBlockAlign;
p_aout->sys->format = i_format;
/* Then fill in the direct sound descriptor */
memset(&dsbdesc, 0, sizeof(DSBUFFERDESC));
dsbdesc.dwSize = sizeof(DSBUFFERDESC);
dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2/* Better position accuracy */
dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 /* Better position accuracy */
| DSBCAPS_GLOBALFOCUS /* Allows background playing */
| DSBCAPS_CTRLVOLUME; /* Allows volume control */
| DSBCAPS_CTRLVOLUME /* Allows volume control */
| DSBCAPS_CTRLPOSITIONNOTIFY; /* Allow position notifications */
/* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */
if( i_nb_channels <= 2 )
......@@ -747,7 +714,7 @@ static int CreateDSBuffer( audio_output_t *p_aout, int i_format,
dsbdesc.dwFlags |= DSBCAPS_LOCHARDWARE;
}
dsbdesc.dwBufferBytes = FRAMES_NUM * i_bytes_per_frame; /* buffer size */
dsbdesc.dwBufferBytes = DS_BUF_SIZE; /* buffer size */
dsbdesc.lpwfxFormat = (WAVEFORMATEX *)&waveformat;
if FAILED( IDirectSound_CreateSoundBuffer(
......@@ -781,7 +748,7 @@ static int CreateDSBuffer( audio_output_t *p_aout, int i_format,
return VLC_SUCCESS;
}
p_aout->sys->i_frame_size = i_bytes_per_frame;
p_aout->sys->i_rate = i_rate;
p_aout->sys->i_channel_mask = waveformat.dwChannelMask;
p_aout->sys->chans_to_reorder =
aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
......@@ -792,6 +759,18 @@ static int CreateDSBuffer( audio_output_t *p_aout, int i_format,
msg_Dbg( p_aout, "channel reordering needed" );
}
if( IDirectSoundBuffer_QueryInterface( p_aout->sys->p_dsbuffer,
&IID_IDirectSoundNotify,
(void **) &p_aout->sys->p_notify )
!= DS_OK )
{
msg_Err(p_aout, "Couldn't query IDirectSoundNotify");
p_aout->sys->p_notify = NULL;
}
FillBuffer(p_aout,NULL);
return VLC_SUCCESS;
}
......@@ -810,13 +789,11 @@ static int CreateDSBufferPCM( audio_output_t *p_aout, vlc_fourcc_t *i_format,
if( !var_GetBool( p_aout, "directx-audio-float32" ) ||
i_nb_channels > 2 ||
CreateDSBuffer( p_aout, VLC_CODEC_FL32,
i_channels, i_nb_channels, i_rate,
(i_rate / 20) * 4 * i_nb_channels, b_probe )
i_channels, i_nb_channels, i_rate, b_probe )
!= VLC_SUCCESS )
{
if ( CreateDSBuffer( p_aout, VLC_CODEC_S16N,
i_channels, i_nb_channels, i_rate,
(i_rate / 20) * 2 * i_nb_channels, b_probe )
i_channels, i_nb_channels, i_rate, b_probe )
!= VLC_SUCCESS )
{
return VLC_EGENERIC;
......@@ -853,10 +830,11 @@ static void DestroyDSBuffer( audio_output_t *p_aout )
*****************************************************************************
* Returns VLC_SUCCESS on success.
*****************************************************************************/
static int FillBuffer( audio_output_t *p_aout, int i_frame, block_t *p_buffer )
static int FillBuffer( audio_output_t *p_aout, block_t *p_buffer )
{
aout_sys_t *p_sys = p_aout->sys;
notification_thread_t *p_notif = &p_sys->notif;
size_t towrite = (p_buffer)?p_buffer->i_buffer:DS_BUF_SIZE;
void *p_write_position, *p_wrap_around;
unsigned long l_bytes1, l_bytes2;
HRESULT dsresult;
......@@ -864,20 +842,20 @@ static int FillBuffer( audio_output_t *p_aout, int i_frame, block_t *p_buffer )
/* Before copying anything, we have to lock the buffer */
dsresult = IDirectSoundBuffer_Lock(
p_sys->p_dsbuffer, /* DS buffer */
i_frame * p_notif->i_frame_size, /* Start offset */
p_notif->i_frame_size, /* Number of bytes */
p_aout->sys->i_write, /* Start offset */
towrite, /* Number of bytes */
&p_write_position, /* Address of lock start */
&l_bytes1, /* Count of bytes locked before wrap around */
&p_wrap_around, /* Buffer address (if wrap around) */
&l_bytes2, /* Count of bytes after wrap around */
0 ); /* Flags */
0 ); /* Flags: DSBLOCK_FROMWRITECURSOR is buggy */
if( dsresult == DSERR_BUFFERLOST )
{
IDirectSoundBuffer_Restore( p_sys->p_dsbuffer );
dsresult = IDirectSoundBuffer_Lock(
p_sys->p_dsbuffer,
i_frame * p_notif->i_frame_size,
p_notif->i_frame_size,
p_aout->sys->i_write,
towrite,
&p_write_position,
&l_bytes1,
&p_wrap_around,
......@@ -904,6 +882,8 @@ static int FillBuffer( audio_output_t *p_aout, int i_frame, block_t *p_buffer )
p_sys->format );
memcpy( p_write_position, p_buffer->p_buffer, l_bytes1 );
if( l_bytes1 < p_buffer->i_buffer)
memcpy(p_wrap_around, p_buffer->p_buffer + l_bytes1, l_bytes2);
block_Release( p_buffer );
}
......@@ -911,117 +891,10 @@ static int FillBuffer( audio_output_t *p_aout, int i_frame, block_t *p_buffer )
IDirectSoundBuffer_Unlock( p_sys->p_dsbuffer, p_write_position, l_bytes1,
p_wrap_around, l_bytes2 );
p_notif->i_write_slot = (i_frame + 1) % FRAMES_NUM;
return VLC_SUCCESS;
}
/*****************************************************************************
* DirectSoundThread: this thread will capture play notification events.
*****************************************************************************
* We use this thread to emulate a callback mechanism. The thread probes for
* event notification and fills up the DS secondary buffer when needed.
*****************************************************************************/
static void* DirectSoundThread( void *data )
{
audio_output_t *p_aout = (audio_output_t *)data;
notification_thread_t *p_notif = &p_aout->sys->notif;
mtime_t last_time;
msg_Dbg( p_aout, "DirectSoundThread ready" );
/* Wait here until Play() is called */
WaitForSingleObject( p_notif->event, INFINITE );
if( !vlc_atomic_get( &p_notif->abort) )
{
HRESULT dsresult;
mwait( p_notif->start_date - AOUT_MAX_PTS_ADVANCE / 2 );
/* start playing the buffer */
dsresult = IDirectSoundBuffer_Play( p_aout->sys->p_dsbuffer,
0, /* Unused */
0, /* Unused */
DSBPLAY_LOOPING ); /* Flags */
if( dsresult == DSERR_BUFFERLOST )
{
IDirectSoundBuffer_Restore( p_aout->sys->p_dsbuffer );
dsresult = IDirectSoundBuffer_Play(
p_aout->sys->p_dsbuffer,
0, /* Unused */
0, /* Unused */
DSBPLAY_LOOPING ); /* Flags */
}
if( dsresult != DS_OK )
{
msg_Err( p_aout, "cannot start playing buffer" );
}
}
last_time = mdate();
while( !vlc_atomic_get( &p_notif->abort ) )
{
DWORD l_read;
int l_queued = 0, l_free_slots;
unsigned i_frame_siz = p_aout->sys->packet.samples;
mtime_t mtime = mdate();
int i;
/* Update volume if required */
LONG volume = InterlockedExchange( &p_aout->sys->volume.volume, -1 );
if( unlikely(volume != -1) )
IDirectSoundBuffer_SetVolume( p_aout->sys->p_dsbuffer, volume );
/*
* Fill in as much audio data as we can in our circular buffer
*/
/* Find out current play position */
if FAILED( IDirectSoundBuffer_GetCurrentPosition(
p_aout->sys->p_dsbuffer, &l_read, NULL ) )
{
msg_Err( p_aout, "GetCurrentPosition() failed!" );
l_read = 0;
}
/* Detect underruns */
if( l_queued && mtime - last_time >
INT64_C(1000000) * l_queued / p_aout->sys->packet.format.i_rate )
{
msg_Dbg( p_aout, "detected underrun!" );
}
last_time = mtime;
p_sys->i_write += towrite;
p_sys->i_write %= DS_BUF_SIZE;
/* Try to fill in as many frame buffers as possible */
l_read /= (p_aout->sys->packet.format.i_bytes_per_frame /
p_aout->sys->packet.format.i_frame_length);
l_queued = p_notif->i_write_slot * i_frame_siz - l_read;
if( l_queued < 0 ) l_queued += (i_frame_siz * FRAMES_NUM);
l_free_slots = (FRAMES_NUM * i_frame_siz - l_queued) / i_frame_siz;
for( i = 0; i < l_free_slots; i++ )
{
block_t *p_buffer = aout_PacketNext( p_aout,
mtime + INT64_C(1000000) * (i * i_frame_siz + l_queued) /
p_aout->sys->packet.format.i_rate );
/* If there is no audio data available and we have some buffered
* already, then just wait for the next time */
if( !p_buffer && (i || l_queued / i_frame_siz) ) break;
if( FillBuffer( p_aout, p_notif->i_write_slot % FRAMES_NUM,
p_buffer ) != VLC_SUCCESS ) break;
}
/* Sleep a reasonable amount of time */
l_queued += (i * i_frame_siz);
msleep( INT64_C(1000000) * l_queued / p_aout->sys->packet.format.i_rate / 2 );
}
/* make sure the buffer isn't playing */
IDirectSoundBuffer_Stop( p_aout->sys->p_dsbuffer );
msg_Dbg( p_aout, "DirectSoundThread exiting" );
return NULL;
return VLC_SUCCESS;
}
typedef struct
......@@ -1106,11 +979,19 @@ static int Open(vlc_object_t *obj)
aout->mute_set = MuteSet;
/* Volume */
LONG mb = var_InheritInteger(aout, "directx-volume");
sys->volume.mb = mb;
aout_VolumeReport(aout, cbrtf(powf(10.f, ((float)mb) / 2000.f)));
sys->volume.volume = var_InheritFloat(aout, "directx-volume");
aout_VolumeReport(aout, sys->volume.volume );
MuteSet(aout, var_InheritBool(aout, "mute"));
sys->hnotify_evt = CreateEvent(NULL, FALSE, TRUE, NULL);
if( !sys->hnotify_evt )
{
msg_Err(aout, "cannot create Event");
FreeLibrary(sys->hdsound_dll);
free(sys);
return VLC_EGENERIC;
}
return VLC_SUCCESS;
}
......@@ -1119,6 +1000,67 @@ static void Close(vlc_object_t *obj)
audio_output_t *aout = (audio_output_t *)obj;
aout_sys_t *sys = aout->sys;
CloseHandle(sys->hnotify_evt);
FreeLibrary(sys->hdsound_dll); /* free DSOUND.DLL */
free(sys);
}
static void Flush ( audio_output_t * aout, bool drain )
{
aout_sys_t *sys = aout->sys;
size_t read;
if( drain )
{
if( sys->p_notify )
{
DSBPOSITIONNOTIFY notif = {.dwOffset = aout->sys->i_write, .hEventNotify = sys->hnotify_evt } ;
if( IDirectSoundNotify_SetNotificationPositions( sys->p_notify, 1, &notif ) == DS_OK )
{
WaitForSingleObject( sys->hnotify_evt, INFINITE );
IDirectSoundBuffer_Stop( aout->sys->p_dsbuffer );
}
}
else
while( IDirectSoundBuffer_GetCurrentPosition( aout->sys->p_dsbuffer,(LPDWORD) &read, NULL) == DS_OK )
{
read %= DS_BUF_SIZE;
if( read == aout->sys->i_write )
break;
msleep(10000);
}
}
else
{
IDirectSoundBuffer_Stop( aout->sys->p_dsbuffer );
IDirectSoundBuffer_SetCurrentPosition( aout->sys->p_dsbuffer,
aout->sys->i_write );
}
}
static void Pause( audio_output_t * aout, bool pause, mtime_t date )
{
(void) date;
if( pause )
IDirectSoundBuffer_Stop( aout->sys->p_dsbuffer );
else
IDirectSoundBuffer_Play( aout->sys->p_dsbuffer, 0, 0, DSBPLAY_LOOPING );
}
static int TimeGet( audio_output_t * aout, mtime_t * delay )
{
uint32_t read;
mtime_t size;
if( IDirectSoundBuffer_GetCurrentPosition( aout->sys->p_dsbuffer, (LPDWORD) &read, NULL) != DS_OK )
return 1;
read %= DS_BUF_SIZE;
size = (mtime_t)aout->sys->i_write - (mtime_t) read;
if( size < 0 )
size += DS_BUF_SIZE;
*delay = ( size / aout->sys->i_bytes_per_sample ) * CLOCK_FREQ / aout->sys->i_rate;
return 0;
}
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