forked from seanbright/asterisk-opus
-
Notifications
You must be signed in to change notification settings - Fork 22
/
enable_native_plc.patch
156 lines (153 loc) · 5.18 KB
/
enable_native_plc.patch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
--- a/main/translate.c (Asterisk 13.17.2)
+++ b/main/translate.c (working copy)
@@ -359,4 +359,5 @@
pvt->f.src = pvt->t->name;
pvt->f.data.ptr = pvt->outbuf.c;
+ pvt->f.seqno = 0x10000;
/*
@@ -531,11 +532,44 @@
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_trans_pvt *p = path;
- struct ast_frame *out;
+ struct ast_frame *out_last, *out = NULL;
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);
@@ -567,16 +601,91 @@
}
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;
+ }
+
+ /* 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 (p = path, inner_head = frame_to_translate; inner_head && p; p = p->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(p, current);
+ tmp = p->t->frameout(p);
+
+ 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;
}
- out = p->t->frameout(p);
}
+
if (out) {
/* we have a frame, play with times */