mirror of
				https://github.com/asterisk/asterisk.git
				synced 2025-10-31 10:47:18 +00:00 
			
		
		
		
	translate: Enables native Packet-Loss Concealment (PLC) for supporting codecs.
This reverts commit 5bfef2a8b4 as it
caused fax test failures.
ASTERISK-25629
Change-Id: I79de974dc4f63a1cafe0d2509169fd9a6b3cbaf4
			
			
This commit is contained in:
		
							
								
								
									
										133
									
								
								main/translate.c
									
									
									
									
									
								
							
							
						
						
									
										133
									
								
								main/translate.c
									
									
									
									
									
								
							| @@ -358,7 +358,6 @@ static struct ast_trans_pvt *newpvt(struct ast_translator *t, struct ast_format | ||||
| 	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 | ||||
| @@ -525,46 +524,13 @@ struct ast_trans_pvt *ast_translator_build_path(struct ast_format *dst, struct a | ||||
| /*! \brief do the actual translation */ | ||||
| struct ast_frame *ast_translate(struct ast_trans_pvt *path, struct ast_frame *f, int consume) | ||||
| { | ||||
| 	const unsigned int rtp_seqno_max_value = 0xffff; | ||||
| 	struct ast_frame *out_last, *out = NULL; | ||||
| 	struct ast_trans_pvt *step; | ||||
| 	struct ast_trans_pvt *p = path; | ||||
| 	struct ast_frame *out; | ||||
| 	struct timeval delivery; | ||||
| 	int has_timing_info; | ||||
| 	long ts; | ||||
| 	long len; | ||||
| 	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; | ||||
| 	} | ||||
| 	int seqno; | ||||
|  | ||||
| 	has_timing_info = ast_test_flag(f, AST_FRFLAG_HAS_TIMING_INFO); | ||||
| 	ts = f->ts; | ||||
| @@ -594,93 +560,18 @@ struct ast_frame *ast_translate(struct ast_trans_pvt *path, struct ast_frame *f, | ||||
| 			 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; | ||||
|  | ||||
| 	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; | ||||
| 		} | ||||
|  | ||||
| 		/* 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; | ||||
| 		do { | ||||
| 			framein(p, current); | ||||
| 			current = AST_LIST_NEXT(current, frame_list); | ||||
| 		} while (current); | ||||
| 		if (out != f) { | ||||
| 			ast_frfree(out); | ||||
| 		} | ||||
| 		out = p->t->frameout(p); | ||||
| 	} | ||||
|  | ||||
| 	if (out) { | ||||
| 		/* we have a frame, play with times */ | ||||
| 		if (!ast_tvzero(delivery)) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user