summaryrefslogtreecommitdiff
path: root/src/xine-engine/audio_out.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/xine-engine/audio_out.c')
-rw-r--r--src/xine-engine/audio_out.c65
1 files changed, 39 insertions, 26 deletions
diff --git a/src/xine-engine/audio_out.c b/src/xine-engine/audio_out.c
index 40abd78cb..935e8b671 100644
--- a/src/xine-engine/audio_out.c
+++ b/src/xine-engine/audio_out.c
@@ -17,7 +17,7 @@
* along with self program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
- * $Id: audio_out.c,v 1.84 2002/11/27 23:13:09 heikos Exp $
+ * $Id: audio_out.c,v 1.85 2002/11/30 22:09:42 miguelfreitas Exp $
*
* 22-8-2001 James imported some useful AC3 sections from the previous alsa driver.
* (c) 2001 Andy Lo A Foe <andy@alsaplayer.org>
@@ -80,6 +80,32 @@
#define ZERO_BUF_SIZE 5000
+/* By adding gap errors (difference between reported and expected
+ * sound card clock) into metronom's vpts_offset we can use its
+ * smoothing algorithms to correct sound card clock drifts.
+ * obs: previously this error was added to xine scr.
+ *
+ * audio buf ---> metronom --> audio fifo --> (buf->vpts - hw_vpts)
+ * (vpts_offset + error) gap
+ * <---------- control --------------|
+ *
+ * Unfortunately audio fifo adds a large delay to our closed loop.
+ *
+ * These are designed to avoid updating the metronom too fast.
+ * - it will only be updated 1 time per second (so it has a chance of
+ * distributing the error for several frames).
+ * - it will only be updated 2 times for the whole audio fifo size
+ * length (so the control will wait to see the feedback effect)
+ * - each update will be of gap/SYNC_GAP_RATE.
+ *
+ * Sound card clock correction can only provide smooth playback for
+ * errors < 1% nominal rate. For bigger errors (bad streams) audio
+ * buffers may be dropped or gaps filled with silence.
+ */
+#define SYNC_TIME_INVERVAL (1 * 90000)
+#define SYNC_BUF_INTERVAL NUM_AUDIO_BUFFERS / 2
+#define SYNC_GAP_RATE 4
+
struct audio_fifo_s {
audio_buffer_t *first;
audio_buffer_t *last;
@@ -521,7 +547,6 @@ static void *ao_loop (void *this_gen) {
}
}
- this->allow_full_ao_fill_gap = 1;
#ifdef LOG
printf ("audio_out:loop:pause: I feel sleepy.\n");
#endif
@@ -566,7 +591,7 @@ static void *ao_loop (void *this_gen) {
gap = in_buf->vpts - hw_vpts;
#ifdef LOG
printf ("audio_out: hw_vpts : %lld buffer_vpts : %lld gap : %lld\n",
- hw_vpts, in_buf->vpts, gap);
+ hw_vpts, buf->vpts, gap);
#endif
/*
@@ -581,24 +606,20 @@ static void *ao_loop (void *this_gen) {
printf ("audio_out:loop: next fifo\n");
#endif
fifo_append (this->free_fifo, in_buf);
+ in_buf = NULL;
#ifdef LOG
printf ("audio_out: audio package (vpts = %lld, gap = %lld) dropped\n",
- in_buf->vpts, gap);
+ buf->vpts, gap);
#endif
- in_buf = NULL;
-
- /*
- * for small gaps ( tolerance < abs(gap) < AO_MAX_GAP ) the metronom's
- * clock is set to compensate.
- *
- * hopefully this will guarantee smooth audio playback - at the possible
- * expense of the video running a little bit faster or slower than it is
- * supposed to.
+ /* for small gaps ( tolerance < abs(gap) < AO_MAX_GAP )
+ * feedback them into metronom's vpts_offset.
*/
- } else if ( (abs(gap) < AO_MAX_GAP) && (abs(gap) > this->gap_tolerance) ) {
+ } else if ( abs(gap) < AO_MAX_GAP && abs(gap) > this->gap_tolerance &&
+ cur_time > (last_sync_time + SYNC_TIME_INVERVAL) &&
+ bufs_since_sync >= SYNC_BUF_INTERVAL ) {
xine_stream_t *stream;
#ifdef LOG
printf ("audio_out: audio_loop: ADJ_VPTS\n");
@@ -606,9 +627,8 @@ static void *ao_loop (void *this_gen) {
pthread_mutex_lock(&this->streams_lock);
for (stream = xine_list_first_content(this->streams); stream;
stream = xine_list_next_content(this->streams)) {
- int64_t curtime = stream->metronom->clock->get_current_time(stream->metronom->clock);
- stream->metronom->clock->adjust_clock(stream->metronom->clock,
- curtime + gap);
+ stream->metronom->set_option(stream->metronom, METRONOM_ADJ_VPTS_OFFSET,
+ -gap/SYNC_GAP_RATE );
last_sync_time = cur_time;
bufs_since_sync = 0;
}
@@ -616,12 +636,7 @@ static void *ao_loop (void *this_gen) {
} else if ( gap > AO_MAX_GAP ) {
/* for big gaps output silence */
- if (this->allow_full_ao_fill_gap) {
- ao_fill_gap (this, gap);
- this->allow_full_ao_fill_gap = 0;
- } else {
- ao_fill_gap (this, gap / 2);
- }
+ ao_fill_gap (this, gap);
} else {
#if 0
{
@@ -828,7 +843,7 @@ static void ao_put_buffer (xine_audio_port_t *this, audio_buffer_t *buf, xine_st
pts, buf->vpts);
#endif
- if ( buf->vpts<this->last_audio_vpts) {
+ if ( buf->vpts + AO_MAX_GAP < this->last_audio_vpts) {
/* reject buffer */
printf ("audio_out: rejected buffer vpts=%lld, last_audio_vpts=%lld\n",
@@ -1027,7 +1042,6 @@ static void ao_flush (xine_audio_port_t *this) {
fifo_append_int (this->out_fifo, buf);
this->flush_audio_driver = 1;
- this->allow_full_ao_fill_gap = 1;
pthread_mutex_unlock (&this->free_fifo->mutex);
pthread_mutex_unlock (&this->out_fifo->mutex);
}
@@ -1062,7 +1076,6 @@ xine_audio_port_t *ao_new_port (xine_t *xine, ao_driver_t *driver) {
this->audio_loop_running = 0;
this->audio_paused = 0;
this->flush_audio_driver = 0;
- this->allow_full_ao_fill_gap = 0;
this->zero_space = xine_xmalloc (ZERO_BUF_SIZE * 2 * 6);
this->gap_tolerance = driver->get_gap_tolerance (this->driver);