diff -ur --exclude-from dontdiff vanilla/main/libmpdemux/ai_alsa.c main/libmpdemux/ai_alsa.c --- vanilla/main/libmpdemux/ai_alsa.c Sun Sep 1 20:12:39 2002 +++ main/libmpdemux/ai_alsa.c Sun Sep 29 15:18:03 2002 @@ -1,5 +1,6 @@ #include #include +#include #include "config.h" @@ -13,11 +14,9 @@ { snd_pcm_hw_params_t *params; snd_pcm_sw_params_t *swparams; - size_t buffer_size; + int buffer_size; int err; - size_t n; unsigned int rate; - snd_pcm_uframes_t start_threshold, stop_threshold; snd_pcm_hw_params_alloca(¶ms); snd_pcm_sw_params_alloca(&swparams); @@ -122,6 +121,49 @@ err = ai_alsa_setup(ai); return err; +} + +#ifndef timersub +#define timersub(a, b, result) \ +do { \ + (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ + (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ + if ((result)->tv_usec < 0) { \ + --(result)->tv_sec; \ + (result)->tv_usec += 1000000; \ + } \ +} while (0) +#endif + +int ai_alsa_xrun(audio_in_t *ai) +{ + snd_pcm_status_t *status; + int res; + + snd_pcm_status_alloca(&status); + if ((res = snd_pcm_status(ai->alsa.handle, status))<0) { + mp_msg(MSGT_TV, MSGL_ERR, "ALSA status error: %s", snd_strerror(res)); + return -1; + } + if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN) { + struct timeval now, diff, tstamp; + gettimeofday(&now, 0); + snd_pcm_status_get_trigger_tstamp(status, &tstamp); + timersub(&now, &tstamp, &diff); + mp_msg(MSGT_TV, MSGL_ERR, "ALSA xrun!!! (at least %.3f ms long)\n", + diff.tv_sec * 1000 + diff.tv_usec / 1000.0); + if (mp_msg_test(MSGT_TV, MSGL_V)) { + mp_msg(MSGT_TV, MSGL_ERR, "ALSA Status:\n"); + snd_pcm_status_dump(status, ai->alsa.log); + } + if ((res = snd_pcm_prepare(ai->alsa.handle))<0) { + mp_msg(MSGT_TV, MSGL_ERR, "ALSA xrun: prepare error: %s", snd_strerror(res)); + return -1; + } + return 0; /* ok, data should be accepted again */ + } + mp_msg(MSGT_TV, MSGL_ERR, "ALSA read/write error"); + return -1; } #endif /* HAVE_ALSA9 */ diff -ur --exclude-from dontdiff vanilla/main/libmpdemux/audio_in.c main/libmpdemux/audio_in.c --- vanilla/main/libmpdemux/audio_in.c Sun Sep 22 20:21:09 2002 +++ main/libmpdemux/audio_in.c Sun Sep 29 15:20:53 2002 @@ -109,7 +109,7 @@ if (ai->alsa.device) free(ai->alsa.device); ai->alsa.device = strdup(device); /* mplayer cannot handle colons in arguments */ - for (i = 0; i < strlen(ai->alsa.device); i++) { + for (i = 0; i < (int)strlen(ai->alsa.device); i++) { if (ai->alsa.device[i] == '.') ai->alsa.device[i] = ':'; } return 0; @@ -171,6 +171,13 @@ if (ret != ai->alsa.chunk_size) { if (ret < 0) { mp_msg(MSGT_TV, MSGL_ERR, "\nerror reading audio: %s\n", snd_strerror(ret)); + if (ret == -EPIPE) { + if (ai_alsa_xrun(ai) == 0) { + mp_msg(MSGT_TV, MSGL_ERR, "Recovered from cross-run, some frames may be left out!\n"); + } else { + mp_msg(MSGT_TV, MSGL_ERR, "Fatal error, cannot recover!\n"); + } + } } else { mp_msg(MSGT_TV, MSGL_ERR, "\nnot enough audio samples!\n"); } diff -ur --exclude-from dontdiff vanilla/main/libmpdemux/audio_in.h main/libmpdemux/audio_in.h --- vanilla/main/libmpdemux/audio_in.h Thu Aug 22 00:50:40 2002 +++ main/libmpdemux/audio_in.h Sun Sep 29 15:11:58 2002 @@ -59,6 +59,7 @@ #ifdef HAVE_ALSA9 int ai_alsa_setup(audio_in_t *ai); int ai_alsa_init(audio_in_t *ai); +int ai_alsa_xrun(audio_in_t *ai); #endif int ai_oss_set_samplerate(audio_in_t *ai); diff -ur --exclude-from dontdiff vanilla/main/libmpdemux/tvi_v4l.c main/libmpdemux/tvi_v4l.c --- vanilla/main/libmpdemux/tvi_v4l.c Sun Sep 29 10:40:19 2002 +++ main/libmpdemux/tvi_v4l.c Sun Sep 29 15:11:58 2002 @@ -1184,7 +1184,7 @@ mp_dbg(MSGT_TV, MSGL_DBG3, "\npicture sync failed\n"); prev_interval = 0.0; - prev_skew = priv->audio_skew; + prev_skew = 0.0; for (;!priv->shutdown;) { @@ -1209,29 +1209,33 @@ priv->starttime = curtime.tv_sec + curtime.tv_usec*.000001; priv->audio_skew_measure_time = 0; pthread_mutex_unlock(&priv->audio_starter); + // first frame must always have timestamp of zero + xskew = 0.0; + skew = 0.0; + interval = 0.0; first = 0; - } + } else { + interval = curtime.tv_sec + curtime.tv_usec*.000001 - priv->starttime; - interval = curtime.tv_sec + curtime.tv_usec*.000001 - priv->starttime; + if (!priv->immediate_mode && ( + (interval - prev_interval < 1.0/priv->fps*0.85) + || (interval - prev_interval > 1.0/priv->fps*1.15) ) ) { + mp_msg(MSGT_TV, MSGL_V, "\nvideo capture thread: frame delta ~ %.1lf fps\n", + 1.0/(interval - prev_interval)); + } - if (!priv->immediate_mode && ( - ((interval - prev_interval < 1.0/priv->fps*0.85) && interval > 0.0001) - || (interval - prev_interval > 1.0/priv->fps*1.15) ) ) { - mp_msg(MSGT_TV, MSGL_V, "\nvideo capture thread: frame delta ~ %.1lf fps\n", - 1.0/(interval - prev_interval)); - } - - // interpolate the skew in time - pthread_mutex_lock(&priv->skew_mutex); - xskew = priv->audio_skew + (interval - priv->audio_skew_measure_time)*priv->audio_skew_factor; - pthread_mutex_unlock(&priv->skew_mutex); - // correct extreme skew changes to avoid (especially) moving backwards in time - if (xskew - prev_skew > (interval - prev_interval)*MAX_SKEW_DELTA) { - skew = prev_skew + (interval - prev_interval)*MAX_SKEW_DELTA; - } else if (xskew - prev_skew < -(interval - prev_interval)*MAX_SKEW_DELTA) { - skew = prev_skew - (interval - prev_interval)*MAX_SKEW_DELTA; - } else { - skew = xskew; + // interpolate the skew in time + pthread_mutex_lock(&priv->skew_mutex); + xskew = priv->audio_skew + (interval - priv->audio_skew_measure_time)*priv->audio_skew_factor; + pthread_mutex_unlock(&priv->skew_mutex); + // correct extreme skew changes to avoid (especially) moving backwards in time + if (xskew - prev_skew > (interval - prev_interval)*MAX_SKEW_DELTA) { + skew = prev_skew + (interval - prev_interval)*MAX_SKEW_DELTA; + } else if (xskew - prev_skew < -(interval - prev_interval)*MAX_SKEW_DELTA) { + skew = prev_skew - (interval - prev_interval)*MAX_SKEW_DELTA; + } else { + skew = xskew; + } } mp_msg(MSGT_TV, MSGL_DBG3, "\nfps = %lf, v_interval = %lf, a_skew = %f, corr_skew = %f\n",