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

📄 jitterbuf.c

📁 来自网络的iaxclient的协议栈源码
💻 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_DEBUGstatic 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");}#endifenum jb_return_code jb_put(jitterbuf *jb, void *data, const enum jb_frame_type 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 enum jb_return_code _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->info.conf.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 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++;			/* 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("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) {			/* 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->info.conf.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++;		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->info.conf.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) {		if (jb->frames) {			long next = queue_next(jb);			history_get(jb);			/* shrink during silence */			if (jb->info.target - jb->info.current < -jb->info.conf.target_extra)				return jb->info.last_adjustment + 10;			return next + jb->info.target;		}		else			return JB_LONGMAX;	} else {		return jb->info.next_voice_ts;	}}enum jb_return_code jb_get(jitterbuf *jb, jb_frame *frameout, long now, long interpl){	enum jb_return_code 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;}enum jb_return_code jb_getall(jitterbuf *jb, jb_frame *frameout){	jb_frame *frame;	frame = queue_getall(jb);	if (!frame) {		return JB_NOFRAME;	}	*frameout = *frame;	return JB_OK;}enum jb_return_code jb_getinfo(jitterbuf *jb, jb_info *stats){	history_get(jb);	*stats = jb->info;	return JB_OK;}enum jb_return_code 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;	/* -1 indicates use of the default JB_TARGET_EXTRA value */	jb->info.conf.target_extra = ( conf->target_extra == -1 )		? JB_TARGET_EXTRA		: conf->target_extra		;	/* update these to match new target_extra setting */	jb->info.current = jb->info.conf.target_extra;	jb->info.target = jb->info.conf.target_extra;	return JB_OK;}

⌨️ 快捷键说明

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