Commit c19df783 authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

aout: separate time and play callbacks

parent f492f85c
...@@ -150,7 +150,14 @@ struct audio_output ...@@ -150,7 +150,14 @@ struct audio_output
/**< Stops the existing stream (optional, may be NULL). /**< Stops the existing stream (optional, may be NULL).
* \note A stream must have been started when called. * \note A stream must have been started when called.
*/ */
void (*play)(audio_output_t *, block_t *, mtime_t *); int (*time_get)(audio_output_t *, mtime_t *write_pts);
/**< Estimates the date/time of the playback buffer write offset
* (optional, may be NULL). The read offset is not returned since it is
* always implicitly equal to the current time (mdate()).
* \param write_pts timestamp of the write offset [OUT]
* \note A stream must have been started when called.
*/
void (*play)(audio_output_t *, block_t *);
/**< Queues a block of samples for playback (mandatory, cannot be NULL). /**< Queues a block of samples for playback (mandatory, cannot be NULL).
* \note A stream must have been started when called. * \note A stream must have been started when called.
*/ */
...@@ -311,7 +318,6 @@ typedef struct ...@@ -311,7 +318,6 @@ typedef struct
aout_fifo_t partial; /**< Audio blocks before packetization */ aout_fifo_t partial; /**< Audio blocks before packetization */
aout_fifo_t fifo; /**< Packetized audio blocks */ aout_fifo_t fifo; /**< Packetized audio blocks */
mtime_t pause_date; /**< Date when paused or VLC_TS_INVALID */ mtime_t pause_date; /**< Date when paused or VLC_TS_INVALID */
mtime_t time_report; /**< Desynchronization estimate or VLC_TS_INVALID */
unsigned samples; /**< Samples per packet */ unsigned samples; /**< Samples per packet */
bool starving; /**< Whether currently starving (to limit error messages) */ bool starving; /**< Whether currently starving (to limit error messages) */
} aout_packet_t; } aout_packet_t;
...@@ -319,7 +325,8 @@ typedef struct ...@@ -319,7 +325,8 @@ typedef struct
VLC_DEPRECATED void aout_PacketInit(audio_output_t *, aout_packet_t *, unsigned, const audio_sample_format_t *); VLC_DEPRECATED void aout_PacketInit(audio_output_t *, aout_packet_t *, unsigned, const audio_sample_format_t *);
VLC_DEPRECATED void aout_PacketDestroy(audio_output_t *); VLC_DEPRECATED void aout_PacketDestroy(audio_output_t *);
VLC_DEPRECATED void aout_PacketPlay(audio_output_t *, block_t *, mtime_t *); VLC_DEPRECATED int aout_PacketTimeGet(audio_output_t *, mtime_t *);
VLC_DEPRECATED void aout_PacketPlay(audio_output_t *, block_t *);
VLC_DEPRECATED void aout_PacketPause(audio_output_t *, bool, mtime_t); VLC_DEPRECATED void aout_PacketPause(audio_output_t *, bool, mtime_t);
VLC_DEPRECATED void aout_PacketFlush(audio_output_t *, bool); VLC_DEPRECATED void aout_PacketFlush(audio_output_t *, bool);
......
...@@ -42,11 +42,10 @@ vlc_module_end () ...@@ -42,11 +42,10 @@ vlc_module_end ()
#define A52_FRAME_NB 1536 #define A52_FRAME_NB 1536
static void Play( audio_output_t *aout, block_t *block, mtime_t *drift ) static void Play(audio_output_t *aout, block_t *block)
{ {
block_Release( block ); block_Release( block );
(void) aout; (void) aout;
(void) drift;
} }
static int Start(audio_output_t *aout, audio_sample_format_t *restrict fmt) static int Start(audio_output_t *aout, audio_sample_format_t *restrict fmt)
...@@ -68,6 +67,7 @@ static int Open(vlc_object_t *obj) ...@@ -68,6 +67,7 @@ static int Open(vlc_object_t *obj)
audio_output_t *aout = (audio_output_t *)obj; audio_output_t *aout = (audio_output_t *)obj;
aout->start = Start; aout->start = Start;
aout->time_get = NULL;
aout->play = Play; aout->play = Play;
aout->pause = NULL; aout->pause = NULL;
aout->flush = NULL; aout->flush = NULL;
......
...@@ -153,7 +153,8 @@ static int DeviceChanged (vlc_object_t *obj, const char *varname, ...@@ -153,7 +153,8 @@ static int DeviceChanged (vlc_object_t *obj, const char *varname,
return VLC_SUCCESS; return VLC_SUCCESS;
} }
static void Play (audio_output_t *, block_t *, mtime_t *); static int TimeGet (audio_output_t *aout, mtime_t *);
static void Play (audio_output_t *, block_t *);
static void Pause (audio_output_t *, bool, mtime_t); static void Pause (audio_output_t *, bool, mtime_t);
static void PauseDummy (audio_output_t *, bool, mtime_t); static void PauseDummy (audio_output_t *, bool, mtime_t);
static void Flush (audio_output_t *, bool); static void Flush (audio_output_t *, bool);
...@@ -508,6 +509,7 @@ static int Start (audio_output_t *aout, audio_sample_format_t *restrict fmt) ...@@ -508,6 +509,7 @@ static int Start (audio_output_t *aout, audio_sample_format_t *restrict fmt)
} }
sys->format = *fmt; sys->format = *fmt;
aout->time_get = TimeGet;
aout->play = Play; aout->play = Play;
if (snd_pcm_hw_params_can_pause (hw)) if (snd_pcm_hw_params_can_pause (hw))
aout->pause = Pause; aout->pause = Pause;
...@@ -540,11 +542,33 @@ error: ...@@ -540,11 +542,33 @@ error:
return VLC_EGENERIC; return VLC_EGENERIC;
} }
static int TimeGet (audio_output_t *aout, mtime_t *restrict pts)
{
aout_sys_t *sys = aout->sys;
snd_pcm_t *pcm = sys->pcm;
snd_pcm_status_t *status;
int val;
snd_pcm_status_alloca (&status);
val = snd_pcm_status (pcm, status);
if (val < 0)
{
msg_Err (aout, "cannot get status: %s", snd_strerror (val));
return -1;
}
if (snd_pcm_status_get_state (status) != SND_PCM_STATE_RUNNING)
return -1;
snd_pcm_sframes_t frames = snd_pcm_status_get_delay (status);
*pts = mdate () + (frames * CLOCK_FREQ / sys->format.i_rate);
return 0;
}
/** /**
* Queues one audio buffer to the hardware. * Queues one audio buffer to the hardware.
*/ */
static void Play (audio_output_t *aout, block_t *block, static void Play (audio_output_t *aout, block_t *block)
mtime_t *restrict drift)
{ {
aout_sys_t *sys = aout->sys; aout_sys_t *sys = aout->sys;
...@@ -561,13 +585,12 @@ static void Play (audio_output_t *aout, block_t *block, ...@@ -561,13 +585,12 @@ static void Play (audio_output_t *aout, block_t *block,
if (val < 0) if (val < 0)
msg_Err (aout, "cannot get status: %s", snd_strerror (val)); msg_Err (aout, "cannot get status: %s", snd_strerror (val));
else else
if (snd_pcm_status_get_state (status) != SND_PCM_STATE_RUNNING)
{ {
snd_pcm_sframes_t frames = snd_pcm_status_get_delay (status); snd_pcm_sframes_t frames = snd_pcm_status_get_delay (status);
mtime_t delay = frames * CLOCK_FREQ / sys->format.i_rate; mtime_t delay = frames * CLOCK_FREQ / sys->format.i_rate;
delay += mdate () - block->i_pts;
if (snd_pcm_status_get_state (status) != SND_PCM_STATE_RUNNING) delay += mdate () - block->i_pts;
{
if (delay < 0) if (delay < 0)
{ {
if (sys->format.i_format != VLC_CODEC_SPDIFL) if (sys->format.i_format != VLC_CODEC_SPDIFL)
...@@ -593,9 +616,6 @@ static void Play (audio_output_t *aout, block_t *block, ...@@ -593,9 +616,6 @@ static void Play (audio_output_t *aout, block_t *block,
else else
msg_Dbg (aout, "starting late (%"PRId64" us)", delay); msg_Dbg (aout, "starting late (%"PRId64" us)", delay);
} }
else
*drift = delay;
}
/* TODO: better overflow handling */ /* TODO: better overflow handling */
/* TODO: no period wake ups */ /* TODO: no period wake ups */
......
...@@ -75,15 +75,13 @@ struct aout_sys_t ...@@ -75,15 +75,13 @@ struct aout_sys_t
bool mute; bool mute;
}; };
static void Play (audio_output_t *aout, block_t *block, static void Play (audio_output_t *aout, block_t *block)
mtime_t *restrict drift)
{ {
aout_sys_t *sys = aout->sys; aout_sys_t *sys = aout->sys;
sys->play (sys->opaque, block->p_buffer, block->i_nb_samples, sys->play (sys->opaque, block->p_buffer, block->i_nb_samples,
block->i_pts); block->i_pts);
block_Release (block); block_Release (block);
(void) drift;
} }
static void Pause (audio_output_t *aout, bool paused, mtime_t date) static void Pause (audio_output_t *aout, bool paused, mtime_t date)
...@@ -251,6 +249,7 @@ static int Open (vlc_object_t *obj) ...@@ -251,6 +249,7 @@ static int Open (vlc_object_t *obj)
aout->start = Start; aout->start = Start;
aout->stop = Stop; aout->stop = Stop;
aout->time_get = NULL;
aout->play = Play; aout->play = Play;
aout->pause = Pause; aout->pause = Pause;
aout->flush = Flush; aout->flush = Flush;
......
...@@ -123,6 +123,7 @@ static int Start( audio_output_t *aout, audio_sample_format_t *restrict fmt ) ...@@ -123,6 +123,7 @@ static int Start( audio_output_t *aout, audio_sample_format_t *restrict fmt )
fmt->i_physical_channels = AOUT_CHANS_STEREO; fmt->i_physical_channels = AOUT_CHANS_STEREO;
fmt->i_rate = 44100; fmt->i_rate = 44100;
aout_PacketInit(p_aout, &p_sys->packet, FRAME_SIZE, fmt); aout_PacketInit(p_aout, &p_sys->packet, FRAME_SIZE, fmt);
p_aout->time_get = aout_PacketTimeGet;
p_aout->play = aout_PacketPlay; p_aout->play = aout_PacketPlay;
p_aout->pause = aout_PacketPause; p_aout->pause = aout_PacketPause;
p_aout->flush = aout_PacketFlush; p_aout->flush = aout_PacketFlush;
......
...@@ -266,6 +266,7 @@ static int Start(audio_output_t *aout, audio_sample_format_t *restrict fmt) ...@@ -266,6 +266,7 @@ static int Start(audio_output_t *aout, audio_sample_format_t *restrict fmt)
} }
aout->sys = p_sys; aout->sys = p_sys;
aout->time_get = NULL;
aout->play = Play; aout->play = Play;
aout->pause = Pause; aout->pause = Pause;
...@@ -287,9 +288,8 @@ static void Stop(audio_output_t* p_aout) ...@@ -287,9 +288,8 @@ static void Stop(audio_output_t* p_aout)
} }
/* FIXME: lipsync */ /* FIXME: lipsync */
static void Play(audio_output_t* p_aout, block_t* p_buffer, mtime_t* restrict drift) static void Play(audio_output_t* p_aout, block_t* p_buffer)
{ {
VLC_UNUSED(drift);
aout_sys_t *p_sys = p_aout->sys; aout_sys_t *p_sys = p_aout->sys;
size_t length = 0; size_t length = 0;
......
...@@ -172,6 +172,7 @@ static int Start(audio_output_t *p_aout, audio_sample_format_t *restrict fmt) ...@@ -172,6 +172,7 @@ static int Start(audio_output_t *p_aout, audio_sample_format_t *restrict fmt)
p_sys->b_changed_mixing = false; p_sys->b_changed_mixing = false;
memset(p_sys->p_remainder_buffer, 0, sizeof(uint8_t) * BUFSIZE); memset(p_sys->p_remainder_buffer, 0, sizeof(uint8_t) * BUFSIZE);
p_aout->time_get = aout_PacketTimeGet;
p_aout->play = aout_PacketPlay; p_aout->play = aout_PacketPlay;
p_aout->pause = aout_PacketPause; p_aout->pause = aout_PacketPause;
p_aout->flush = aout_PacketFlush; p_aout->flush = aout_PacketFlush;
......
...@@ -96,7 +96,7 @@ struct aout_sys_t ...@@ -96,7 +96,7 @@ struct aout_sys_t
static int Open( vlc_object_t * ); static int Open( vlc_object_t * );
static void Close( vlc_object_t * ); static void Close( vlc_object_t * );
static void Stop( audio_output_t * ); static void Stop( audio_output_t * );
static void Play ( audio_output_t *, block_t *, mtime_t * ); static void Play ( audio_output_t *, block_t * );
static int VolumeSet ( audio_output_t *, float ); static int VolumeSet ( audio_output_t *, float );
static int MuteSet ( audio_output_t *, bool ); static int MuteSet ( audio_output_t *, bool );
...@@ -282,6 +282,7 @@ static int Start( audio_output_t *p_aout, audio_sample_format_t *restrict fmt ) ...@@ -282,6 +282,7 @@ static int Start( audio_output_t *p_aout, audio_sample_format_t *restrict fmt )
goto error; goto error;
} }
p_aout->time_get = aout_PacketTimeGet;
p_aout->play = Play; p_aout->play = Play;
p_aout->pause = aout_PacketPause; p_aout->pause = aout_PacketPause;
p_aout->flush = aout_PacketFlush; p_aout->flush = aout_PacketFlush;
...@@ -509,8 +510,7 @@ static void Probe( audio_output_t * p_aout, const audio_sample_format_t *fmt ) ...@@ -509,8 +510,7 @@ static void Probe( audio_output_t * p_aout, const audio_sample_format_t *fmt )
* we know the first buffer has been put in the aout fifo and we also * we know the first buffer has been put in the aout fifo and we also
* know its date. * know its date.
*****************************************************************************/ *****************************************************************************/
static void Play( audio_output_t *p_aout, block_t *p_buffer, static void Play( audio_output_t *p_aout, block_t *p_buffer )
mtime_t *restrict drift )
{ {
/* get the playing date of the first aout buffer */ /* get the playing date of the first aout buffer */
p_aout->sys->notif.start_date = p_buffer->i_pts; p_aout->sys->notif.start_date = p_buffer->i_pts;
...@@ -521,7 +521,7 @@ static void Play( audio_output_t *p_aout, block_t *p_buffer, ...@@ -521,7 +521,7 @@ static void Play( audio_output_t *p_aout, block_t *p_buffer,
/* wake up the audio output thread */ /* wake up the audio output thread */
SetEvent( p_aout->sys->notif.event ); SetEvent( p_aout->sys->notif.event );
aout_PacketPlay( p_aout, p_buffer, drift ); aout_PacketPlay( p_aout, p_buffer );
p_aout->play = aout_PacketPlay; p_aout->play = aout_PacketPlay;
} }
......
...@@ -71,7 +71,7 @@ static const int pi_channels_maps[CHANNELS_MAX+1] = ...@@ -71,7 +71,7 @@ static const int pi_channels_maps[CHANNELS_MAX+1] =
* Local prototypes. * Local prototypes.
*****************************************************************************/ *****************************************************************************/
static int Open ( vlc_object_t * ); static int Open ( vlc_object_t * );
static void Play ( audio_output_t *, block_t *, mtime_t * ); static void Play ( audio_output_t *, block_t * );
/***************************************************************************** /*****************************************************************************
* Module descriptor * Module descriptor
...@@ -154,6 +154,7 @@ static int Start( audio_output_t *p_aout, audio_sample_format_t *restrict fmt ) ...@@ -154,6 +154,7 @@ static int Start( audio_output_t *p_aout, audio_sample_format_t *restrict fmt )
return VLC_EGENERIC; return VLC_EGENERIC;
} }
p_aout->time_get = NULL;
p_aout->play = Play; p_aout->play = Play;
p_aout->pause = NULL; p_aout->pause = NULL;
p_aout->flush = NULL; p_aout->flush = NULL;
...@@ -296,8 +297,7 @@ static void Stop( audio_output_t *p_aout ) ...@@ -296,8 +297,7 @@ static void Stop( audio_output_t *p_aout )
/***************************************************************************** /*****************************************************************************
* Play: pretend to play a sound * Play: pretend to play a sound
*****************************************************************************/ *****************************************************************************/
static void Play( audio_output_t * p_aout, block_t *p_buffer, static void Play( audio_output_t * p_aout, block_t *p_buffer )
mtime_t *restrict drift )
{ {
if( fwrite( p_buffer->p_buffer, p_buffer->i_buffer, 1, if( fwrite( p_buffer->p_buffer, p_buffer->i_buffer, 1,
p_aout->sys->p_file ) != 1 ) p_aout->sys->p_file ) != 1 )
...@@ -312,7 +312,6 @@ static void Play( audio_output_t * p_aout, block_t *p_buffer, ...@@ -312,7 +312,6 @@ static void Play( audio_output_t * p_aout, block_t *p_buffer,
} }
block_Release( p_buffer ); block_Release( p_buffer );
(void) drift;
} }
static int Open(vlc_object_t *obj) static int Open(vlc_object_t *obj)
......
...@@ -132,6 +132,7 @@ static int Start( audio_output_t *p_aout, audio_sample_format_t *restrict fmt ) ...@@ -132,6 +132,7 @@ static int Start( audio_output_t *p_aout, audio_sample_format_t *restrict fmt )
// TODO add buffer size callback // TODO add buffer size callback
fmt->i_rate = jack_get_sample_rate( p_sys->p_jack_client ); fmt->i_rate = jack_get_sample_rate( p_sys->p_jack_client );
p_aout->time_get = aout_PacketTimeGet;
p_aout->play = aout_PacketPlay; p_aout->play = aout_PacketPlay;
p_aout->pause = aout_PacketPause; p_aout->pause = aout_PacketPause;
p_aout->flush = aout_PacketFlush; p_aout->flush = aout_PacketFlush;
......
...@@ -57,7 +57,7 @@ struct aout_sys_t ...@@ -57,7 +57,7 @@ struct aout_sys_t
*****************************************************************************/ *****************************************************************************/
static int Open ( vlc_object_t * ); static int Open ( vlc_object_t * );
static void Close ( vlc_object_t * ); static void Close ( vlc_object_t * );
static void Play ( audio_output_t *_p_aout, block_t *block, mtime_t * ); static void Play ( audio_output_t *_p_aout, block_t *block );
static ULONG APIENTRY KaiCallback ( PVOID, PVOID, ULONG ); static ULONG APIENTRY KaiCallback ( PVOID, PVOID, ULONG );
...@@ -195,6 +195,7 @@ static int Start ( audio_output_t *p_aout, audio_sample_format_t *fmt ) ...@@ -195,6 +195,7 @@ static int Start ( audio_output_t *p_aout, audio_sample_format_t *fmt )
p_sys->format = *fmt = format; p_sys->format = *fmt = format;
p_aout->time_get = aout_PacketTimeGet;
p_aout->play = Play; p_aout->play = Play;
p_aout->pause = aout_PacketPause; p_aout->pause = aout_PacketPause;
p_aout->flush = aout_PacketFlush; p_aout->flush = aout_PacketFlush;
...@@ -244,14 +245,13 @@ exit_kai_done : ...@@ -244,14 +245,13 @@ exit_kai_done :
/***************************************************************************** /*****************************************************************************
* Play: play a sound samples buffer * Play: play a sound samples buffer
*****************************************************************************/ *****************************************************************************/
static void Play (audio_output_t *p_aout, block_t *block, static void Play (audio_output_t *p_aout, block_t *block)
mtime_t *restrict drift)
{ {
aout_sys_t *p_sys = p_aout->sys; aout_sys_t *p_sys = p_aout->sys;
kaiPlay( p_sys->hkai ); kaiPlay( p_sys->hkai );
aout_PacketPlay( p_aout, block, drift ); aout_PacketPlay( p_aout, block );
} }
/***************************************************************************** /*****************************************************************************
......
...@@ -75,7 +75,8 @@ vlc_module_begin () ...@@ -75,7 +75,8 @@ vlc_module_begin ()
set_callbacks (Open, NULL) set_callbacks (Open, NULL)
vlc_module_end () vlc_module_end ()
static void Play (audio_output_t *, block_t *, mtime_t *); static int TimeGet (audio_output_t *, mtime_t *);
static void Play (audio_output_t *, block_t *);
static void Pause (audio_output_t *, bool, mtime_t); static void Pause (audio_output_t *, bool, mtime_t);
static void Flush (audio_output_t *, bool); static void Flush (audio_output_t *, bool);
static int VolumeSync (audio_output_t *); static int VolumeSync (audio_output_t *);
...@@ -219,6 +220,7 @@ static int Start (audio_output_t *aout, audio_sample_format_t *restrict fmt) ...@@ -219,6 +220,7 @@ static int Start (audio_output_t *aout, audio_sample_format_t *restrict fmt)
} }
/* Setup audio_output_t */ /* Setup audio_output_t */
aout->time_get = TimeGet;
aout->play = Play; aout->play = Play;
aout->pause = Pause; aout->pause = Pause;
aout->flush = Flush; aout->flush = Flush;
...@@ -311,38 +313,30 @@ static void Stop (audio_output_t *aout) ...@@ -311,38 +313,30 @@ static void Stop (audio_output_t *aout)
free (sys); free (sys);
} }
/** static int TimeGet (audio_output_t *aout, mtime_t *restrict pts)
* Queues one audio buffer to the hardware.
*/
static void Play (audio_output_t *aout, block_t *block,
mtime_t *restrict drift)
{ {
aout_sys_t *sys = aout->sys; aout_sys_t *sys = aout->sys;
int fd = sys->fd;
int delay; int delay;
if (ioctl (sys->fd, SNDCTL_DSP_GETODELAY, &delay) >= 0)
if (ioctl (sys->fd, SNDCTL_DSP_GETODELAY, &delay) < 0)
{ {
mtime_t latency = (delay * CLOCK_FREQ * sys->format.i_frame_length)
/ (sys->format.i_rate * sys->format.i_bytes_per_frame);
*drift = mdate () + latency - block->i_pts;
}
else
msg_Warn (aout, "cannot get delay: %m"); msg_Warn (aout, "cannot get delay: %m");
return -1;
if (sys->starting)
{ /* Start on time */
/* TODO: resync on pause resumption and underflow recovery */
mtime_t delta = -*drift;
if (delta > 0) {
msg_Dbg(aout, "deferring start (%"PRId64" us)", delta);
msleep(delta);
*drift = 0;
} else
msg_Warn(aout, "starting late (%"PRId64" us)", delta);
sys->starting = false;
} }
*pts = mdate () + ((delay * CLOCK_FREQ * sys->format.i_frame_length)
/ (sys->format.i_rate * sys->format.i_bytes_per_frame));
return 0;
}
/**
* Queues one audio buffer to the hardware.
*/
static void Play (audio_output_t *aout, block_t *block)
{
aout_sys_t *sys = aout->sys;
int fd = sys->fd;
while (block->i_buffer > 0) while (block->i_buffer > 0)
{ {
ssize_t bytes = write (fd, block->p_buffer, block->i_buffer); ssize_t bytes = write (fd, block->p_buffer, block->i_buffer);
......
...@@ -144,7 +144,6 @@ void aout_PacketInit (audio_output_t *aout, aout_packet_t *p, unsigned samples, ...@@ -144,7 +144,6 @@ void aout_PacketInit (audio_output_t *aout, aout_packet_t *p, unsigned samples,
aout_FifoInit (&p->partial, p->format.i_rate); aout_FifoInit (&p->partial, p->format.i_rate);
aout_FifoInit (&p->fifo, p->format.i_rate); aout_FifoInit (&p->fifo, p->format.i_rate);
p->pause_date = VLC_TS_INVALID; p->pause_date = VLC_TS_INVALID;
p->time_report = INT64_MIN;
p->samples = samples; p->samples = samples;
p->starving = true; p->starving = true;
} }
...@@ -158,25 +157,32 @@ void aout_PacketDestroy (audio_output_t *aout) ...@@ -158,25 +157,32 @@ void aout_PacketDestroy (audio_output_t *aout)
vlc_mutex_destroy (&p->lock); vlc_mutex_destroy (&p->lock);
} }
int aout_PacketTimeGet (audio_output_t *aout, mtime_t *restrict pts)
{
aout_packet_t *p = aout_packet (aout);
mtime_t time_report;
vlc_mutex_lock (&p->lock);
time_report = date_Get (&p->fifo.end_date);
vlc_mutex_unlock (&p->lock);
if (time_report == VLC_TS_INVALID)
return -1;
*pts = time_report;
return 0;
}
static block_t *aout_OutputSlice (audio_output_t *); static block_t *aout_OutputSlice (audio_output_t *);
void aout_PacketPlay (audio_output_t *aout, block_t *block, void aout_PacketPlay (audio_output_t *aout, block_t *block)
mtime_t *restrict drift)
{ {
aout_packet_t *p = aout_packet (aout); aout_packet_t *p = aout_packet (aout);
mtime_t time_report;
vlc_mutex_lock (&p->lock); vlc_mutex_lock (&p->lock);
aout_FifoPush (&p->partial, block); aout_FifoPush (&p->partial, block);
while ((block = aout_OutputSlice (aout)) != NULL) while ((block = aout_OutputSlice (aout)) != NULL)
aout_FifoPush (&p->fifo, block); aout_FifoPush (&p->fifo, block);
time_report = p->time_report;
p->time_report = INT64_MIN;
vlc_mutex_unlock (&p->lock); vlc_mutex_unlock (&p->lock);
if (time_report != INT64_MIN)
*drift = time_report;
} }
void aout_PacketPause (audio_output_t *aout, bool pause, mtime_t date) void aout_PacketPause (audio_output_t *aout, bool pause, mtime_t date)
...@@ -375,7 +381,6 @@ block_t *aout_PacketNext (audio_output_t *p_aout, mtime_t start_date) ...@@ -375,7 +381,6 @@ block_t *aout_PacketNext (audio_output_t *p_aout, mtime_t start_date)
"adjusting dates (%"PRId64" us)", delta); "adjusting dates (%"PRId64" us)", delta);
aout_FifoMoveDates (&p->partial, delta); aout_FifoMoveDates (&p->partial, delta);
aout_FifoMoveDates (p_fifo, delta); aout_FifoMoveDates (p_fifo, delta);
p->time_report = delta;
} }
vlc_mutex_unlock( &p->lock ); vlc_mutex_unlock( &p->lock );
return p_buffer; return p_buffer;
......
...@@ -539,7 +539,7 @@ static void *data_convert(block_t **pp) ...@@ -539,7 +539,7 @@ static void *data_convert(block_t **pp)
/** /**
* Queue one audio frame to the playback stream * Queue one audio frame to the playback stream
*/ */
static void Play(audio_output_t *aout, block_t *block, mtime_t *restrict drift) static void Play(audio_output_t *aout, block_t *block)
{ {
aout_sys_t *sys = aout->sys; aout_sys_t *sys = aout->sys;
pa_stream *s = sys->stream; pa_stream *s = sys->stream;
...@@ -581,7 +581,6 @@ static void Play(audio_output_t *aout, block_t *block, mtime_t *restrict drift) ...@@ -581,7 +581,6 @@ static void Play(audio_output_t *aout, block_t *block, mtime_t *restrict drift)
} }
pa_threaded_mainloop_unlock(sys->mainloop); pa_threaded_mainloop_unlock(sys->mainloop);
(void) drift;
} }
/** /**
...@@ -1030,6 +1029,7 @@ static int Open(vlc_object_t *obj) ...@@ -1030,6 +1029,7 @@ static int Open(vlc_object_t *obj)
aout->sys = sys; aout->sys = sys;
aout->start = Start; aout->start = Start;
aout->stop = Stop; aout->stop = Stop;
aout->time_get = NULL;
aout->play = Play; aout->play = Play;
aout->pause = Pause; aout->pause = Pause;
aout->flush = Flush; aout->flush = Flush;
......
...@@ -43,7 +43,8 @@ vlc_module_begin () ...@@ -43,7 +43,8 @@ vlc_module_begin ()
set_callbacks (Open, Close) set_callbacks (Open, Close)
vlc_module_end () vlc_module_end ()
static void Play (audio_output_t *, block_t *, mtime_t *); static int TimeGet (audio_output, mtime_t *);
static void Play (audio_output_t *, block_t *);
static void Pause (audio_output_t *, bool, mtime_t); static void Pause (audio_output_t *, bool, mtime_t);
static int VolumeSet (audio_output_t *, float); static int VolumeSet (audio_output_t *, float);
static int MuteSet (audio_output_t *, bool); static int MuteSet (audio_output_t *, bool);
...@@ -149,6 +150,7 @@ static int Start (audio_output_t *aout, audio_sample_format_t *restrict fmt) ...@@ -149,6 +150,7 @@ static int Start (audio_output_t *aout, audio_sample_format_t *restrict fmt)
aout_FormatPrepare (fmt); aout_FormatPrepare (fmt);
aout->sys = sys; aout->sys = sys;
aout->time_get = TimeGet;
aout->play = Play; aout->play = Play;
aout->pause = Pause; aout->pause = Pause;
aout->flush = NULL; /* sndio sucks! */ aout->flush = NULL; /* sndio sucks! */
...@@ -179,18 +181,21 @@ static void Close (vlc_object_t *obj) ...@@ -179,18 +181,21 @@ static void Close (vlc_object_t *obj)
sio_close (sys->hdl); sio_close (sys->hdl);
} }
static void Play (audio_output_t *aout, block_t *block, static int TimeGet (audio_output_t *aout, mtime_t *restrict pts)
mtime_t *restrict drift)
{ {
aout_sys_t *sys = aout->sys; aout_sys_t *sys = aout->sys;
struct sio_par par; struct sio_par par;
if (sio_getpar (sys->hdl, &par) == 0) if (sio_getpar (sys->hdl, &par))
{ return -1;
mtime_t delay = par.bufsz * CLOCK_FREQ / aout->format.i_rate;
*drift = mdate () + delay - block->i_pts; *pts = mdate () + (par.bufsz * CLOCK_FREQ / aout->format.i_rate);
} return 0;
}
static void Play (audio_output_t *aout, block_t *block)
{
aout_sys_t *sys = aout->sys;
while (block->i_buffer > 0 && !sio_eof (sys->hdl)) while (block->i_buffer > 0 && !sio_eof (sys->hdl))
{ {
......
...@@ -135,32 +135,43 @@ struct aout_sys_t ...@@ -135,32 +135,43 @@ struct aout_sys_t
/*** VLC audio output callbacks ***/ /*** VLC audio output callbacks ***/
static void Play(audio_output_t *aout, block_t *block, mtime_t *restrict drift) static int TimeGet(audio_output_t *aout, mtime_t *restrict pts)
{ {
aout_sys_t *sys = aout->sys; aout_sys_t *sys = aout->sys;
HRESULT hr = S_OK; UINT64 pos, qpcpos;
HRESULT hr;
if (sys->chans_to_reorder) if (sys->clock == NULL)
aout_ChannelReorder(block->p_buffer, block->i_buffer, return -1;
sys->chans_to_reorder, sys->chans_table, sys->bits);
Enter(); Enter();
if (likely(sys->clock != NULL))
{
UINT64 pos, qpcpos;
hr = IAudioClock_GetPosition(sys->clock, &pos, &qpcpos); hr = IAudioClock_GetPosition(sys->clock, &pos, &qpcpos);
if (SUCCEEDED(hr)) Leave();
if (FAILED(hr))
{ {
qpcpos = GetQPC() - qpcpos; msg_Err(aout, "cannot get position (error 0x%lx)", hr);
static_assert((10000000 % CLOCK_FREQ) == 0, return -1;
"Frequency conversion broken");
*drift = qpcpos / (10000000 / CLOCK_FREQ);
}
else
msg_Warn(aout, "cannot get position (error 0x%lx)", hr);
} }
mtime_t delay = ((GetQPC() - qpcpos) / (10000000 / CLOCK_FREQ));
static_assert((10000000 % CLOCK_FREQ) == 0, "Frequency conversion broken");
if (delay < 1000) /* device is still buffering, time is screwed */
return -1;
*pts += mdate () + delay;
return 0;
}
static void Play(audio_output_t *aout, block_t *block)
{
aout_sys_t *sys = aout->sys;
HRESULT hr = S_OK;
if (sys->chans_to_reorder)
aout_ChannelReorder(block->p_buffer, block->i_buffer,
sys->chans_to_reorder, sys->chans_table, sys->bits);
Enter();
for (;;) for (;;)
{ {
UINT32 frames; UINT32 frames;
...@@ -799,6 +810,7 @@ retry: ...@@ -799,6 +810,7 @@ retry:
sys->rate = fmt->i_rate; sys->rate = fmt->i_rate;
sys->bytes_per_frame = fmt->i_bytes_per_frame; sys->bytes_per_frame = fmt->i_bytes_per_frame;
aout->time_get = TimeGet;
aout->play = Play; aout->play = Play;
aout->pause = Pause; aout->pause = Pause;
aout->flush = Flush; aout->flush = Flush;
......
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
*****************************************************************************/ *****************************************************************************/
static int Open ( vlc_object_t * ); static int Open ( vlc_object_t * );
static void Close ( vlc_object_t * ); static void Close ( vlc_object_t * );
static void Play ( audio_output_t *, block_t *, mtime_t * ); static void Play ( audio_output_t *, block_t * );
/***************************************************************************** /*****************************************************************************
* notification_thread_t: waveOut event thread * notification_thread_t: waveOut event thread
...@@ -160,6 +160,7 @@ static int Start( audio_output_t *p_aout, audio_sample_format_t *restrict fmt ) ...@@ -160,6 +160,7 @@ static int Start( audio_output_t *p_aout, audio_sample_format_t *restrict fmt )
{ {
vlc_value_t val; vlc_value_t val;
p_aout->time_get = aout_PacketTimeGet;
p_aout->play = Play; p_aout->play = Play;
p_aout->pause = aout_PacketPause; p_aout->pause = aout_PacketPause;
p_aout->flush = aout_PacketFlush; p_aout->flush = aout_PacketFlush;
...@@ -449,8 +450,7 @@ static void Probe( audio_output_t * p_aout, const audio_sample_format_t *fmt ) ...@@ -449,8 +450,7 @@ static void Probe( audio_output_t * p_aout, const audio_sample_format_t *fmt )
* This doesn't actually play the buffer. This just stores the buffer so it * This doesn't actually play the buffer. This just stores the buffer so it
* can be played by the callback thread. * can be played by the callback thread.
*****************************************************************************/ *****************************************************************************/
static void Play( audio_output_t *_p_aout, block_t *block, static void Play( audio_output_t *_p_aout, block_t *block )
mtime_t *restrict drift )
{ {
if( !_p_aout->sys->b_playing ) if( !_p_aout->sys->b_playing )
{ {
...@@ -467,7 +467,7 @@ static void Play( audio_output_t *_p_aout, block_t *block, ...@@ -467,7 +467,7 @@ static void Play( audio_output_t *_p_aout, block_t *block,
SetEvent( _p_aout->sys->new_buffer_event ); SetEvent( _p_aout->sys->new_buffer_event );
} }
aout_PacketPlay( _p_aout, block, drift ); aout_PacketPlay( _p_aout, block );
} }
/***************************************************************************** /*****************************************************************************
......
...@@ -440,7 +440,7 @@ void aout_OutputDelete (audio_output_t *aout) ...@@ -440,7 +440,7 @@ void aout_OutputDelete (audio_output_t *aout)
void aout_OutputPlay (audio_output_t *aout, block_t *block) void aout_OutputPlay (audio_output_t *aout, block_t *block)
{ {
aout_owner_t *owner = aout_owner (aout); aout_owner_t *owner = aout_owner (aout);
mtime_t drift = 0; mtime_t drift;
aout_assert_locked (aout); aout_assert_locked (aout);
...@@ -454,7 +454,12 @@ void aout_OutputPlay (audio_output_t *aout, block_t *block) ...@@ -454,7 +454,12 @@ void aout_OutputPlay (audio_output_t *aout, block_t *block)
return; return;
} }
aout->play (aout, block, &drift); if (aout->time_get != NULL && aout->time_get (aout, &drift) == 0)
drift -= block->i_pts;
else
drift = 0;
aout->play (aout, block);
/** /**
* Notifies the audio input of the drift from the requested audio * Notifies the audio input of the drift from the requested audio
* playback timestamp (@ref block_t.i_pts) to the anticipated playback time * playback timestamp (@ref block_t.i_pts) to the anticipated playback time
...@@ -463,14 +468,9 @@ void aout_OutputPlay (audio_output_t *aout, block_t *block) ...@@ -463,14 +468,9 @@ void aout_OutputPlay (audio_output_t *aout, block_t *block)
* trigger upsampling or downsampling, or even discard samples. * trigger upsampling or downsampling, or even discard samples.
* Future VLC versions may instead adjust the input decoding speed. * Future VLC versions may instead adjust the input decoding speed.
* *
* The audio output plugin is responsible for estimating the drift. A negative * The audio output plugin is responsible for estimating the time. Typically,
* value means playback is ahead of the intended time and a positive value * the audio output can estimate the total buffer delay. Then:
* means playback is late from the intended time. In most cases, the audio * pts = mdate() + delay
* output can estimate the delay until playback of the next sample to be
* queued. Then, before the block is queued:
* drift = mdate() + delay - block->i_pts
* where mdate() + delay is the estimated time when the sample will be rendered
* and block->i_pts is the intended time.
*/ */
if (drift < -AOUT_MAX_PTS_ADVANCE || +AOUT_MAX_PTS_DELAY < drift) if (drift < -AOUT_MAX_PTS_ADVANCE || +AOUT_MAX_PTS_DELAY < drift)
{ {
......
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