⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 jitterbuf.c

📁 ppciaxclient softphone
💻 C
📖 第 1 页 / 共 2 页
字号:
	if(frame->next == frame)
	  jb->frames = NULL;
	else
	  jb->frames = frame->next;


	/* insert onto "free" single-linked list */
	frame->next = jb->free;
	jb->free = frame;

	jb->info.frames_cur--;

	/* we return the frame pointer, even though it's on free list, 
	 * but caller must copy data */
	return frame;
    } 

    return NULL;
}

static jb_frame *queue_get(jitterbuf *jb, long ts) 
{
    return _queue_get(jb,ts,0);
}

static jb_frame *queue_getall(jitterbuf *jb) 
{
    return _queue_get(jb,0,1);
}

#if 0
/* some diagnostics */
static void jb_dbginfo(jitterbuf *jb) 
{
    if(dbgf == NULL) return;

    jb_dbg("\njb info: fin=%ld fout=%ld flate=%ld flost=%ld fdrop=%ld fcur=%ld\n",
	    jb->info.frames_in, jb->info.frames_out, jb->info.frames_late, jb->info.frames_lost, jb->info.frames_dropped, jb->info.frames_cur);
	
    jb_dbg("	jitter=%ld current=%ld target=%ld min=%ld sil=%d len=%d len/fcur=%ld\n",
	    jb->info.jitter, jb->info.current, jb->info.target, jb->info.min, jb->info.silence_begin_ts, jb->info.current - jb->info.min, 
	    jb->info.frames_cur ? (jb->info.current - jb->info.min)/jb->info.frames_cur : -8);
    if(jb->info.frames_in > 0) 
	jb_dbg("jb info: Loss PCT = %ld%%, Late PCT = %ld%%\n",
	    jb->info.frames_lost * 100/(jb->info.frames_in + jb->info.frames_lost), 
	    jb->info.frames_late * 100/jb->info.frames_in);
	jb_dbg("jb info: queue %d -> %d.  last_ts %d (queue len: %d) last_ms %d\n",
	    queue_next(jb), 
	    queue_last(jb),
	    jb->info.next_voice_ts, 
	    queue_last(jb) - queue_next(jb),
	    jb->info.last_voice_ms);
}
#endif

#ifdef DEEP_DEBUG
static void jb_chkqueue(jitterbuf *jb) 
{
    int i=0;
    jb_frame *p = jb->frames;

    if(!p) {
      return;
    }

    do {
	if(p->next == NULL)  {
	  jb_err("Queue is BROKEN at item [%d]", i);	
	}
	i++;
	p=p->next;
    } while (p->next != jb->frames);
}

static void jb_dbgqueue(jitterbuf *jb) 
{
    int i=0;
    jb_frame *p = jb->frames;

    jb_dbg("queue: ");

    if(!p) {
      jb_dbg("EMPTY\n");
      return;
    }

    do {
	jb_dbg("[%d]=%ld ", i++, p->ts);
	p=p->next;
    } while (p->next != jb->frames);

    jb_dbg("\n");
}
#endif

int jb_put(jitterbuf *jb, void *data, int type, long ms, long ts, long now) 
{
    jb_dbg2("jb_put(%x,%x,%ld,%ld,%ld)\n", jb, data, ms, ts, now);

    jb->info.frames_in++;

    if(type == JB_TYPE_VOICE) {
      /* presently, I'm only adding VOICE frames to history and drift calculations; mostly because with the
       * IAX integrations, I'm sending retransmitted control frames with their awkward timestamps through */
		if (history_put(jb,ts,now,ms))
			return JB_DROP;
    }

	/* if put into head of queue, caller needs to reschedule */
	if (queue_put(jb,data,type,ms,ts)) {
		return JB_SCHED;
	}

    return JB_OK;
}


static int _jb_get(jitterbuf *jb, jb_frame *frameout, long now, long interpl) 
{
    jb_frame *frame;
    long diff;

    /*if((now - jb_next(jb)) > 2 * jb->info.last_voice_ms) jb_warn("SCHED: %ld", (now - jb_next(jb))); */
    /* get jitter info */
    history_get(jb);


    /* target */
    jb->info.target = jb->info.jitter + jb->info.min + JB_TARGET_EXTRA; 

    /* if a hard clamp was requested, use it */
    if((jb->info.conf.max_jitterbuf) && ((jb->info.target - jb->info.min) > jb->info.conf.max_jitterbuf)) {
	jb_dbg("clamping target from %d to %d\n", (jb->info.target - jb->info.min), jb->info.conf.max_jitterbuf);
	jb->info.target = jb->info.min + jb->info.conf.max_jitterbuf;
    }

    diff = jb->info.target - jb->info.current;

    /*    jb_warn("diff = %d lms=%d last = %d now = %d\n", diff,  */
    /*	jb->info.last_voice_ms, jb->info.last_adjustment, now); */

    /* let's work on non-silent case first */
    if(!jb->info.silence_begin_ts) { 
      /* we want to grow */
      if( (diff > 0) && 
	  /* we haven't grown in the delay length */
	  (((jb->info.last_adjustment + JB_ADJUST_DELAY) < now) || 
	   /* we need to grow more than the "length" we have left */
	   (diff > queue_last(jb)  - queue_next(jb)) ) ) {
              /* grow by interp frame len */
	      jb->info.current += interpl;
              jb->info.next_voice_ts += interpl;
              jb->info.last_voice_ms = interpl;
	      jb->info.last_adjustment = now;
              jb->info.cnt_contig_interp++;
	      jb_dbg("G");
              /* assume silence instead of continuing to interpolate */
              if (jb->info.conf.max_contig_interp && jb->info.cnt_contig_interp >= jb->info.conf.max_contig_interp)
                  jb->info.silence_begin_ts = jb->info.next_voice_ts - jb->info.current;
	      return JB_INTERP;
      }

      frame = queue_get(jb, jb->info.next_voice_ts - jb->info.current);

      /* not a voice frame; just return it. */
      if(frame && frame->type != JB_TYPE_VOICE) {
        /* track start of silence */
	if(frame->type == JB_TYPE_SILENCE) {
	  jb->info.silence_begin_ts = frame->ts;
          jb->info.cnt_contig_interp = 0;
        }

	*frameout = *frame;
	jb->info.frames_out++;
	jb_dbg("o");
	return JB_OK;
      }

      /* voice frame is later than expected */
      if(frame && frame->ts + jb->info.current < jb->info.next_voice_ts) {
        if (frame->ts + jb->info.current > jb->info.next_voice_ts - jb->info.last_voice_ms) {
            /* either we interpolated past this frame in the last jb_get */
            /* or the frame is still in order, but came a little too quick */ 
            *frameout = *frame;
            /* reset expectation for next frame */
            jb->info.next_voice_ts = frame->ts + jb->info.current + frame->ms;
            jb->info.frames_out++;
            decrement_losspct(jb);
            jb->info.cnt_contig_interp = 0;
            jb_dbg("v");
            return JB_OK;
        } else {
      	    /* voice frame is late */
            *frameout = *frame;
            jb->info.frames_out++;
            decrement_losspct(jb);
            jb->info.frames_late++;
            jb->info.frames_lost--;
            jb_dbg("l");
            /*jb_warn("\nlate: wanted=%ld, this=%ld, next=%ld\n", jb->info.next_voice_ts - jb->info.current, frame->ts, queue_next(jb));
            jb_warninfo(jb); */
            return JB_DROP;
        }
      }

      /* keep track of frame sizes, to allow for variable sized-frames */
      if(frame && frame->ms > 0) {
	jb->info.last_voice_ms = frame->ms;
      }

      /* we want to shrink; shrink at 1 frame / 500ms */
      /* unless we don't have a frame, then shrink 1 frame */
      /* every 80ms (though perhaps we can shrink even faster */
      /* in this case) */
      if(diff < -JB_TARGET_EXTRA && 
		((!frame && jb->info.last_adjustment + 80 < now) || 
		 (jb->info.last_adjustment + 500 < now))) {
	jb->info.last_adjustment = now;
        jb->info.cnt_contig_interp = 0;

	if(frame)  {
	  *frameout = *frame;
          /* shrink by frame size we're throwing out */
          jb->info.current -= frame->ms;
	  jb->info.frames_out++;
	  decrement_losspct(jb);
	  jb->info.frames_dropped++;
	  jb_dbg("s");
	  return JB_DROP;
	} else {
          /* shrink by last_voice_ms */
          jb->info.current -= jb->info.last_voice_ms;
	  jb->info.frames_lost++;
	  increment_losspct(jb);
	  jb_dbg("S");
	  return JB_NOFRAME;
	}
      }

      /* lost frame */
      if(!frame) {
	  /* this is a bit of a hack for now, but if we're close to
	   * target, and we find a missing frame, it makes sense to
	   * grow, because the frame might just be a bit late;
	   * otherwise, we presently get into a pattern where we return
	   * INTERP for the lost frame, then it shows up next, and we
	   * throw it away because it's late */
	  /* I've recently only been able to replicate this using
	   * iaxclient talking to app_echo on asterisk.  In this case,
	   * my outgoing packets go through asterisk's (old)
	   * jitterbuffer, and then might get an unusual increasing delay 
	   * there if it decides to grow?? */
	  /* Update: that might have been a different bug, that has been fixed..
	   * But, this still seemed like a good idea, except that it ended up making a single actual
	   * lost frame get interpolated two or more times, when there was "room" to grow, so it might
	   * be a bit of a bad idea overall */
	  /*if(diff > -1 * jb->info.last_voice_ms) { 
	      jb->info.current += jb->info.last_voice_ms;
	      jb->info.last_adjustment = now;
	      jb_warn("g");
	      return JB_INTERP;
	  } */
	  jb->info.frames_lost++;
	  increment_losspct(jb);
          jb->info.next_voice_ts += interpl;
          jb->info.last_voice_ms = interpl;
          jb->info.cnt_contig_interp++;
          /* assume silence instead of continuing to interpolate */
          if (jb->info.conf.max_contig_interp && jb->info.cnt_contig_interp >= jb->info.conf.max_contig_interp)
            jb->info.silence_begin_ts = jb->info.next_voice_ts - jb->info.current;
	  jb_dbg("L");
	  return JB_INTERP;
      }

      /* normal case; return the frame, increment stuff */
      *frameout = *frame;
      jb->info.next_voice_ts += frame->ms;
      jb->info.frames_out++;
      decrement_losspct(jb);
      jb->info.cnt_contig_interp = 0;
      jb_dbg("v");
      return JB_OK;
  } else {     
      /* TODO: after we get the non-silent case down, we'll make the
       * silent case -- basically, we'll just grow and shrink faster
       * here, plus handle next_voice_ts a bit differently */
      
      /* to disable silent special case altogether, just uncomment this: */
       /* jb->info.silence_begin_ts = 0; */

       /* shrink interpl len every 10ms during silence */
       if (diff < -JB_TARGET_EXTRA &&
           jb->info.last_adjustment + 10 <= now) {
         jb->info.current -= interpl;
         jb->info.last_adjustment = now;
       }

       frame = queue_get(jb, now - jb->info.current);
       if(!frame) {
	  return JB_NOFRAME;
       } else if (frame->type != JB_TYPE_VOICE) {
          /* normal case; in silent mode, got a non-voice frame */
          *frameout = *frame;
	  jb->info.frames_out++;
          return JB_OK;
       }
       if (frame->ts < jb->info.silence_begin_ts) {
          /* voice frame is late */
	  *frameout = *frame;
	  jb->info.frames_out++;
	  decrement_losspct(jb);
	  jb->info.frames_late++;
	  jb->info.frames_lost--;
	  jb_dbg("l");
	  /*jb_warn("\nlate: wanted=%ld, this=%ld, next=%ld\n", jb->info.next_voice_ts - jb->info.current, frame->ts, queue_next(jb));
	jb_warninfo(jb); */
	  return JB_DROP;
       } else { 
          /* voice frame */
	  /* try setting current to target right away here */
	  jb->info.current = jb->info.target;
	  jb->info.silence_begin_ts = 0;
	  jb->info.next_voice_ts = frame->ts + jb->info.current + frame->ms;
	  jb->info.last_voice_ms = frame->ms;
	  jb->info.frames_out++;
	  decrement_losspct(jb);
	  *frameout = *frame;
	  jb_dbg("V");
	  return JB_OK;
       }
  }
}

long jb_next(jitterbuf *jb) 
{
    if(jb->info.silence_begin_ts) {
      long next = queue_next(jb);
      if(next > 0) { 
        /* shrink during silence */
        if (jb->info.target - jb->info.current < -JB_TARGET_EXTRA)
          return jb->info.last_adjustment + 10;
        return next + jb->info.target;
      }
      else return JB_LONGMAX;
    } else {
      return jb->info.next_voice_ts;
    }
}

int jb_get(jitterbuf *jb, jb_frame *frameout, long now, long interpl) 
{
    int ret = _jb_get(jb,frameout,now,interpl);
#if 0
    static int lastts=0;
    int thists = ((ret == JB_OK) || (ret == JB_DROP)) ? frameout->ts : 0;
    jb_warn("jb_get(%x,%x,%ld) = %d (%d)\n", jb, frameout, now, ret, thists);
    if(thists && thists < lastts) jb_warn("XXXX timestamp roll-back!!!\n");
    lastts = thists;
#endif
    return ret;
}

int jb_getall(jitterbuf *jb, jb_frame *frameout) 
{
    jb_frame *frame;
    frame = queue_getall(jb);

    if(!frame) {
      return JB_NOFRAME;
    }

    *frameout = *frame;
    return JB_OK;
}


int jb_getinfo(jitterbuf *jb, jb_info *stats) 
{

    history_get(jb);

    *stats = jb->info;

  return JB_OK;
}

int jb_setconf(jitterbuf *jb, jb_conf *conf) 
{
  /* take selected settings from the struct */

	jb->info.conf.max_jitterbuf = conf->max_jitterbuf;
 	jb->info.conf.resync_threshold = conf->resync_threshold;
	jb->info.conf.max_contig_interp = conf->max_contig_interp;

  return JB_OK;
}


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -