[Asterisk-code-review] translate: Enables native Packet-Loss Concealment (PLC) for ... (asterisk[master])

Joshua Colp asteriskteam at digium.com
Thu Jun 9 07:24:47 CDT 2016


Joshua Colp has submitted this change and it was merged.

Change subject: translate: Enables native Packet-Loss Concealment (PLC) for supporting codecs.
......................................................................


translate: Enables native Packet-Loss Concealment (PLC) for supporting codecs.

ASTERISK-25629 #close

Change-Id: Ibfcf0670e094e9718d82fd9920f1fb2dae122006
---
M main/translate.c
1 file changed, 121 insertions(+), 12 deletions(-)

Approvals:
  Joshua Colp: Looks good to me, approved; Verified
  Matthew Fredrickson: Looks good to me, but someone else must approve



diff --git a/main/translate.c b/main/translate.c
index 8d37e37..b7443b8 100644
--- a/main/translate.c
+++ b/main/translate.c
@@ -358,6 +358,7 @@
 	pvt->f.offset = AST_FRIENDLY_OFFSET;
 	pvt->f.src = pvt->t->name;
 	pvt->f.data.ptr = pvt->outbuf.c;
+	pvt->f.seqno = 0x10000;
 
 	/*
 	 * If the translator has not provided a format
@@ -524,13 +525,46 @@
 /*! \brief do the actual translation */
 struct ast_frame *ast_translate(struct ast_trans_pvt *path, struct ast_frame *f, int consume)
 {
-	struct ast_trans_pvt *p = path;
-	struct ast_frame *out;
+	const unsigned int rtp_seqno_max_value = 0xffff;
+	struct ast_frame *out_last, *out = NULL;
+	struct ast_trans_pvt *step;
 	struct timeval delivery;
 	int has_timing_info;
 	long ts;
 	long len;
-	int seqno;
+	int seqno, frames_missing;
+
+	/* Determine the amount of lost packets for PLC */
+	/* But not at start with first frame = path->f.seqno is still 0x10000 */
+	/* But not when there is no sequence number = frame created internally */
+	if ((path->f.seqno <= rtp_seqno_max_value) && (path->f.seqno != f->seqno)) {
+		if (f->seqno < path->f.seqno) { /* seqno overrun situation */
+			frames_missing = rtp_seqno_max_value + f->seqno - path->f.seqno - 1;
+		} else {
+			frames_missing = f->seqno - path->f.seqno - 1;
+		}
+		/* Out-of-order packet - more precise: late packet */
+		if ((rtp_seqno_max_value + 1) / 2 < frames_missing) {
+			if (consume) {
+				ast_frfree(f);
+			}
+			/*
+			 * Do not pass late packets to any transcoding module, because that
+			 * confuses the state of any library (packets inter-depend). With
+			 * the next packet, this one is going to be treated as lost packet.
+			 */
+			return NULL;
+		}
+
+		if (frames_missing > 96) {
+			struct ast_str *str = ast_str_alloca(256);
+
+			/* not DEBUG but NOTICE because of WARNING in main/cannel.c:__ast_queue_frame */
+			ast_log(LOG_NOTICE, "%d lost frame(s) %d/%d %s\n", frames_missing, f->seqno, path->f.seqno, ast_translate_path_to_str(path, &str));
+		}
+	} else {
+		frames_missing = 0;
+	}
 
 	has_timing_info = ast_test_flag(f, AST_FRFLAG_HAS_TIMING_INFO);
 	ts = f->ts;
@@ -560,18 +594,93 @@
 			 f->samples, ast_format_get_sample_rate(f->subclass.format)));
 	}
 	delivery = f->delivery;
-	for (out = f; out && p ; p = p->next) {
-		struct ast_frame *current = out;
 
-		do {
-			framein(p, current);
-			current = AST_LIST_NEXT(current, frame_list);
-		} while (current);
-		if (out != f) {
-			ast_frfree(out);
+	for (out_last = NULL; frames_missing + 1; frames_missing--) {
+		struct ast_frame *frame_to_translate, *inner_head;
+		struct ast_frame missed = {
+			.frametype = AST_FRAME_VOICE,
+			.subclass.format = f->subclass.format,
+			.datalen = 0,
+			/* In RTP, the amount of samples might change anytime  */
+			/* If that happened while frames got lost, what to do? */
+			.samples = f->samples, /* FIXME */
+			.src = __FUNCTION__,
+			.data.uint32 = 0,
+			.delivery.tv_sec = 0,
+			.delivery.tv_usec = 0,
+			.flags = 0,
+			/* RTP sequence number is between 0x0001 and 0xffff */
+			.seqno = (rtp_seqno_max_value + 1 + f->seqno - frames_missing) & rtp_seqno_max_value,
+		};
+
+		if (frames_missing) {
+			frame_to_translate = &missed;
+		} else {
+			frame_to_translate = f;
 		}
-		out = p->t->frameout(p);
+
+		/* The translation path from one format to another might contain several steps */
+		/* out* collects the result for missed frame(s) and input frame(s) */
+		/* out is the result of the conversion of all frames, translated into the destination format */
+		/* out_last is the last frame in that list, to add frames faster */
+		for (step = path, inner_head = frame_to_translate; inner_head && step; step = step->next) {
+			struct ast_frame *current, *inner_last, *inner_prev = frame_to_translate;
+
+			/* inner* collects the result of each conversion step, the input for the next step */
+			/* inner_head is a list of frames created by each conversion step */
+			/* inner_last is the last frame in that list, to add frames faster */
+			for (inner_last = NULL, current = inner_head; current; current = AST_LIST_NEXT(current, frame_list)) {
+				struct ast_frame *tmp;
+
+				framein(step, current);
+				tmp = step->t->frameout(step);
+
+				if (!tmp) {
+					continue;
+				} else if (inner_last) {
+					struct ast_frame *t;
+
+					/* Determine the last frame of the list before appending to it */
+					while ((t = AST_LIST_NEXT(inner_last, frame_list))) {
+						inner_last = t;
+					}
+					AST_LIST_NEXT(inner_last, frame_list) = tmp;
+				} else {
+					inner_prev = inner_head;
+					inner_head = tmp;
+					inner_last = tmp;
+				}
+			}
+
+			/* The current step did not create any frames = no frames for the next step */
+			/* The steps are not lost because framein buffered those for the next input frame */
+			if (!inner_last) {
+				inner_prev = inner_head;
+				inner_head = NULL;
+			}
+			if (inner_prev != frame_to_translate) {
+				ast_frfree(inner_prev); /* Frees just the intermediate lists */
+			}
+		}
+
+		/* This frame created no frames after translation = continue with next frame */
+		/* The frame is not lost because framein buffered it to be combined with the next frame */
+		if (!inner_head) {
+			continue;
+		} else if (out_last) {
+			struct ast_frame *t;
+
+			/* Determine the last frame of the list before appending to it */
+			while ((t = AST_LIST_NEXT(out_last, frame_list))) {
+				out_last = t;
+			}
+			AST_LIST_NEXT(out_last, frame_list) = inner_head;
+		} else {
+			out = inner_head;
+			out_last = inner_head;
+		}
 	}
+
 	if (out) {
 		/* we have a frame, play with times */
 		if (!ast_tvzero(delivery)) {

-- 
To view, visit https://gerrit.asterisk.org/1820
To unsubscribe, visit https://gerrit.asterisk.org/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: Ibfcf0670e094e9718d82fd9920f1fb2dae122006
Gerrit-PatchSet: 16
Gerrit-Project: asterisk
Gerrit-Branch: master
Gerrit-Owner: Alexander Traud <pabstraud at compuserve.com>
Gerrit-Reviewer: Alexander Traud <pabstraud at compuserve.com>
Gerrit-Reviewer: Anonymous Coward #1000019
Gerrit-Reviewer: Jaco Kroon <jaco at uls.co.za>
Gerrit-Reviewer: Joshua Colp <jcolp at digium.com>
Gerrit-Reviewer: Matthew Fredrickson <creslin at digium.com>
Gerrit-Reviewer: Richard Mudgett <rmudgett at digium.com>



More information about the asterisk-code-review mailing list