FreeSWITCH API Documentation  1.7.0
switch_jitterbuffer.c
Go to the documentation of this file.
1 /*
2  * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
3  * Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org>
4  *
5  * Version: MPL 1.1
6  *
7  * The contents of this file are subject to the Mozilla Public License Version
8  * 1.1 (the "License"); you may not use this file except in compliance with
9  * the License. You may obtain a copy of the License at
10  * http://www.mozilla.org/MPL/
11  *
12  * Software distributed under the License is distributed on an "AS IS" basis,
13  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14  * for the specific language governing rights and limitations under the
15  * License.
16  *
17  * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
18  *
19  * The Initial Developer of the Original Code is
20  * Anthony Minessale II <anthm@freeswitch.org>
21  * Portions created by the Initial Developer are Copyright (C)
22  * the Initial Developer. All Rights Reserved.
23  *
24  * Contributor(s):
25  *
26  * Anthony Minessale II <anthm@freeswitch.org>
27  *
28  * switch_jitterbuffer.c -- Audio/Video Jitter Buffer
29  *
30  */
31 #include <switch.h>
32 #include <switch_jitterbuffer.h>
34 
35 #define NACK_TIME 80000
36 #define RENACK_TIME 100000
37 #define PERIOD_LEN 250
38 #define MAX_FRAME_PADDING 2
39 #define MAX_MISSING_SEQ 20
40 #define jb_debug(_jb, _level, _format, ...) if (_jb->debug_level >= _level) switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(_jb->session), SWITCH_LOG_ALERT, "JB:%p:%s lv:%d ln:%.4d sz:%.3u/%.3u/%.3u/%.3u c:%.3u %.3u/%.3u/%.3u/%.3u %.2f%% ->" _format, (void *) _jb, (jb->type == SJB_AUDIO ? "aud" : "vid"), _level, __LINE__, _jb->min_frame_len, _jb->max_frame_len, _jb->frame_len, _jb->complete_frames, _jb->period_count, _jb->consec_good_count, _jb->period_good_count, _jb->consec_miss_count, _jb->period_miss_count, _jb->period_miss_pct, __VA_ARGS__)
41 
42 //const char *TOKEN_1 = "ONE";
43 //const char *TOKEN_2 = "TWO";
44 
45 struct switch_jb_s;
46 
47 typedef struct switch_jb_node_s {
50  uint32_t len;
51  uint8_t visible;
52  uint8_t bad_hits;
56 
57 struct switch_jb_s {
59  uint32_t last_target_seq;
60  uint32_t highest_read_ts;
61  uint32_t highest_read_seq;
62  uint32_t highest_wrote_ts;
64  uint16_t target_seq;
65  uint32_t target_ts;
66  uint32_t last_target_ts;
67  uint16_t psuedo_seq;
68  uint16_t last_psuedo_seq;
69  uint32_t visible_nodes;
70  uint32_t complete_frames;
71  uint32_t frame_len;
72  uint32_t min_frame_len;
73  uint32_t max_frame_len;
77  uint32_t period_miss_inc;
81  uint32_t period_count;
82  uint32_t dropped;
85  uint32_t bitrate_control;
87  uint8_t write_init;
88  uint8_t read_init;
89  uint8_t debug_level;
90  uint16_t next_seq;
98  int free_pool;
99  int drop_flag;
104 };
105 
106 
107 static int node_cmp(const void *l, const void *r)
108 {
111 
112  if (!a->visible) return 0;
113  if (!b->visible) return 1;
114 
115  return ntohs(a->packet.header.seq) - ntohs(b->packet.header.seq);
116 }
117 
118 //http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.c
119 switch_jb_node_t *sort_nodes(switch_jb_node_t *list, int (*cmp)(const void *, const void *)) {
120  switch_jb_node_t *p, *q, *e, *tail;
121  int insize, nmerges, psize, qsize, i;
122 
123  if (!list) {
124  return NULL;
125  }
126 
127  insize = 1;
128 
129  while (1) {
130  p = list;
131  list = NULL;
132  tail = NULL;
133 
134  nmerges = 0; /* count number of merges we do in this pass */
135 
136  while (p) {
137  nmerges++; /* there exists a merge to be done */
138  /* step `insize' places along from p */
139  q = p;
140  psize = 0;
141  for (i = 0; i < insize; i++) {
142  psize++;
143  q = q->next;
144  if (!q) break;
145  }
146 
147  /* if q hasn't fallen off end, we have two lists to merge */
148  qsize = insize;
149 
150  /* now we have two lists; merge them */
151  while (psize > 0 || (qsize > 0 && q)) {
152 
153  /* decide whether next switch_jb_node_t of merge comes from p or q */
154  if (psize == 0) {
155  /* p is empty; e must come from q. */
156  e = q; q = q->next; qsize--;
157  } else if (qsize == 0 || !q) {
158  /* q is empty; e must come from p. */
159  e = p; p = p->next; psize--;
160  } else if (cmp(p,q) <= 0) {
161  /* First switch_jb_node_t of p is lower (or same);
162  * e must come from p. */
163  e = p; p = p->next; psize--;
164  } else {
165  /* First switch_jb_node_t of q is lower; e must come from q. */
166  e = q; q = q->next; qsize--;
167  }
168 
169  /* add the next switch_jb_node_t to the merged list */
170  if (tail) {
171  tail->next = e;
172  } else {
173  list = e;
174  }
175 
176  /* Maintain reverse pointers in a doubly linked list. */
177  e->prev = tail;
178 
179  tail = e;
180  }
181 
182  /* now p has stepped `insize' places along, and q has too */
183  p = q;
184  }
185 
186  tail->next = NULL;
187 
188  /* If we have done only one merge, we're finished. */
189  if (nmerges <= 1) /* allow for nmerges==0, the empty list case */
190  return list;
191 
192  /* Otherwise repeat, merging lists twice the size */
193  insize *= 2;
194  }
195 }
196 
197 
199 {
200  switch_jb_node_t *np;
201 
203 
204  for (np = jb->node_list; np; np = np->next) {
205  if (!np->visible) {
206  break;
207  }
208  }
209 
210  if (!np) {
211 
212  np = switch_core_alloc(jb->pool, sizeof(*np));
213 
214  np->next = jb->node_list;
215  if (np->next) {
216  np->next->prev = np;
217  }
218  jb->node_list = np;
219 
220  }
221 
222  switch_assert(np);
223  np->bad_hits = 0;
224  np->visible = 1;
225  jb->visible_nodes++;
226  np->parent = jb;
227 
229 
230  return np;
231 }
232 
233 static inline void push_to_top(switch_jb_t *jb, switch_jb_node_t *node)
234 {
235  if (node == jb->node_list) {
236  jb->node_list = node->next;
237  } else if (node->prev) {
238  node->prev->next = node->next;
239  }
240 
241  if (node->next) {
242  node->next->prev = node->prev;
243  }
244 
245  node->next = jb->node_list;
246  node->prev = NULL;
247 
248  if (node->next) {
249  node->next->prev = node;
250  }
251 
252  jb->node_list = node;
253 
254  switch_assert(node->next != node);
255  switch_assert(node->prev != node);
256 }
257 
258 static inline void hide_node(switch_jb_node_t *node, switch_bool_t pop)
259 {
260  switch_jb_t *jb = node->parent;
261 
263 
264  if (node->visible) {
265  node->visible = 0;
266  node->bad_hits = 0;
267  jb->visible_nodes--;
268 
269  if (pop) {
270  push_to_top(jb, node);
271  }
272  }
273 
274  if (jb->node_hash_ts) {
276  }
277 
279 
281 }
282 
283 static inline void sort_free_nodes(switch_jb_t *jb)
284 {
288 }
289 
290 static inline void hide_nodes(switch_jb_t *jb)
291 {
292  switch_jb_node_t *np;
293 
295  for (np = jb->node_list; np; np = np->next) {
296  hide_node(np, SWITCH_FALSE);
297  }
299 }
300 
301 static inline void drop_ts(switch_jb_t *jb, uint32_t ts)
302 {
303  switch_jb_node_t *np;
304  int x = 0;
305 
307  for (np = jb->node_list; np; np = np->next) {
308  if (!np->visible) continue;
309 
310  if (ts == np->packet.header.ts) {
311  hide_node(np, SWITCH_FALSE);
312  x++;
313  }
314  }
315 
316  if (x) {
317  sort_free_nodes(jb);
318  }
319 
321 
322  if (x) jb->complete_frames--;
323 }
324 
325 static inline switch_jb_node_t *jb_find_lowest_seq(switch_jb_t *jb, uint32_t ts)
326 {
327  switch_jb_node_t *np, *lowest = NULL;
328 
330  for (np = jb->node_list; np; np = np->next) {
331  if (!np->visible) continue;
332 
333  if (ts && ts != np->packet.header.ts) continue;
334 
335  if (!lowest || ntohs(lowest->packet.header.seq) > ntohs(np->packet.header.seq)) {
336  lowest = np;
337  }
338  }
340 
341  return lowest;
342 }
343 
345 {
346  switch_jb_node_t *np, *lowest = NULL;
347 
349  for (np = jb->node_list; np; np = np->next) {
350  if (!np->visible) continue;
351 
352  if (!lowest || ntohl(lowest->packet.header.ts) > ntohl(np->packet.header.ts)) {
353  lowest = np;
354  }
355  }
357 
358  return lowest ? lowest : NULL;
359 }
360 
361 static inline uint32_t jb_find_lowest_ts(switch_jb_t *jb)
362 {
364 
365  return lowest ? lowest->packet.header.ts : 0;
366 }
367 
368 static inline void thin_frames(switch_jb_t *jb, int freq, int max)
369 {
370  switch_jb_node_t *node;
371  int i = -1;
372  int dropped = 0;
373 
375  node = jb->node_list;
376 
377  for (node = jb->node_list; node && jb->complete_frames > jb->max_frame_len && dropped < max; node = node->next) {
378 
379  if (node->visible) {
380  i++;
381  } else {
382  continue;
383  }
384 
385  if ((i % freq) == 0) {
386  drop_ts(jb, node->packet.header.ts);
387  node = jb->node_list;
388  dropped++;
389  }
390  }
391 
392  sort_free_nodes(jb);
394 }
395 
396 
397 
398 #if 0
399 static inline switch_jb_node_t *jb_find_highest_node(switch_jb_t *jb)
400 {
401  switch_jb_node_t *np, *highest = NULL;
402 
404  for (np = jb->node_list; np; np = np->next) {
405  if (!np->visible) continue;
406 
407  if (!highest || ntohl(highest->packet.header.ts) < ntohl(np->packet.header.ts)) {
408  highest = np;
409  }
410  }
412 
413  return highest ? highest : NULL;
414 }
415 
416 static inline uint32_t jb_find_highest_ts(switch_jb_t *jb)
417 {
418  switch_jb_node_t *highest = jb_find_highest_node(jb);
419 
420  return highest ? highest->packet.header.ts : 0;
421 }
422 
423 static inline switch_jb_node_t *jb_find_penultimate_node(switch_jb_t *jb)
424 {
425  switch_jb_node_t *np, *highest = NULL, *second_highest = NULL;
426 
428  for (np = jb->node_list; np; np = np->next) {
429  if (!np->visible) continue;
430 
431  if (!highest || ntohl(highest->packet.header.ts) < ntohl(np->packet.header.ts)) {
432  if (highest) second_highest = highest;
433  highest = np;
434  }
435  }
437 
438  return second_highest ? second_highest : highest;
439 }
440 #endif
441 
442 static inline void jb_hit(switch_jb_t *jb)
443 {
444  jb->period_good_count++;
445  jb->consec_good_count++;
446  jb->consec_miss_count = 0;
447 }
448 
449 static void jb_frame_inc_line(switch_jb_t *jb, int i, int line)
450 {
451  uint32_t old_frame_len = jb->frame_len;
452 
453  if (i == 0) {
454  jb->frame_len = jb->min_frame_len;
455  goto end;
456  }
457 
458  if (i > 0) {
459  if ((jb->frame_len + i) < jb->max_frame_len) {
460  jb->frame_len += i;
461  } else {
462  jb->frame_len = jb->max_frame_len;
463  }
464 
465  goto end;
466  }
467 
468  if (i < 0) {
469  if ((jb->frame_len + i) > jb->min_frame_len) {
470  jb->frame_len += i;
471  } else {
472  jb->frame_len = jb->min_frame_len;
473  }
474  }
475 
476  end:
477 
478  if (jb->frame_len > jb->highest_frame_len) {
479  jb->highest_frame_len = jb->frame_len;
480  }
481 
482  if (old_frame_len != jb->frame_len) {
483  jb_debug(jb, 2, "%d Change framelen from %u to %u\n", line, old_frame_len, jb->frame_len);
484  if (jb->session) {
486  }
487  }
488 
489 }
490 
491 #define jb_frame_inc(_jb, _i) jb_frame_inc_line(_jb, _i, __LINE__)
492 
493 
494 static inline void jb_miss(switch_jb_t *jb)
495 {
496  jb->period_miss_count++;
497  jb->consec_miss_count++;
498  jb->consec_good_count = 0;
499 }
500 
501 #if 0
502 static inline int verify_oldest_frame(switch_jb_t *jb)
503 {
504  switch_jb_node_t *lowest = NULL, *np = NULL;
505  int r = 0;
506 
507  lowest = jb_find_lowest_node(jb);
508 
509  if (!lowest || !(lowest = jb_find_lowest_seq(jb, lowest->packet.header.ts))) {
510  goto end;
511  }
512 
514 
516 
517  for (np = lowest->next; np; np = np->next) {
518 
519  if (!np->visible) continue;
520 
521  if (ntohs(np->packet.header.seq) != ntohs(np->prev->packet.header.seq) + 1) {
522  uint32_t val = (uint32_t)htons(ntohs(np->prev->packet.header.seq) + 1);
523 
525  switch_core_inthash_insert(jb->missing_seq_hash, val, (void *)(intptr_t)1);
526  }
527  break;
528  }
529 
530  if (np->packet.header.ts != lowest->packet.header.ts || !np->next) {
531  r = 1;
532  }
533  }
534 
536 
537  end:
538 
539  return r;
540 }
541 #endif
542 
543 static inline void drop_oldest_frame(switch_jb_t *jb)
544 {
545  uint32_t ts = jb_find_lowest_ts(jb);
546 
547  drop_ts(jb, ts);
548  jb_debug(jb, 1, "Dropping oldest frame ts:%u\n", ntohl(ts));
549 }
550 
551 #if 0
552 static inline void drop_newest_frame(switch_jb_t *jb)
553 {
554  uint32_t ts = jb_find_highest_ts(jb);
555 
556  drop_ts(jb, ts);
557  jb_debug(jb, 1, "Dropping highest frame ts:%u\n", ntohl(ts));
558 }
559 
560 static inline void drop_second_newest_frame(switch_jb_t *jb)
561 {
562  switch_jb_node_t *second_newest = jb_find_penultimate_node(jb);
563 
564  if (second_newest) {
565  drop_ts(jb, second_newest->packet.header.ts);
566  jb_debug(jb, 1, "Dropping second highest frame ts:%u\n", ntohl(second_newest->packet.header.ts));
567  }
568 }
569 #endif
570 
572 {
573  switch_jb_node_t *node = new_node(jb);
574 
575  node->packet = *packet;
576  node->len = len;
577  memcpy(node->packet.body, packet->body, len);
578 
580 
581  if (jb->node_hash_ts) {
583  }
584 
585  jb_debug(jb, (packet->header.m ? 1 : 2), "PUT packet last_ts:%u ts:%u seq:%u%s\n",
586  ntohl(jb->highest_wrote_ts), ntohl(node->packet.header.ts), ntohs(node->packet.header.seq), packet->header.m ? " <MARK>" : "");
587 
588  if (jb->write_init && jb->type == SJB_VIDEO) {
589  int seq_diff = 0, ts_diff = 0;
590 
591  if (ntohs(jb->highest_wrote_seq) > (USHRT_MAX - 100) && ntohs(packet->header.seq) < 100) {
592  seq_diff = (USHRT_MAX - ntohs(jb->highest_wrote_seq)) + ntohs(packet->header.seq);
593  } else {
594  seq_diff = abs(((int)ntohs(packet->header.seq) - ntohs(jb->highest_wrote_seq)));
595  }
596 
597  if (ntohl(jb->highest_wrote_ts) > (UINT_MAX - 1000) && ntohl(node->packet.header.ts) < 1000) {
598  ts_diff = (UINT_MAX - ntohl(node->packet.header.ts)) + ntohl(node->packet.header.ts);
599  } else {
600  ts_diff = abs((int)((int64_t)ntohl(node->packet.header.ts) - (int64_t)ntohl(jb->highest_wrote_ts)));
601  }
602 
603  if (((seq_diff >= jb->max_frame_len) || (ts_diff > (900000 * 5)))) {
604  jb_debug(jb, 2, "CHANGE DETECTED, PUNT %u\n", abs(((int)ntohs(packet->header.seq) - ntohs(jb->highest_wrote_seq))));
605  switch_jb_reset(jb);
606  }
607  }
608 
609  if (!jb->write_init || ntohs(packet->header.seq) > ntohs(jb->highest_wrote_seq) ||
610  (ntohs(jb->highest_wrote_seq) > USHRT_MAX - 100 && ntohs(packet->header.seq) < 100) ) {
611  jb->highest_wrote_seq = packet->header.seq;
612  }
613 
614  if (jb->type == SJB_VIDEO) {
615  if (jb->write_init && ((htons(packet->header.seq) >= htons(jb->highest_wrote_seq) && (ntohl(node->packet.header.ts) > ntohl(jb->highest_wrote_ts))) ||
616  (ntohl(jb->highest_wrote_ts) > (UINT_MAX - 1000) && ntohl(node->packet.header.ts) < 1000))) {
617  jb->complete_frames++;
618  jb_debug(jb, 2, "WRITE frame ts: %u complete=%u/%u n:%u\n", ntohl(node->packet.header.ts), jb->complete_frames , jb->frame_len, jb->visible_nodes);
619  jb->highest_wrote_ts = packet->header.ts;
620  //verify_oldest_frame(jb);
621  } else if (!jb->write_init) {
622  jb->highest_wrote_ts = packet->header.ts;
623  }
624  } else {
625  if (jb->write_init) {
626  jb_debug(jb, 2, "WRITE frame ts: %u complete=%u/%u n:%u\n", ntohl(node->packet.header.ts), jb->complete_frames , jb->frame_len, jb->visible_nodes);
627  jb->complete_frames++;
628  } else {
629  jb->highest_wrote_ts = packet->header.ts;
630  }
631  }
632 
633  if (!jb->write_init) jb->write_init = 1;
634 }
635 
636 static inline void increment_ts(switch_jb_t *jb)
637 {
638  if (!jb->target_ts) return;
639 
640  jb->last_psuedo_seq = jb->psuedo_seq;
641  jb->last_target_ts = jb->target_ts;
642  jb->target_ts = htonl((ntohl(jb->target_ts) + jb->samples_per_frame));
643  jb->psuedo_seq++;
644 }
645 
646 static inline void set_read_ts(switch_jb_t *jb, uint32_t ts)
647 {
648  if (!ts) return;
649 
650  jb->last_psuedo_seq = jb->psuedo_seq;
651  jb->last_target_ts = ts;
652  jb->target_ts = htonl((ntohl(jb->last_target_ts) + jb->samples_per_frame));
653  jb->psuedo_seq++;
654 }
655 
656 
657 static inline void increment_seq(switch_jb_t *jb)
658 {
659  jb->last_target_seq = jb->target_seq;
660  jb->target_seq = htons((ntohs(jb->target_seq) + 1));
661 }
662 
663 static inline void set_read_seq(switch_jb_t *jb, uint16_t seq)
664 {
665  jb->last_target_seq = seq;
666  jb->target_seq = htons((ntohs(jb->last_target_seq) + 1));
667 }
668 
670 {
671  switch_jb_node_t *node = NULL;
672 
673  top:
674 
675  if (jb->type == SJB_VIDEO) {
676  if (jb->dropped) {
677  jb->dropped = 0;
678  jb_debug(jb, 2, "%s", "DROPPED FRAME DETECTED RESYNCING\n");
679  jb->target_seq = 0;
680 
681  if (jb->session) {
683  }
684  }
685  }
686 
687  if (!jb->target_seq) {
688  if ((node = switch_core_inthash_find(jb->node_hash, jb->target_seq))) {
689  jb_debug(jb, 2, "FOUND rollover seq: %u\n", ntohs(jb->target_seq));
690  } else if ((node = jb_find_lowest_seq(jb, 0))) {
691  jb_debug(jb, 2, "No target seq using seq: %u as a starting point\n", ntohs(node->packet.header.seq));
692  } else {
693  jb_debug(jb, 1, "%s", "No nodes available....\n");
694  }
695  jb_hit(jb);
696  } else if ((node = switch_core_inthash_find(jb->node_hash, jb->target_seq))) {
697  jb_debug(jb, 2, "FOUND desired seq: %u\n", ntohs(jb->target_seq));
698  jb_hit(jb);
699  } else {
700  jb_debug(jb, 2, "MISSING desired seq: %u\n", ntohs(jb->target_seq));
701  jb_miss(jb);
702 
703  if (jb->type == SJB_VIDEO) {
704  int x;
705 
706  if (jb->period_miss_count > 1 && !jb->period_miss_inc) {
707  jb->period_miss_inc++;
708  jb_frame_inc(jb, 1);
709  }
710 
711  //if (jb->session) {
712  // switch_core_session_request_video_refresh(jb->session);
713  //}
714 
715  for (x = 0; x < 10; x++) {
716  increment_seq(jb);
717  if ((node = switch_core_inthash_find(jb->node_hash, jb->target_seq))) {
718  jb_debug(jb, 2, "FOUND incremental seq: %u\n", ntohs(jb->target_seq));
719 
720  if (node->packet.header.m || node->packet.header.ts == jb->highest_read_ts) {
721  jb_debug(jb, 2, "%s", "SAME FRAME DROPPING\n");
722  jb->dropped++;
723  drop_ts(jb, node->packet.header.ts);
724  node = NULL;
725  goto top;
726  }
727  break;
728  } else {
729  jb_debug(jb, 2, "MISSING incremental seq: %u\n", ntohs(jb->target_seq));
730  }
731  }
732  } else {
733  increment_seq(jb);
734  }
735  }
736 
737  *nodep = node;
738 
739  if (node) {
740  set_read_seq(jb, node->packet.header.seq);
741  return SWITCH_STATUS_SUCCESS;
742  }
743 
744  return SWITCH_STATUS_NOTFOUND;
745 
746 }
747 
748 
750 {
751  switch_jb_node_t *node = NULL;
752 
753  if (!jb->target_ts) {
754  if ((node = jb_find_lowest_node(jb))) {
755  jb_debug(jb, 2, "No target ts using ts: %u as a starting point\n", ntohl(node->packet.header.ts));
756  } else {
757  jb_debug(jb, 1, "%s", "No nodes available....\n");
758  }
759  jb_hit(jb);
760  } else if ((node = switch_core_inthash_find(jb->node_hash_ts, jb->target_ts))) {
761  jb_debug(jb, 2, "FOUND desired ts: %u\n", ntohl(jb->target_ts));
762  jb_hit(jb);
763  } else {
764  jb_debug(jb, 2, "MISSING desired ts: %u\n", ntohl(jb->target_ts));
765  jb_miss(jb);
766  increment_ts(jb);
767  }
768 
769  *nodep = node;
770 
771  if (node) {
772  set_read_ts(jb, node->packet.header.ts);
773  node->packet.header.seq = htons(jb->psuedo_seq);
774  return SWITCH_STATUS_SUCCESS;
775  }
776 
777  return SWITCH_STATUS_NOTFOUND;
778 
779 }
780 
782 {
783  if (jb->samples_per_frame) {
784  return jb_next_packet_by_ts(jb, nodep);
785  } else {
786  return jb_next_packet_by_seq(jb, nodep);
787  }
788 }
789 
790 static inline void free_nodes(switch_jb_t *jb)
791 {
793  jb->node_list = NULL;
795 }
796 
797 SWITCH_DECLARE(void) switch_jb_ts_mode(switch_jb_t *jb, uint32_t samples_per_frame, uint32_t samples_per_second)
798 {
799  jb->samples_per_frame = samples_per_frame;
800  jb->samples_per_second = samples_per_second;
801  switch_core_inthash_init(&jb->node_hash_ts);
802 }
803 
805 {
806  const char *var;
807 
808  jb->session = session;
809  jb->channel = switch_core_session_get_channel(session);
810 
811  if (jb->type == SJB_VIDEO && (var = switch_channel_get_variable_dup(jb->channel, "jb_video_low_bitrate", SWITCH_FALSE, -1))) {
812  int tmp = atoi(var);
813 
814  if (tmp > 128 && tmp < 10240) {
815  jb->video_low_bitrate = (uint32_t)tmp;
816  }
817  }
818 
819 }
820 
822 {
823  switch_set_flag(jb, flag);
824 }
825 
827 {
828  switch_clear_flag(jb, flag);
829 }
830 
832 {
833  return (jb->complete_frames >= jb->frame_len);
834 }
835 
837 {
838  return jb->complete_frames;
839 }
840 
842 {
843  jb->debug_level = level;
844 }
845 
847 {
848 
849  if (jb->type == SJB_VIDEO) {
850  switch_mutex_lock(jb->mutex);
851  switch_core_inthash_destroy(&jb->missing_seq_hash);
852  switch_core_inthash_init(&jb->missing_seq_hash);
853  switch_mutex_unlock(jb->mutex);
854 
855  if (jb->session) {
857  }
858  }
859 
860  jb_debug(jb, 2, "%s", "RESET BUFFER\n");
861 
862  jb->drop_flag = 0;
863  jb->last_target_seq = 0;
864  jb->target_seq = 0;
865  jb->write_init = 0;
866  jb->highest_wrote_seq = 0;
867  jb->highest_wrote_ts = 0;
868  jb->next_seq = 0;
869  jb->highest_read_ts = 0;
870  jb->highest_read_seq = 0;
871  jb->complete_frames = 0;
872  jb->read_init = 0;
873  jb->next_seq = 0;
874  jb->complete_frames = 0;
875  jb->period_miss_count = 0;
876  jb->consec_miss_count = 0;
877  jb->period_miss_pct = 0;
878  jb->period_good_count = 0;
879  jb->consec_good_count = 0;
880  jb->period_count = 0;
881  jb->period_miss_inc = 0;
882  jb->target_ts = 0;
883  jb->last_target_ts = 0;
884 
885  switch_mutex_lock(jb->mutex);
886  hide_nodes(jb);
887  switch_mutex_unlock(jb->mutex);
888 }
889 
890 SWITCH_DECLARE(switch_status_t) switch_jb_peek_frame(switch_jb_t *jb, uint32_t ts, uint16_t seq, int peek, switch_frame_t *frame)
891 {
892  switch_jb_node_t *node = NULL;
893  if (seq) {
894  uint16_t want_seq = seq + peek;
895  node = switch_core_inthash_find(jb->node_hash, htons(want_seq));
896  } else if (ts && jb->samples_per_frame) {
897  uint32_t want_ts = ts + (peek * jb->samples_per_frame);
898  node = switch_core_inthash_find(jb->node_hash_ts, htonl(want_ts));
899  }
900 
901  if (node) {
902  frame->seq = ntohs(node->packet.header.seq);
903  frame->timestamp = ntohl(node->packet.header.ts);
904  frame->m = node->packet.header.m;
905  frame->datalen = node->len;
906 
907  if (frame->data && frame->buflen > node->len) {
908  memcpy(frame->data, node->packet.body, node->len);
909  }
910  return SWITCH_STATUS_SUCCESS;
911  }
912 
913  return SWITCH_STATUS_FALSE;
914 }
915 
916 SWITCH_DECLARE(switch_status_t) switch_jb_get_frames(switch_jb_t *jb, uint32_t *min_frame_len, uint32_t *max_frame_len, uint32_t *cur_frame_len, uint32_t *highest_frame_len)
917 {
918 
919  switch_mutex_lock(jb->mutex);
920 
921  if (min_frame_len) {
922  *min_frame_len = jb->min_frame_len;
923  }
924 
925  if (max_frame_len) {
926  *max_frame_len = jb->max_frame_len;
927  }
928 
929  if (cur_frame_len) {
930  *cur_frame_len = jb->frame_len;
931  }
932 
933  switch_mutex_unlock(jb->mutex);
934 
935  return SWITCH_STATUS_SUCCESS;
936 }
937 
938 SWITCH_DECLARE(switch_status_t) switch_jb_set_frames(switch_jb_t *jb, uint32_t min_frame_len, uint32_t max_frame_len)
939 {
940  int lowest = 0;
941 
942  switch_mutex_lock(jb->mutex);
943 
944  if (jb->frame_len == jb->min_frame_len) lowest = 1;
945 
946  jb->min_frame_len = min_frame_len;
947  jb->max_frame_len = max_frame_len;
948 
949  if (jb->frame_len > jb->max_frame_len) {
950  jb->frame_len = jb->max_frame_len;
951  }
952 
953  if (jb->frame_len < jb->min_frame_len) {
954  jb->frame_len = jb->min_frame_len;
955  }
956 
957  if (jb->frame_len > jb->highest_frame_len) {
958  jb->highest_frame_len = jb->frame_len;
959  }
960 
961  if (lowest) {
962  jb->frame_len = jb->min_frame_len;
963  }
964 
965  switch_mutex_unlock(jb->mutex);
966 
967  return SWITCH_STATUS_SUCCESS;
968 }
969 
971  uint32_t min_frame_len, uint32_t max_frame_len, switch_memory_pool_t *pool)
972 {
973  switch_jb_t *jb;
974  int free_pool = 0;
975 
976  if (!pool) {
978  free_pool = 1;
979  }
980 
981  jb = switch_core_alloc(pool, sizeof(*jb));
982  jb->free_pool = free_pool;
983  jb->min_frame_len = jb->frame_len = min_frame_len;
984  jb->max_frame_len = max_frame_len;
985  jb->pool = pool;
986  jb->type = type;
987  jb->highest_frame_len = jb->frame_len;
988 
989  if (jb->type == SJB_VIDEO) {
991  }
995 
996  *jbp = jb;
997 
998  return SWITCH_STATUS_SUCCESS;
999 }
1000 
1002 {
1003  switch_jb_t *jb = *jbp;
1004  *jbp = NULL;
1005 
1006  if (jb->type == SJB_VIDEO) {
1008  }
1010 
1011  if (jb->node_hash_ts) {
1013  }
1014 
1015  free_nodes(jb);
1016 
1017  if (jb->free_pool) {
1019  }
1020 
1021  return SWITCH_STATUS_SUCCESS;
1022 }
1023 
1025 {
1026  switch_hash_index_t *hi = NULL;
1027  uint32_t nack = 0;
1028  uint16_t blp = 0;
1029  uint16_t least = 0;
1030  int i = 0;
1031  void *val;
1032  const void *var;
1033 
1034  if (jb->type != SJB_VIDEO) {
1035  return 0;
1036  }
1037 
1038  switch_mutex_lock(jb->mutex);
1039 
1040  top:
1041 
1042  for (hi = switch_core_hash_first(jb->missing_seq_hash); hi; hi = switch_core_hash_next(&hi)) {
1043  uint16_t seq;
1044  //const char *token;
1045  switch_time_t then = 0;
1046 
1047  switch_core_hash_this(hi, &var, NULL, &val);
1048  //token = (const char *) val;
1049 
1050  //if (token == TOKEN_2) {
1051  //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "SKIP %u %s\n", ntohs(*((uint16_t *) var)), token);
1052  //printf("WTf\n");
1053  // continue;
1054  //}
1055 
1056  seq = ntohs(*((uint16_t *) var));
1057  then = (intptr_t) val;
1058 
1059  if (then != 1 && switch_time_now() - then < RENACK_TIME) {
1060  //jb_debug(jb, 3, "NACKABLE seq %u too soon to repeat\n", seq);
1061  continue;
1062  }
1063 
1064  //if (then != 1) {
1065  // jb_debug(jb, 3, "NACKABLE seq %u not too soon to repeat %lu\n", seq, switch_time_now() - then);
1066  //}
1067 
1068  if (seq < ntohs(jb->target_seq) - jb->frame_len) {
1069  jb_debug(jb, 3, "NACKABLE seq %u expired\n", seq);
1070  switch_core_inthash_delete(jb->missing_seq_hash, (uint32_t)htons(seq));
1071  goto top;
1072  }
1073 
1074  if (!least || seq < least) {
1075  least = seq;
1076  }
1077  }
1078 
1079  if (least && switch_core_inthash_delete(jb->missing_seq_hash, (uint32_t)htons(least))) {
1080  jb_debug(jb, 3, "Found NACKABLE seq %u\n", least);
1081  nack = (uint32_t) htons(least);
1082  switch_core_inthash_insert(jb->missing_seq_hash, nack, (void *) (intptr_t)switch_time_now());
1083 
1084  for(i = 0; i < 16; i++) {
1085  if (switch_core_inthash_delete(jb->missing_seq_hash, (uint32_t)htons(least + i + 1))) {
1086  switch_core_inthash_insert(jb->missing_seq_hash, (uint32_t)htons(least + i + 1), (void *)(intptr_t)switch_time_now());
1087  jb_debug(jb, 3, "Found addtl NACKABLE seq %u\n", least + i + 1);
1088  blp |= (1 << i);
1089  }
1090  }
1091 
1092  blp = htons(blp);
1093  nack |= (uint32_t) blp << 16;
1094 
1095  //jb_frame_inc(jb, 1);
1096  }
1097 
1098  switch_mutex_unlock(jb->mutex);
1099 
1100 
1101  return nack;
1102 }
1103 
1105 {
1106  uint32_t i;
1107  uint16_t want = ntohs(jb->next_seq), got = ntohs(packet->header.seq);
1108 
1109  if (len >= sizeof(switch_rtp_packet_t)) {
1110  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "trying to put %" SWITCH_SIZE_T_FMT " bytes exceeding buffer, truncate to %" SWITCH_SIZE_T_FMT "\n", len, sizeof(switch_rtp_packet_t));
1111  len = sizeof(switch_rtp_packet_t);
1112  }
1113 
1114  switch_mutex_lock(jb->mutex);
1115 
1116  if (!want) want = got;
1117 
1118  if (switch_test_flag(jb, SJB_QUEUE_ONLY) || jb->type == SJB_AUDIO) {
1119  jb->next_seq = htons(got + 1);
1120  } else {
1121 
1122  if (switch_core_inthash_delete(jb->missing_seq_hash, (uint32_t)htons(got))) {
1123  if (got < ntohs(jb->target_seq)) {
1124  jb_debug(jb, 2, "got nacked seq %u too late\n", got);
1125  jb_frame_inc(jb, 1);
1126  } else {
1127  jb_debug(jb, 2, "got nacked %u saved the day!\n", got);
1128  }
1129  }
1130 
1131  if (got > want) {
1132  if (got - want > jb->max_frame_len && got - want > 17) {
1133  jb_debug(jb, 2, "Missing %u frames, Resetting\n", got - want);
1134  switch_jb_reset(jb);
1135  if (jb->session) {
1137  }
1138  } else {
1139 
1140  if (jb->frame_len < got - want) {
1141  jb_frame_inc(jb, 1);
1142  }
1143 
1144  jb_debug(jb, 2, "GOT %u WANTED %u; MARK SEQS MISSING %u - %u\n", got, want, want, got - 1);
1145 
1146  for (i = want; i < got; i++) {
1147  jb_debug(jb, 2, "MARK MISSING %u ts:%u\n", i, ntohl(packet->header.ts));
1148  switch_core_inthash_insert(jb->missing_seq_hash, (uint32_t)htons(i), (void *)(intptr_t)1);
1149  }
1150  }
1151  }
1152 
1153  if (got >= want || (want - got) > 1000) {
1154  jb->next_seq = htons(got + 1);
1155  }
1156  }
1157 
1158  add_node(jb, packet, len);
1159 
1160  if (switch_test_flag(jb, SJB_QUEUE_ONLY) && jb->complete_frames > jb->max_frame_len) {
1161  drop_oldest_frame(jb);
1162  }
1163 
1164  switch_mutex_unlock(jb->mutex);
1165 
1166  return SWITCH_STATUS_SUCCESS;
1167 }
1168 
1170 {
1171  switch_jb_node_t *node;
1173 
1174  switch_mutex_lock(jb->mutex);
1175  if ((node = switch_core_inthash_find(jb->node_hash, seq))) {
1176  jb_debug(jb, 2, "Found buffered seq: %u\n", ntohs(seq));
1177  *packet = node->packet;
1178  *len = node->len;
1179  memcpy(packet->body, node->packet.body, node->len);
1180  status = SWITCH_STATUS_SUCCESS;
1181  } else {
1182  jb_debug(jb, 2, "Missing buffered seq: %u\n", ntohs(seq));
1183  }
1184  switch_mutex_unlock(jb->mutex);
1185 
1186  return status;
1187 }
1188 
1190 {
1191  return jb->last_len;
1192 }
1193 
1194 
1196 {
1197  switch_jb_node_t *node = NULL;
1198  switch_status_t status;
1199  int plc = 0;
1200 
1201  switch_mutex_lock(jb->mutex);
1202 
1203  if (jb->complete_frames == 0) {
1205  }
1206 
1207  if (jb->complete_frames < jb->frame_len) {
1208  jb_debug(jb, 2, "BUFFERING %u/%u\n", jb->complete_frames , jb->frame_len);
1210  }
1211 
1212  jb_debug(jb, 2, "GET PACKET %u/%u n:%d\n", jb->complete_frames , jb->frame_len, jb->visible_nodes);
1213 
1214  if (++jb->period_count >= PERIOD_LEN) {
1215 
1216  if (jb->consec_good_count >= (PERIOD_LEN - 5)) {
1217  jb_frame_inc(jb, -1);
1218  }
1219 
1220  jb->period_count = 1;
1221  jb->period_miss_inc = 0;
1222  jb->period_miss_count = 0;
1223  jb->period_good_count = 0;
1224  jb->consec_miss_count = 0;
1225  jb->consec_good_count = 0;
1226 
1227  if (jb->type == SJB_VIDEO && jb->channel && jb->video_low_bitrate) {
1228  //switch_time_t now = switch_time_now();
1229  //int ok = (now - jb->last_bitrate_change) > 10000;
1230 
1231  if (switch_channel_test_flag(jb->channel, CF_VIDEO_BITRATE_UNMANAGABLE) && jb->frame_len == jb->min_frame_len) {
1232  jb_debug(jb, 2, "%s", "Allow BITRATE changes\n");
1234  jb->bitrate_control = 0;
1235  if (jb->session) {
1237  }
1238  } else if (!switch_channel_test_flag(jb->channel, CF_VIDEO_BITRATE_UNMANAGABLE) && jb->frame_len > jb->min_frame_len * 2) {
1239  switch_core_session_message_t msg = { 0 };
1240 
1241  jb->bitrate_control = jb->video_low_bitrate;
1242 
1244  msg.numeric_arg = jb->bitrate_control * 1024;
1245  msg.from = __FILE__;
1246 
1247  jb_debug(jb, 2, "Force BITRATE to %d\n", jb->bitrate_control);
1248  switch_core_session_receive_message(jb->session, &msg);
1250  if (jb->session) {
1252  }
1253  }
1254  }
1255 
1256  }
1257 
1258  jb->period_miss_pct = ((double)jb->period_miss_count / jb->period_count) * 100;
1259 
1260  if (jb->period_miss_pct > 60.0f) {
1261  jb_debug(jb, 2, "Miss percent %02f too high, resetting buffer.\n", jb->period_miss_pct);
1262  switch_jb_reset(jb);
1263  }
1264 
1265  if ((status = jb_next_packet(jb, &node)) == SWITCH_STATUS_SUCCESS) {
1266  jb_debug(jb, 2, "Found next frame cur ts: %u seq: %u\n", htonl(node->packet.header.ts), htons(node->packet.header.seq));
1267 
1268  if (!jb->read_init || ntohs(node->packet.header.seq) > ntohs(jb->highest_read_seq) ||
1269  (ntohs(jb->highest_read_seq) > USHRT_MAX - 10 && ntohs(node->packet.header.seq) <= 10) ) {
1270  jb->highest_read_seq = node->packet.header.seq;
1271  }
1272 
1273  if (jb->read_init && htons(node->packet.header.seq) >= htons(jb->highest_read_seq) && (ntohl(node->packet.header.ts) > ntohl(jb->highest_read_ts))) {
1274  jb->complete_frames--;
1275  jb_debug(jb, 2, "READ frame ts: %u complete=%u/%u n:%u\n", ntohl(node->packet.header.ts), jb->complete_frames , jb->frame_len, jb->visible_nodes);
1276  jb->highest_read_ts = node->packet.header.ts;
1277  } else if (!jb->read_init) {
1278  jb->highest_read_ts = node->packet.header.ts;
1279  }
1280 
1281  if (!jb->read_init) jb->read_init = 1;
1282  } else {
1283  if (jb->type == SJB_VIDEO) {
1284  switch_jb_reset(jb);
1285 
1286  switch(status) {
1287  case SWITCH_STATUS_RESTART:
1288  jb_debug(jb, 2, "%s", "Error encountered ask for new keyframe\n");
1291  default:
1292  jb_debug(jb, 2, "%s", "No frames found wait for more\n");
1294  }
1295  } else {
1296  switch(status) {
1297  case SWITCH_STATUS_RESTART:
1298  jb_debug(jb, 2, "%s", "Error encountered\n");
1299  switch_jb_reset(jb);
1302  default:
1303  if (jb->consec_miss_count > jb->frame_len) {
1304  switch_jb_reset(jb);
1305  jb_frame_inc(jb, 1);
1306  jb_debug(jb, 2, "%s", "Too many frames not found, RESIZE\n");
1308  } else {
1309  jb_debug(jb, 2, "%s", "Frame not found suggest PLC\n");
1310  plc = 1;
1312  }
1313  }
1314  }
1315  }
1316 
1317  if (node) {
1318  status = SWITCH_STATUS_SUCCESS;
1319 
1320  *packet = node->packet;
1321  *len = node->len;
1322  jb->last_len = *len;
1323  memcpy(packet->body, node->packet.body, node->len);
1324  hide_node(node, SWITCH_TRUE);
1325 
1326  jb_debug(jb, 1, "GET packet ts:%u seq:%u %s\n", ntohl(packet->header.ts), ntohs(packet->header.seq), packet->header.m ? " <MARK>" : "");
1327 
1328  } else {
1329  status = SWITCH_STATUS_MORE_DATA;
1330  }
1331 
1332  end:
1333 
1334  if (plc) {
1335  uint16_t seq;
1336  uint32_t ts = 0;
1337 
1338  if (jb->samples_per_frame) {
1339  seq = htons(jb->last_psuedo_seq);
1340  ts = jb->last_target_ts;
1341  } else {
1342  seq = jb->last_target_seq;
1343  }
1344 
1345  packet->header.seq = seq;
1346  packet->header.ts = ts;
1347  }
1348 
1349  switch_mutex_unlock(jb->mutex);
1350 
1351  if (jb->complete_frames > jb->max_frame_len) {
1352  thin_frames(jb, 8, 25);
1353  }
1354 
1355  return status;
1356 }
1357 
1358 
1359 /* For Emacs:
1360  * Local Variables:
1361  * mode:c
1362  * indent-tabs-mode:t
1363  * tab-width:4
1364  * c-basic-offset:4
1365  * End:
1366  * For VIM:
1367  * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
1368  */
uint32_t highest_wrote_ts
switch_jb_type_t type
#define switch_core_new_memory_pool(p)
Create a new sub memory pool from the core's master pool.
Definition: switch_core.h:631
switch_status_t switch_jb_put_packet(switch_jb_t *jb, switch_rtp_packet_t *packet, switch_size_t len)
#define switch_set_flag(obj, flag)
Set a flag on an arbitrary object.
Definition: switch_utils.h:631
switch_status_t switch_core_inthash_init(switch_inthash_t **hash)
static switch_jb_node_t * jb_find_lowest_seq(switch_jb_t *jb, uint32_t ts)
void switch_jb_debug_level(switch_jb_t *jb, uint8_t level)
switch_core_session_message_types_t message_id
Definition: switch_core.h:181
#define SWITCH_CHANNEL_LOG
uint32_t highest_read_seq
switch_inthash_t * node_hash
switch_channel_t * channel
switch_inthash_t * node_hash_ts
uint32_t min_frame_len
uint32_t last_target_ts
switch_rtp_hdr_t header
Definition: switch_rtp.h:53
switch_inthash_t * missing_seq_hash
static void hide_nodes(switch_jb_t *jb)
uint32_t highest_read_ts
switch_bool_t
Definition: switch_types.h:405
uint32_t complete_frames
struct switch_jb_node_s * next
void switch_jb_ts_mode(switch_jb_t *jb, uint32_t samples_per_frame, uint32_t samples_per_second)
uint32_t switch_jb_pop_nack(switch_jb_t *jb)
#define switch_core_destroy_memory_pool(p)
Returns a subpool back to the main pool.
Definition: switch_core.h:640
switch_memory_pool_t * pool
#define jb_debug(_jb, _level, _format,...)
void * switch_core_inthash_find(switch_inthash_t *hash, uint32_t key)
switch_status_t switch_jb_create(switch_jb_t **jbp, switch_jb_type_t type, uint32_t min_frame_len, uint32_t max_frame_len, switch_memory_pool_t *pool)
switch_jb_type_t
#define jb_frame_inc(_jb, _i)
int switch_jb_frame_count(switch_jb_t *jb)
struct switch_jb_node_s switch_jb_node_t
static uint32_t jb_find_lowest_ts(switch_jb_t *jb)
static void set_read_seq(switch_jb_t *jb, uint16_t seq)
const char * switch_channel_get_variable_dup(switch_channel_t *channel, const char *varname, switch_bool_t dup, int idx)
Retrieve a variable from a given channel.
switch_jb_node_t * sort_nodes(switch_jb_node_t *list, int(*cmp)(const void *, const void *))
int switch_jb_poll(switch_jb_t *jb)
uint32_t switch_channel_test_flag(switch_channel_t *channel, switch_channel_flag_t flag)
Test for presence of given flag on a given channel.
uint32_t max_frame_len
A message object designed to allow unlike technologies to exchange data.
Definition: switch_core.h:177
switch_status_t switch_mutex_unlock(switch_mutex_t *lock)
Definition: switch_apr.c:290
struct switch_jb_s * parent
_Ret_ switch_channel_t * switch_core_session_get_channel(_In_ switch_core_session_t *session)
Retrieve a pointer to the channel object associated with a given session.
switch_status_t switch_core_inthash_destroy(switch_inthash_t **hash)
switch_status_t switch_jb_peek_frame(switch_jb_t *jb, uint32_t ts, uint16_t seq, int peek, switch_frame_t *frame)
#define switch_clear_flag(obj, flag)
Clear a flag on an arbitrary object while locked.
Definition: switch_utils.h:655
#define SWITCH_MUTEX_NESTED
Definition: switch_apr.h:318
static switch_jb_node_t * jb_find_lowest_node(switch_jb_t *jb)
uint32_t samples_per_second
static void jb_hit(switch_jb_t *jb)
switch_status_t switch_jb_get_packet_by_seq(switch_jb_t *jb, uint16_t seq, switch_rtp_packet_t *packet, switch_size_t *len)
static void drop_oldest_frame(switch_jb_t *jb)
int64_t switch_time_t
Definition: switch_apr.h:188
uint32_t bitrate_control
switch_status_t switch_jb_get_packet(switch_jb_t *jb, switch_rtp_packet_t *packet, switch_size_t *len)
static void add_node(switch_jb_t *jb, switch_rtp_packet_t *packet, switch_size_t len)
switch_mutex_t * mutex
static void increment_ts(switch_jb_t *jb)
void * switch_core_inthash_delete(switch_inthash_t *hash, uint32_t key)
static void push_to_top(switch_jb_t *jb, switch_jb_node_t *node)
switch_status_t switch_mutex_lock(switch_mutex_t *lock)
Definition: switch_apr.c:285
#define switch_core_alloc(_pool, _mem)
Allocate memory directly from a memory pool.
Definition: switch_core.h:682
static void drop_ts(switch_jb_t *jb, uint32_t ts)
switch_status_t switch_core_inthash_insert(switch_inthash_t *hash, uint32_t key, const void *data)
switch_status_t switch_mutex_init(switch_mutex_t **lock, unsigned int flags, switch_memory_pool_t *pool)
Definition: switch_apr.c:270
void switch_jb_clear_flag(switch_jb_t *jb, switch_jb_flag_t flag)
static switch_status_t jb_next_packet_by_ts(switch_jb_t *jb, switch_jb_node_t **nodep)
switch_size_t last_len
#define RENACK_TIME
uint32_t visible_nodes
uint32_t consec_miss_count
uint32_t period_count
void switch_core_hash_this(_In_ switch_hash_index_t *hi, _Out_opt_ptrdiff_cap_(klen) const void **key, _Out_opt_ switch_ssize_t *klen, _Out_ void **val)
Gets the key and value of the current hash element.
An abstraction of a data frame.
Definition: switch_frame.h:43
uintptr_t switch_size_t
switch_hash_index_t * switch_core_hash_next(_In_ switch_hash_index_t **hi)
Gets the next element of a hashtable.
static void thin_frames(switch_jb_t *jb, int freq, int max)
#define switch_core_session_receive_message(_session, _message)
Definition: switch_core.h:1217
static void sort_free_nodes(switch_jb_t *jb)
uint32_t video_low_bitrate
static void increment_seq(switch_jb_t *jb)
uint32_t period_miss_inc
uint32_t period_good_count
uint32_t period_miss_count
switch_status_t switch_core_session_request_video_refresh(switch_core_session_t *session)
static int node_cmp(const void *l, const void *r)
uint16_t last_psuedo_seq
struct apr_thread_mutex_t switch_mutex_t
Definition: switch_apr.h:314
switch_status_t switch_jb_destroy(switch_jb_t **jbp)
switch_status_t
Common return values.
#define switch_goto_status(_status, _label)
Definition: switch_utils.h:256
void switch_jb_set_session(switch_jb_t *jb, switch_core_session_t *session)
static void jb_frame_inc_line(switch_jb_t *jb, int i, int line)
char body[SWITCH_RTP_MAX_BUF_LEN+4+sizeof(char *)]
Definition: switch_rtp.h:54
switch_mutex_t * list_mutex
switch_jb_flag_t flags
Main Library Header.
static switch_jb_node_t * new_node(switch_jb_t *jb)
static switch_status_t jb_next_packet_by_seq(switch_jb_t *jb, switch_jb_node_t **nodep)
#define SWITCH_DECLARE(type)
static void set_read_ts(switch_jb_t *jb, uint32_t ts)
#define switch_channel_set_flag(_c, _f)
void switch_jb_set_flag(switch_jb_t *jb, switch_jb_flag_t flag)
switch_core_session_t * session
uint32_t last_target_seq
switch_size_t switch_jb_get_last_read_len(switch_jb_t *jb)
struct switch_jb_node_s * prev
static void free_nodes(switch_jb_t *jb)
switch_status_t switch_jb_set_frames(switch_jb_t *jb, uint32_t min_frame_len, uint32_t max_frame_len)
uint32_t highest_frame_len
struct apr_pool_t switch_memory_pool_t
#define switch_test_flag(obj, flag)
Test for the existance of a flag on an arbitary object.
Definition: switch_utils.h:624
static void jb_miss(switch_jb_t *jb)
switch_memory_pool_t * pool
void switch_log_printf(_In_ switch_text_channel_t channel, _In_z_ const char *file, _In_z_ const char *func, _In_ int line, _In_opt_z_ const char *userdata, _In_ switch_log_level_t level, _In_z_ _Printf_format_string_ const char *fmt,...) PRINTF_FUNCTION(7
Write log data to the logging engine.
#define PERIOD_LEN
switch_rtp_packet_t packet
switch_jb_flag_t
switch_status_t switch_jb_get_frames(switch_jb_t *jb, uint32_t *min_frame_len, uint32_t *max_frame_len, uint32_t *cur_frame_len, uint32_t *highest_frame_len)
void switch_channel_clear_flag(switch_channel_t *channel, switch_channel_flag_t flag)
Clear given flag(s) from a channel.
uint32_t highest_wrote_seq
#define switch_assert(expr)
switch_time_t switch_time_now(void)
Definition: switch_apr.c:302
static switch_status_t jb_next_packet(switch_jb_t *jb, switch_jb_node_t **nodep)
uint32_t samples_per_frame
#define switch_core_hash_first(_h)
Definition: switch_core.h:1501
#define SWITCH_SIZE_T_FMT
static void hide_node(switch_jb_node_t *node, switch_bool_t pop)
struct switch_jb_node_s * node_list
void switch_jb_reset(switch_jb_t *jb)
uint32_t consec_good_count