--- main/translate.c (Astaerisk 13.6.0) +++ main/translate.c (working copy) @@ -513,4 +526,4 @@ { - struct ast_trans_pvt *p = path; - struct ast_frame *out; + struct ast_trans_pvt *p; + struct ast_frame *list, *out = NULL; struct timeval delivery; @@ -520,2 +533,3 @@ int seqno; + unsigned int frames_missing = 0; @@ -530,2 +544,23 @@ if (!ast_tveq(path->nextin, f->delivery)) { + /* For native PLC, determine the amout of lost packets */ + if (path->t->native_plc && path->f.seqno) { /* not at start 0 */ + if (seqno < path->f.seqno) { /* seqno overrun situation */ + frames_missing = 0xffff + seqno - path->f.seqno - 1; + } else { + frames_missing = seqno - path->f.seqno - 1; + } + /* Out-of-order packet - more precise: late packet */ + if (0x7fff < frames_missing) { + if (consume) { + ast_frfree(f); + } + /* + * Do not pass a late packet to transcoding module, + * because that confuses the internal state of the + * library (packets inter-depent). With the next valid + * packet, this is going to be threated as lost packet. + */ ast_log(LOG_NOTICE, "late packet %d; expected %d\n", seqno, path->f.seqno+1); + return NULL; + } ast_log(LOG_NOTICE, "%d lost packet(s) - %d/%d\n", frames_missing, seqno, path->f.seqno); + } /* The time has changed between what we expected and this @@ -549,14 +584,47 @@ 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); + while (0 < frames_missing) { /* lost packet(s) */ + struct ast_frame *missed = ast_malloc(sizeof(*missed)); + + if (missed) { + *missed = ast_null_frame; + missed->samples = f->samples; + missed->subclass.format = ao2_bump(f->subclass.format); + missed->seqno = seqno - frames_missing; + AST_LIST_NEXT(missed, frame_list) = f; + f = missed; /* f is head because of if (consume) then ast_free(f) */ } - out = p->t->frameout(p); + + frames_missing--; } + + for (list = f; list; list = AST_LIST_NEXT(list, frame_list)) { + struct ast_frame *inner; + + for (inner = list, p = path; inner && p; p = p->next) { + framein(p, inner); + if (inner != list) { + ast_frfree(inner); + } + inner = p->t->frameout(p); + } + if (out && inner) { + struct ast_frame *current = out; + + while (current != inner && AST_LIST_NEXT(current, frame_list)) { + current = AST_LIST_NEXT(current, frame_list); + } + /* + * Now, 'current' points to the + * A) last element in the list of 'out' (inner is new), or + * B) is the same as 'inner' (exists already in list). + */ + if (current != inner) { + AST_LIST_NEXT(current, frame_list) = inner; + } + } else if (inner) { + out = inner; + } + } + if (out) {