diff options
Diffstat (limited to 'src/xine-engine/audio_out.c')
-rw-r--r-- | src/xine-engine/audio_out.c | 65 |
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); |