summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiguel Freitas <miguelfreitas@users.sourceforge.net>2002-03-26 01:47:17 +0000
committerMiguel Freitas <miguelfreitas@users.sourceforge.net>2002-03-26 01:47:17 +0000
commitc97b86045b81f7ee758acb7f835bbd2a697c03d0 (patch)
treead792557788a992d5ba2534f54671ce4bc072df3
parent76927755fa6782d3df74ecd9d95a92bf429fad5f (diff)
downloadxine-lib-c97b86045b81f7ee758acb7f835bbd2a697c03d0.tar.gz
xine-lib-c97b86045b81f7ee758acb7f835bbd2a697c03d0.tar.bz2
sound card clock drift patch
CVS patchset: 1635 CVS date: 2002/03/26 01:47:17
-rw-r--r--src/xine-engine/audio_out.c67
-rw-r--r--src/xine-engine/audio_out.h4
-rw-r--r--src/xine-engine/metronom.c12
-rw-r--r--src/xine-engine/metronom.h7
4 files changed, 69 insertions, 21 deletions
diff --git a/src/xine-engine/audio_out.c b/src/xine-engine/audio_out.c
index 27dc57dfb..52e568339 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.48 2002/03/19 02:12:49 guenter Exp $
+ * $Id: audio_out.c,v 1.49 2002/03/26 01:47:17 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>
@@ -76,6 +76,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;
@@ -240,12 +266,16 @@ static void *ao_loop (void *this_gen) {
int64_t cur_time;
int num_output_frames ;
int paused_wait;
+ int64_t last_sync_time;
+ int bufs_since_sync;
-
+ last_sync_time = bufs_since_sync = 0;
+
while ((this->audio_loop_running) ||
(!this->audio_loop_running && this->out_fifo->first)) {
buf = fifo_remove (this->out_fifo);
+ bufs_since_sync++;
do {
delay = this->driver->delay(this->driver);
@@ -294,8 +324,8 @@ static void *ao_loop (void *this_gen) {
/*
* output audio data synced to master clock
*/
-
- if (gap < (-1 * this->gap_tolerance) || !buf->num_frames ||
+
+ if (gap < (-1 * AO_MAX_GAP) || !buf->num_frames ||
this->audio_paused ) {
/* drop package */
@@ -306,19 +336,24 @@ static void *ao_loop (void *this_gen) {
#endif
} else {
-
- if (gap>this->gap_tolerance) {
-
- if (gap>15000)
- ao_fill_gap (this, gap);
- else {
- printf ("audio_out: adjusting master clock %lld -> %lld\n",
- cur_time, cur_time + gap);
- this->metronom->adjust_clock (this->metronom,
- cur_time + gap);
- }
- }
+ /* for small gaps ( tolerance < abs(gap) < AO_MAX_GAP )
+ * feedback them into metronom's vpts_offset.
+ */
+ 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 ) {
+
+ this->metronom->set_option(this->metronom, METRONOM_ADJ_VPTS_OFFSET,
+ -gap/SYNC_GAP_RATE );
+ last_sync_time = cur_time;
+ bufs_since_sync = 0;
+ }
+
+ /* for big gaps output silence */
+ if ( gap > AO_MAX_GAP ) {
+ ao_fill_gap (this, gap/2);
+ }
/*
* resample and output audio data
diff --git a/src/xine-engine/audio_out.h b/src/xine-engine/audio_out.h
index 03600edcf..fb73dc483 100644
--- a/src/xine-engine/audio_out.h
+++ b/src/xine-engine/audio_out.h
@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
- * $Id: audio_out.h,v 1.27 2002/03/19 02:12:50 guenter Exp $
+ * $Id: audio_out.h,v 1.28 2002/03/26 01:47:17 miguelfreitas Exp $
*/
#ifndef HAVE_AUDIO_OUT_H
#define HAVE_AUDIO_OUT_H
@@ -273,6 +273,8 @@ ao_instance_t *ao_new_instance (ao_driver_t *driver, xine_t *xine) ;
#define AO_CTRL_PLAY_RESUME 1
#define AO_CTRL_FLUSH_BUFFERS 2
+/* above that value audio frames are discarded */
+#define AO_MAX_GAP 15000
typedef struct ao_info_s {
diff --git a/src/xine-engine/metronom.c b/src/xine-engine/metronom.c
index 5846e5408..689274239 100644
--- a/src/xine-engine/metronom.c
+++ b/src/xine-engine/metronom.c
@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
- * $Id: metronom.c,v 1.75 2002/03/24 14:15:37 guenter Exp $
+ * $Id: metronom.c,v 1.76 2002/03/26 01:47:17 miguelfreitas Exp $
*/
#ifdef HAVE_CONFIG_H
@@ -471,7 +471,9 @@ static int64_t metronom_got_audio_samples (metronom_t *this, int64_t pts,
else {
if( this->audio_samples ) {
/* calculate drift_step to recover vpts errors */
+#ifdef LOG
printf("audio diff = %lld ", diff );
+#endif
diff *= AUDIO_SAMPLE_NUM;
diff /= this->audio_samples * 4;
@@ -483,8 +485,10 @@ static int64_t metronom_got_audio_samples (metronom_t *this, int64_t pts,
this->audio_drift_step = diff;
+#ifdef LOG
printf("audio_drift = %lld, pts_per_smpls = %lld\n", diff,
this->pts_per_smpls );
+#endif
}
}
this->audio_samples = 0;
@@ -516,6 +520,12 @@ static void metronom_set_option (metronom_t *this, int option, int64_t value) {
case METRONOM_SCR_ADJUSTABLE:
this->scr_adjustable = value;
break;
+ case METRONOM_ADJ_VPTS_OFFSET:
+ this->vpts_offset += value;
+/*#ifdef LOG*/
+ printf ("metronom: adjusting vpts_offset by %lld\n", value );
+/*#endif*/
+ break;
default:
printf ("metronom: unknown option in set_option: %d\n",
option);
diff --git a/src/xine-engine/metronom.h b/src/xine-engine/metronom.h
index 4f7d9ebb7..b49303a63 100644
--- a/src/xine-engine/metronom.h
+++ b/src/xine-engine/metronom.h
@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
- * $Id: metronom.h,v 1.25 2002/03/23 18:56:56 guenter Exp $
+ * $Id: metronom.h,v 1.26 2002/03/26 01:47:17 miguelfreitas Exp $
*
* metronom: general pts => virtual calculation/assoc
*
@@ -244,8 +244,9 @@ metronom_t *metronom_init (int have_audio, void *xine);
* metronom options
*/
-#define METRONOM_SCR_ADJUSTABLE 1
-#define METRONOM_AV_OFFSET 2
+#define METRONOM_SCR_ADJUSTABLE 1
+#define METRONOM_AV_OFFSET 2
+#define METRONOM_ADJ_VPTS_OFFSET 3
/*
* SCR (system clock reference) plugins