Ejemplo n.º 1
0
/***********
 * returns JB_OK if a frame is available and *data points to the packet
 * returns JB_NOFRAME if it's no time to play voice and or no frame available
 * returns JB_INTERP if interpolating is required
 * returns JB_EMPTY if no voice frame is in the jitterbuffer (only during silence)
 * 
 * if the next frame is a silence frame we will go in silence-mode
 * each new instance of the jitterbuffer will start in silence mode
 * in silence mode we will set the jitterbuffer to the size we want
 * when we are not in silence mode get_voicecase will handle the rest. 
 */
static int get_voice(jitterbuffer *jb, void **data, long now, long interpl) 
{
  jb_frame *frame;
  long diff;
  int result;
  
  diff = jb->target - jb->current;
  
  //if the next frame is a silence frame, go in silence mode...
  if((get_next_frametype(jb, now - jb->current) == JB_TYPE_SILENCE) ) {
    jb_dbg("gs");
    frame = get_frame(jb, now - jb->current);
    *data = frame->data;
    frame->data = NULL;
    jb->info.silence =1;
    jb->silence_begin_ts = frame->ts;
    frame_free(frame);
    result = JB_OK;
  } else {  
    if(jb->info.silence) { // we are in silence
      /*
       * During silence we can set the jitterbuffer size to the size
       * we want...
       */
      if (diff) {
        jb->current = jb->target;
      }
      frame = get_frame(jb, now - jb->current);
      if (frame) {
        if (jb->silence_begin_ts && frame->ts < jb->silence_begin_ts) {
          jb_dbg("gL");
          /* voice frame is late, next!*/
          jb->info.frames_late++;
          frame_free(frame);
          result = get_voice(jb, data, now, interpl);
        } else {
          jb_dbg("gP"); 
          /* voice frame */
          jb->info.silence = 0;
          jb->silence_begin_ts = 0;
          jb->next_voice_time = frame->ts + frame->ms;
          jb->info.last_voice_ms = frame->ms;
          *data = frame->data;
          frame->data = NULL;
          frame_free(frame);
          result = JB_OK;
        }
      } else {    //no frame 
        jb_dbg("gS");
        result = JB_EMPTY;
      }
    } else { //voice case
      result = get_voicecase(jb,data,now,interpl,diff);
    }
  }
  return result;
}
Ejemplo n.º 2
0
static jb_frame *_queue_get(jitterbuf *jb, long ts, int all) 
{
	jb_frame *frame;
	frame = jb->frames;

	if (!frame)
		return NULL;

	jb_dbg("queue_get: ASK %ld FIRST %ld\n", ts, frame->ts); 
	
	if (all || ts >= frame->ts) {
		/* remove this frame */
		frame->prev->next = frame->next;
		frame->next->prev = frame->prev;

		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;
}
Ejemplo n.º 3
0
/***********
 * validates the statistics
 * the losspct due the jitterbuffer will be calculated.
 * delay and delay_target will be calculated
 * *stats = info
 */
void jb_get_info(jitterbuffer *jb, jb_info *stats) 
{
  long max_index, pointer;
  
  jb_dbg("I");
  if (jb == NULL) {
    jb_err("no jitterbuffer in jb_get_info()\n");
    return;
  }
  
  jb->info.delay = jb->current - jb->min;
  jb->info.delay_target = jb->target - jb->min;
  
  //calculate the losspct...
  max_index = (jb->hist_pointer < JB_HISTORY_SIZE) ? 
jb->hist_pointer : JB_HISTORY_SIZE-1;
  if (max_index>1) {
    pointer = find_pointer(&jb->hist_sorted_delay[0], max_index, 
jb->current);
    jb->info.losspct = ((max_index - pointer)*100/max_index);
    if (jb->info.losspct < 0) {
      jb->info.losspct = 0;
    }
  } else {
    jb->info.losspct = 0;
  }
  
  *stats = jb->info;
}
Ejemplo n.º 4
0
/***********
 * Set settings for the jitterbuffer. 
 * Only if a setting is defined it will be written
 * in the jb->settings.
 * This means that no setting can be set to zero
 */
void jb_set_settings(jitterbuffer *jb, jb_settings *settings) 
{
  jb_dbg("S");
  if (jb == NULL) {
    jb_err("no jitterbuffer in jb_set_settings()\n");
    return;
  }
  
  if (settings->min_jb) {
    jb->settings.min_jb = settings->min_jb;
  }
  if (settings->max_jb) {
    jb->settings.max_jb = settings->max_jb;
  }
  if (settings->max_successive_interp) {
    jb->settings.max_successive_interp = settings->max_successive_interp;
  }
  if (settings->extra_delay) {
    jb->settings.extra_delay = settings->extra_delay;
  }
  if (settings->wait_grow) {
    jb->settings.wait_grow = settings->wait_grow;
  }
  if (settings->wait_shrink) {
    jb->settings.wait_shrink = settings->wait_shrink;
  }
  if (settings->max_diff) {
    jb->settings.max_diff = settings->max_diff;
  }
}
Ejemplo n.º 5
0
/***********
 * gives the settings for this jitterbuffer
 * *settings = settings
 */
void jb_get_settings(jitterbuffer *jb, jb_settings *settings) 
{
  jb_dbg("S");
  if (jb == NULL) {
    jb_err("no jitterbuffer in jb_get_settings()\n");
    return;
  }
  
  *settings = jb->settings;
}
Ejemplo n.º 6
0
/***********
 * Put a packet into the jitterbuffers 
 * Only the timestamps of voicepackets are put in the history
 * this because the jitterbuffer only works for voicepackets
 * don't put packets twice in history and queue (e.g. transmitting every frame twice)
 * keep track of statistics
 */
void jb_put(jitterbuffer *jb, void *data, int type, long ms, long ts, long now, int codec) 
{ 
  long pointer, max_index;
  
  if (jb == NULL) {
    jb_err("no jitterbuffer in jb_put()\n");
    return;
  }
  
  jb->info.frames_received++;

  if (type == JB_TYPE_CONTROL) {
    //put the packet into the contol-queue of the jitterbuffer
    jb_dbg("pC");
    put_control(jb,data,type,ts);

  } else if (type == JB_TYPE_VOICE) {
    // only add voice that aren't already in the buffer
    max_index = (jb->hist_pointer < JB_HISTORY_SIZE) ? jb->hist_pointer : JB_HISTORY_SIZE-1;
    pointer = find_pointer(&jb->hist_sorted_timestamp[0], max_index, ts);
    if (jb->hist_sorted_timestamp[pointer]==ts) { //timestamp already in queue
      jb_dbg("pT");
      free(data); 
      jb->info.frames_dropped_twice++;
    } else { //add
      jb_dbg("pV");
      /* add voicepacket to history */
      put_history(jb,ts,now,ms,codec);
      /*calculate jitterbuffer size*/
      calculate_info(jb, ts, now, codec);
      /*put the packet into the queue of the jitterbuffer*/
      put_voice(jb,data,type,ms,ts,codec);
    } 

  } else if (type == JB_TYPE_SILENCE){ //silence
    jb_dbg("pS");
    put_voice(jb,data,type,ms,ts,codec);

  } else {//should NEVER happen
    jb_err("jb_put(): type not known\n");
    free(data);
  }
}
Ejemplo n.º 7
0
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");
}
Ejemplo n.º 8
0
/***********
 * destroy the jitterbuffer
 * free all the [non]voice frames with reset_all
 * free the jitterbuffer
 */
void jb_destroy(jitterbuffer *jb) 
{
  jb_dbg("D");
  if (jb == NULL) {
    jb_err("no jitterbuffer in jb_destroy()\n");
    return;
  }
  
  jb_reset_all(jb);
  free(jb);
}
Ejemplo n.º 9
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);
}
Ejemplo n.º 10
0
/***********
 * create a new jitterbuffer
 * return NULL if malloc doesn't work
 * else return jb with default_settings.
 */
jitterbuffer *jb_new() 
{
  jitterbuffer *jb;
  
  jb_dbg("N");
  jb = tsk_calloc(1, sizeof(jitterbuffer));
  if (!jb) {
    jb_err("cannot allocate jitterbuffer\n");
    return NULL;
  }
  set_default_settings(jb);
  reset(jb);
  return jb;
}
Ejemplo n.º 11
0
/***********
 * if there are any frames left in JB returns JB_OK, otherwise returns JB_EMPTY
 */
int jb_has_frames(jitterbuffer *jb)
{
  jb_dbg("H");
  if (jb == NULL) {
    jb_err("no jitterbuffer in jb_has_frames()\n");
    return JB_NOJB;
  }
  
  if(jb->controlframes || jb->voiceframes) {
    return JB_OK;
  } else {
    return JB_EMPTY;
  }
}
Ejemplo n.º 12
0
/***********
 * control frames have a higher priority then voice frames
 * returns JB_OK if a frame is available and *data points to the packet
 * returns JB_NOFRAME if it's no time to play voice and no control available
 * returns JB_INTERP if interpolating is required
 * returns JB_EMPTY if no voice frame is in the jitterbuffer (only during silence)
 */
int jb_get(jitterbuffer *jb, void **data, long now, long interpl) 
{
  int result;
  
  jb_dbg("A");
  if (jb == NULL) {
    jb_err("no jitterbuffer in jb_get()\n");
    return JB_NOJB;
  }
  
  result = get_control(jb, data);
  if (result != JB_OK ) { //no control message available maybe there is voice...
    result = get_voice(jb, data, now, interpl);
  }
  return result;
}
Ejemplo n.º 13
0
/***********
 * if there is a nonvoice frame it will be returned [*data] and the frame
 * will be made free
 */  
static int get_control(jitterbuffer *jb, void **data) 
{
  jb_frame *frame;
  int result;
  
  frame = jb->controlframes;
  if (frame) {
    jb_dbg("gC");
    *data = frame->data;
    frame->data = NULL;
    jb->controlframes = frame->next;
    frame_free(frame);
    result = JB_OK;
  } else {
    result = JB_NOFRAME;
  }
  return result;
}
Ejemplo n.º 14
0
/***********
 * empty voice messages 
 * reset statistics 
 * keep the settings
 */
void jb_reset(jitterbuffer *jb) 
{
  jb_frame *frame;
  
  jb_dbg("R");
  if (jb == NULL) {
    jb_err("no jitterbuffer in jb_reset()\n");
    return;
  }
  
  //free voice
  while(jb->voiceframes) {
    frame = get_all_frames(jb);
    frame_free(frame);
  }
  //reset stats
  memset(&(jb->info),0,sizeof(jb_info) );
  // set default settings
  reset(jb);
}
Ejemplo n.º 15
0
/***********
 * empty nonvoice messages
 * empty voice messages
 * reset statistics 
 * reset settings to default
 */
void jb_reset_all(jitterbuffer *jb) 
{
  jb_frame *frame;
  
  jb_dbg("r");
  if (jb == NULL) {
    jb_err("no jitterbuffer in jb_reset_all()\n");
    return;
  }
  
  // free nonvoice
  while(jb->controlframes) {
    frame = jb->controlframes;
    jb->controlframes = frame->next;
    frame_free(frame);
  }
  // free voice and reset statistics is done by jb_reset
  jb_reset(jb);
  set_default_settings(jb);
}
Ejemplo n.º 16
0
static int history_put(jitterbuf *jb, long ts, long now, long ms) 
{
	long delay = now - (ts - jb->info.resync_offset);
	long threshold = 2 * jb->info.jitter + jb->conf.resync_threshold;
	long kicked;

	/* check if a resync has been requested, or is needed */
	if (jb->force_resync) {
		resync(jb, ts, now);
		delay = 0;
	}

	/* don't add special/negative times to history */
	if (ts <= 0) 
		return 0;

	/* check for drastic change in delay */
	if (jb->conf.resync_threshold != -1) {
	    if (abs(delay - jb->info.last_delay) > threshold) {
			jb->info.cnt_delay_discont++;
			if (jb->info.cnt_delay_discont > 3) {
				resync(jb, ts, now);
				delay = 0;
			} else {
			    jb_dbg("Semiresyncing!\n");
				return -1;
			}
		} else {
			jb->info.last_delay = delay;
			jb->info.cnt_delay_discont = 0;
		}
	}

	kicked = jb->history[jb->hist_ptr % JB_HISTORY_SZ];

	jb->history[(jb->hist_ptr++) % JB_HISTORY_SZ] = delay;

	/* optimization; the max/min buffers don't need to be recalculated, if this packet's
	 * entry doesn't change them.  This happens if this packet is not involved, _and_ any packet
	 * that got kicked out of the history is also not involved 
	 * We do a number of comparisons, but it's probably still worthwhile, because it will usually
	 * succeed, and should be a lot faster than going through all 500 packets in history */
	if (!jb->hist_maxbuf_valid)
		return 0;

	/* don't do this until we've filled history 
	 * (reduces some edge cases below) */
	if (jb->hist_ptr < JB_HISTORY_SZ)
		goto invalidate;

	/* if the new delay would go into min */
	if (delay < jb->hist_minbuf[JB_HISTORY_MAXBUF_SZ-1])
		goto invalidate;
    
	/* or max.. */
	if (delay > jb->hist_maxbuf[JB_HISTORY_MAXBUF_SZ-1])
		goto invalidate;

	/* or the kicked delay would be in min */
	if (kicked <= jb->hist_minbuf[JB_HISTORY_MAXBUF_SZ-1]) 
		goto invalidate;

	if (kicked >= jb->hist_maxbuf[JB_HISTORY_MAXBUF_SZ-1]) 
		goto invalidate;

	/* if we got here, we don't need to invalidate, 'cause this delay didn't 
	 * affect things */
	return 0;
	/* end optimization */


invalidate:
	jb->hist_maxbuf_valid = 0;
	return 0;
}
Ejemplo n.º 17
0
/***********
 * The voicecase has four 'options'
 * - difference is way off, reset
 * - diff > 0, we may need to grow
 * - diff < 0, we may need to shrink
 * - everything else
 */
static int get_voicecase(jitterbuffer *jb, void **data, long now, long interpl, long diff) 
{
  jb_frame *frame;
  int result;
  
   // * - difference is way off, reset
  if (diff > jb->settings.max_diff || -diff > jb->settings.max_diff) {
    jb_err("wakko diff in get_voicecase\n");
    reset(jb); //reset hist because the timestamps are wakko. 
    result = JB_NOFRAME;
  //- diff > 0, we may need to grow
  } else if ((diff > 0) && 
                   (now > (jb->last_adjustment + jb->settings.wait_grow) 
                    || (now + jb->current + interpl) < get_next_framets(jb) ) ) { //grow
    /* first try to grow */
    if (diff<interpl/2) {
      jb_dbg("ag");
      jb->current +=diff;
    } else {
      jb_dbg("aG");
      /* grow by interp frame len */
      jb->current += interpl;
    }
    jb->last_adjustment = now;
    result = get_voice(jb, data, now, interpl);
  //- diff < 0, we may need to shrink
  } else if ( (diff < 0) 
                && (now > (jb->last_adjustment + jb->settings.wait_shrink)) 
                && ((-diff) > jb->settings.extra_delay) ) {
    /* now try to shrink
     * if there is a frame shrink by frame length
     * otherwise shrink by interpl
     */
    jb->last_adjustment = now;
    
    frame = get_frame(jb, now - jb->current);
    if(frame) {
      jb_dbg("as");
      /* shrink by frame size we're throwing out */
      jb->info.frames_dropped++;
      jb->current -= frame->ms;
      frame_free(frame);
    } else {
      jb_dbg("aS");
      /* shrink by interpl */
      jb->current -= interpl;
    }
    result = get_voice(jb, data, now, interpl);
  } else  { 
    /* if it is not the time to play a result = JB_NOFRAME
     * else We try to play a frame if a frame is available
     * and not late it is played otherwise 
     * if available it is dropped and the next is tried
     * last option is interpolating
     */
    if (now - jb->current < jb->next_voice_time) {
      jb_dbg("aN");
      result = JB_NOFRAME;
    } else {
      frame = get_frame(jb, now - jb->current);
      if (frame) { //there is a frame
        /* voice frame is late */
        if(frame->ts < jb->next_voice_time) {   //late
          jb_dbg("aL");
          jb->info.frames_late++;
          frame_free(frame);
          result = get_voice(jb, data, now, interpl);
        } else {
          jb_dbg("aP");
          /* normal case; return the frame, increment stuff */
          *data = frame->data;
          frame->data = NULL;
          jb->next_voice_time = frame->ts + frame->ms;
          jb->cnt_successive_interp = 0;
          frame_free(frame);
          result = JB_OK;
        }
      } else { // no frame, thus interpolate
        jb->cnt_successive_interp++;
        /* assume silence instead of continuing to interpolate */
        if (jb->settings.max_successive_interp && jb->cnt_successive_interp >= jb->settings.max_successive_interp) {
          jb->info.silence = 1;
          jb->silence_begin_ts = jb->next_voice_time;
        }
        jb_dbg("aI");
        jb->next_voice_time += interpl;
        result = JB_INTERP;
      }
    }
  }
  return result;

}
Ejemplo n.º 18
0
static int _jb_get(jitterbuf *jb, jb_frame *frameout, long now, long interpl) 
{
	jb_frame *frame;
	long diff;
	static int dbg_cnt = 0;

	/*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);

	if (dbg_cnt && dbg_cnt % 50 == 0) {
		jb_dbg("\n");
	}
	dbg_cnt++;

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

	/* if a hard clamp was requested, use it */
	if ((jb->conf.max_jitterbuf) && ((jb->info.target - jb->info.min) > jb->conf.max_jitterbuf)) {
		jb_dbg("clamping target from %d to %d\n", (jb->info.target - jb->info.min), jb->conf.max_jitterbuf);
		jb->info.target = jb->info.min + jb->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 length */
			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++;
			if (jb->conf.max_contig_interp && jb->info.cnt_contig_interp >= jb->conf.max_contig_interp) {
				jb->info.silence_begin_ts = jb->info.next_voice_ts - jb->info.current;
			}
			jb_dbg("G");
			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) {
			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 callweaver.  In this case,
			 * my outgoing packets go through callweaver'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++;
			if (jb->conf.max_contig_interp && jb->info.cnt_contig_interp >= jb->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++;
		jb->info.cnt_contig_interp = 0;
		decrement_losspct(jb);
		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) {
			jb_dbg("Didn't get a frame from queue\n");
			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;
		}
	}
}
Ejemplo n.º 19
0
/* returns 1 if frame was inserted into head of queue, 0 otherwise */
static int queue_put(jitterbuf *jb, void *data, int type, long ms, long ts) 
{
	jb_frame *frame;
	jb_frame *p;
	int head = 0;
	long resync_ts = ts - jb->info.resync_offset;

	frame = jb->free;
	if (frame) {
		jb->free = frame->next;
	} else {
		frame = malloc(sizeof(jb_frame));
	}

	if (!frame) {
		jb_err("cannot allocate frame\n");
		return 0;
	}

	jb->info.frames_cur++;

	frame->data = data;
	frame->ts = resync_ts;
	frame->ms = ms;
	frame->type = type;

	/* 
	 * frames are a circular list, jb-frames points to to the lowest ts, 
	 * jb->frames->prev points to the highest ts
	 */

	if (!jb->frames) {  /* queue is empty */
		jb->frames = frame;
		frame->next = frame;
		frame->prev = frame;
		head = 1;
	} else if (resync_ts < jb->frames->ts) {
		frame->next = jb->frames;
		frame->prev = jb->frames->prev;

		frame->next->prev = frame;
		frame->prev->next = frame;

		/* frame is out of order */
		jb->info.frames_ooo++;

		jb->frames = frame;
		head = 1;
	} else { 
		p = jb->frames;

		/* frame is out of order */
		if (resync_ts < p->prev->ts) jb->info.frames_ooo++;

		while (resync_ts < p->prev->ts && p->prev != jb->frames) 
			p = p->prev;

		frame->next = p;
		frame->prev = p->prev;

		frame->next->prev = frame;
		frame->prev->next = frame;
	}

	jb_dbg("Head ts=%d  rsoffs=%d\n", jb->frames->ts, jb->info.resync_offset);
	return head;
}