gstreamer中rtpjitterbuffer的定时器线程及重传请求代码分析

本文详细分析了gstreamer的rtpjitterbuffer组件在处理丢包时的定时器线程流程,包括创建、超时判断和重传请求。当检测到丢包时,rtpjitterbuffer会计算超时时间并添加定时器,如果超时未收到丢失的包,将决定是否进行重传或标记为丢包。通过对代码的深入解读,阐述了丢包处理的关键步骤和逻辑。
摘要由CSDN通过智能技术生成

1. 简介:

    本文主要描述gstreamer中rtpjitterbuffer的定时器线程的处理流程,定时器主要对丢包进行延迟处理。

2. 流程:

2.1 定时器线程主要流程:

    1) 当rtpjitterbuffer组件状态从READY升至PAUSED时,会创建出定时器的子线程。

    2) 从当前定时器中找到超时时间最早的定时器。

    3) 如果没有找到定时器,说明当前并没有定时器被添加,此时会挂起本线程,等待主线程上丢包后添加相应的定时器。

    4) 找到定时器后,与当前时间比较,如果已经超时,则处理超时事件,处理超时事件完成后回到4)。

    5) 如果这个定时器还没有超时,说明所有定时器都还没有到,本线程进入睡眠,待睡眠醒来时,回到2)。

流程如图:


2.2 超时重传处理流程:

    这里主要分析单个包丢失后的处理流程。

    1) 当一个不是预期的包到来,且序号大于预期包,则认为预期包可能丢包,这时候进入丢包处理流程。

    2) 首先通过函数calculate_expected计算第一次超时的时间,这里使用的是预期包和实际到达包的序号差和dts的比值,线性增大的时间戳作为超时时间,具体见下分析。

    3) 为对应包序添加定时器,此时非预期的包照常处理,依旧进入jbuf,但是由于包序不连续,推送线程不会把数据往下游发送。

    4) 定时器线程等待超时时间的到来。

    5) 如果超时到来之前,预期包到达,则删除定时器,进入正常的包处理流程,定时器线程唤醒后没有对应的定时器事件,则进行其他处理。

    6) 如果超时到来之前,包都没有到达,则定时器触发,需要判断当前重试次数是否已经达到上限,或者重试时间超过限制的总时间。

    7) 如果尝试满了,则将包设置为LOST,在下一个超时后执行do_lost_timeout操作,将该序号的包置位LOST的event向下游发送。

    8) 如果还可以继续尝试,则刷新当前尝试次数和尝试时间,重新调度定时器,再次加入调度。

流程如图:


3. 代码分析:

3.1 主入口函数wait_next_timeout

    当rtpjitterbuffer从READY状态转换到PAUSED状态时,会创建一个子线程用来对所有的定时器事件进行管理。

    其代码如下,虽然比较冗长,但是处理流程比较简单,如上描述。

/* called when we need to wait for the next timeout.
 *
 * We loop over the array of recorded timeouts and wait for the earliest one.
 * When it timed out, do the logic associated with the timer.
 *
 * If there are no timers, we wait on a gcond until something new happens.
 */
static void
wait_next_timeout (GstRtpJitterBuffer * jitterbuffer)
{
  GstRtpJitterBufferPrivate *priv = jitterbuffer->priv;
  GstClockTime now = 0;

  JBUF_LOCK (priv);
  while (priv->timer_running) {
    TimerData *timer = NULL;
    GstClockTime timer_timeout = -1;
    gint i, len;

    /* If we have a clock, update "now" now with the very
     * latest running time we have. If timers are unscheduled below we
     * otherwise wouldn't update now (it's only updated when timers
     * expire), and also for the very first loop iteration now would
     * otherwise always be 0
     */
    // 获取当前时间,主要用来和定时器的超时时间做对比。
    GST_OBJECT_LOCK (jitterbuffer);
    if (GST_ELEMENT_CLOCK (jitterbuffer)) {
      now =
          gst_clock_get_time (GST_ELEMENT_CLOCK (jitterbuffer)) -
          GST_ELEMENT_CAST (jitterbuffer)->base_time;
    }
    GST_OBJECT_UNLOCK (jitterbuffer);

    GST_DEBUG_OBJECT (jitterbuffer, "now %" GST_TIME_FORMAT,
        GST_TIME_ARGS (now));

    len = priv->timers->len;
    // 遍历所有定时器,找到其中时间最小的。
    for (i = 0; i < len; i++) {
      TimerData *test = &g_array_index (priv->timers, TimerData, i);
      GstClockTime test_timeout = get_timeout (jitterbuffer, test);
      gboolean save_best = FALSE;

      GST_DEBUG_OBJECT (jitterbuffer, "%d, %d, %d, %" GST_TIME_FORMAT,
          i, test->type, test->seqnum, GST_TIME_ARGS (test_timeout));

      /* find the smallest timeout */
      if (timer == NULL) {
        // 当前没有最小值
        save_best = TRUE;
      } else if (timer_timeout == -1) {
        // 不是很确定什么场景会有超时时间为-1的,因此这两个分支不分析。
        /* we already have an immediate timeout, the new timer must be an
         * immediate timer with smaller seqnum to become the best */
        if (te
  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值