Changeset 3841 for pjproject/trunk/pjmedia/src/pjmedia/jbuf.c
- Timestamp:
- Oct 24, 2011 9:28:13 AM (13 years ago)
- Location:
- pjproject/trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk
- Property svn:mergeinfo changed
-
pjproject/trunk/pjmedia/src/pjmedia/jbuf.c
r3835 r3841 33 33 34 34 35 /* Minimal difference between JB size and 2*burst-level to perform36 * JB shrinking.37 */38 #define SAFE_SHRINKING_DIFF 139 40 /* Minimal gap (in ms) between JB shrinking */41 #define MIN_SHRINK_GAP_MSEC 20042 43 35 /* Invalid sequence number, used as the initial value. */ 44 36 #define INVALID_OFFSET -9999 … … 53 45 */ 54 46 #define INIT_CYCLE 10 47 48 49 /* Minimal difference between JB size and 2*burst-level to perform 50 * JB shrinking in static discard algorithm. 51 */ 52 #define STA_DISC_SAFE_SHRINKING_DIFF 1 55 53 56 54 … … 83 81 84 82 83 typedef void (*discard_algo)(pjmedia_jbuf *jb); 84 static void jbuf_discard_static(pjmedia_jbuf *jb); 85 static void jbuf_discard_progressive(pjmedia_jbuf *jb); 86 87 85 88 struct pjmedia_jbuf 86 89 { … … 99 102 calculation */ 100 103 int jb_min_shrink_gap; /**< How often can we shrink */ 104 discard_algo jb_discard_algo; /**< Discard algorithm */ 101 105 102 106 /* Buffer */ … … 121 125 continuously updated based on 122 126 current frame burst level. */ 127 pj_bool_t jb_prefetching; /**< flag if jbuf is prefetching. */ 123 128 int jb_status; /**< status is 'init' until the first 124 129 'put' operation */ 125 130 int jb_init_cycle_cnt; /**< status is 'init' until the first 126 131 'put' operation */ 127 int jb_last_del_seq; /**< Seq # of last frame deleted */ 128 129 int jb_last_discard_seq;/**< Seq # of last frame discarded */ 132 133 int jb_discard_ref; /**< Seq # of last frame deleted or 134 discarded */ 135 unsigned jb_discard_dist; /**< Distance from jb_discard_ref 136 to perform discard (in frm) */ 130 137 131 138 /* Statistics */ … … 142 149 #define JB_STATUS_INITIALIZING 0 143 150 #define JB_STATUS_PROCESSING 1 144 #define JB_STATUS_PREFETCHING 2145 151 146 152 … … 452 458 enum { MAX_DROPOUT = 3000 }; 453 459 454 assert(frame_size <= framelist->frame_size);460 PJ_ASSERT_RETURN(frame_size <= framelist->frame_size, PJ_EINVAL); 455 461 456 462 /* too late or sequence restart */ … … 508 514 pj_memcpy(framelist->content + pos * framelist->frame_size, 509 515 frame, frame_size); 510 return PJ_SUCCESS; 511 } else { 512 /* frame is being discarded */ 513 framelist->discarded_num++; 514 return PJ_EIGNORED; 515 } 516 } 517 516 } 517 518 return PJ_SUCCESS; 519 } 520 521 522 static pj_status_t jb_framelist_discard(jb_framelist_t *framelist, 523 int index) 524 { 525 unsigned pos; 526 527 PJ_ASSERT_RETURN(index >= framelist->origin && 528 index < framelist->origin + (int)framelist->size, 529 PJ_EINVAL); 530 531 /* Get the slot position */ 532 pos = (framelist->head + (index - framelist->origin)) % 533 framelist->max_count; 534 535 /* Discard the frame */ 536 framelist->frame_type[pos] = PJMEDIA_JB_DISCARDED_FRAME; 537 framelist->discarded_num++; 538 539 return PJ_SUCCESS; 540 } 518 541 519 542 … … 549 572 jb->jb_max_prefetch = max_count*4/5; 550 573 jb->jb_max_count = max_count; 551 jb->jb_min_shrink_gap= MIN_SHRINK_GAP_MSEC/ ptime;574 jb->jb_min_shrink_gap= PJMEDIA_JBUF_DISC_MIN_GAP / ptime; 552 575 jb->jb_max_burst = PJ_MAX(MAX_BURST_MSEC / ptime, max_count*3/4); 553 jb->jb_last_discard_seq = 0;554 576 555 577 pj_math_stat_init(&jb->jb_delay); 556 578 pj_math_stat_init(&jb->jb_burst); 557 579 580 pjmedia_jbuf_set_discard(jb, PJMEDIA_JB_DISCARD_PROGRESSIVE); 558 581 pjmedia_jbuf_reset(jb); 559 582 … … 590 613 { 591 614 PJ_ASSERT_RETURN(jb, PJ_EINVAL); 592 PJ_ASSERT_RETURN(min_prefetch < max_prefetch &&615 PJ_ASSERT_RETURN(min_prefetch <= max_prefetch && 593 616 prefetch <= max_prefetch && 594 617 max_prefetch <= jb->jb_max_count, … … 598 621 jb->jb_min_prefetch = min_prefetch; 599 622 jb->jb_max_prefetch = max_prefetch; 623 624 return PJ_SUCCESS; 625 } 626 627 628 PJ_DEF(pj_status_t) pjmedia_jbuf_set_discard( pjmedia_jbuf *jb, 629 pjmedia_jb_discard_algo algo) 630 { 631 PJ_ASSERT_RETURN(jb, PJ_EINVAL); 632 PJ_ASSERT_RETURN(algo >= PJMEDIA_JB_DISCARD_NONE && 633 algo <= PJMEDIA_JB_DISCARD_PROGRESSIVE, 634 PJ_EINVAL); 635 636 switch(algo) { 637 case PJMEDIA_JB_DISCARD_PROGRESSIVE: 638 jb->jb_discard_algo = &jbuf_discard_progressive; 639 break; 640 case PJMEDIA_JB_DISCARD_STATIC: 641 jb->jb_discard_algo = &jbuf_discard_static; 642 break; 643 default: 644 jb->jb_discard_algo = NULL; 645 break; 646 } 600 647 601 648 return PJ_SUCCESS; … … 611 658 jb->jb_init_cycle_cnt= 0; 612 659 jb->jb_max_hist_level= 0; 660 jb->jb_prefetching = (jb->jb_prefetch != 0); 661 jb->jb_discard_dist = 0; 613 662 614 663 jb_framelist_reset(&jb->jb_framelist); … … 622 671 PJ_LOG(5, (jb->jb_name.ptr, "" 623 672 "JB summary:\n" 624 " size=%d prefetch=%d level=%d\n"673 " size=%d/eff=%d prefetch=%d level=%d\n" 625 674 " delay (min/max/avg/dev)=%d/%d/%d/%d ms\n" 626 675 " burst (min/max/avg/dev)=%d/%d/%d/%d frames\n" 627 676 " lost=%d discard=%d empty=%d", 628 jb->jb_framelist.size, jb->jb_prefetch, jb->jb_eff_level, 677 jb_framelist_size(&jb->jb_framelist), 678 jb_framelist_eff_size(&jb->jb_framelist), 679 jb->jb_prefetch, jb->jb_eff_level, 629 680 jb->jb_delay.min, jb->jb_delay.max, jb->jb_delay.mean, 630 681 pj_math_stat_get_stddev(&jb->jb_delay), … … 712 763 } 713 764 } 765 766 767 static void jbuf_discard_static(pjmedia_jbuf *jb) 768 { 769 /* These code is used for shortening the delay in the jitter buffer. 770 * It needs shrink only when there is possibility of drift. Drift 771 * detection is performed by inspecting the jitter buffer size, if 772 * its size is twice of current burst level, there can be drift. 773 * 774 * Moreover, normally drift level is quite low, so JB shouldn't need 775 * to shrink aggresively, it will shrink maximum one frame per 776 * PJMEDIA_JBUF_DISC_MIN_GAP ms. Theoritically, JB may handle drift level 777 * as much as = FRAME_PTIME/PJMEDIA_JBUF_DISC_MIN_GAP * 100% 778 * 779 * Whenever there is drift, where PUT > GET, this method will keep 780 * the latency (JB size) as much as twice of burst level. 781 */ 782 783 /* Shrinking due of drift will be implicitly done by progressive discard, 784 * so just disable it when progressive discard is active. 785 */ 786 int diff, burst_level; 787 788 burst_level = PJ_MAX(jb->jb_eff_level, jb->jb_level); 789 diff = jb_framelist_eff_size(&jb->jb_framelist) - burst_level*2; 790 791 if (diff >= STA_DISC_SAFE_SHRINKING_DIFF) { 792 int seq_origin; 793 794 /* Check and adjust jb_discard_ref, in case there was 795 * seq restart 796 */ 797 seq_origin = jb_framelist_origin(&jb->jb_framelist); 798 if (seq_origin < jb->jb_discard_ref) 799 jb->jb_discard_ref = seq_origin; 800 801 if (seq_origin - jb->jb_discard_ref >= jb->jb_min_shrink_gap) 802 { 803 /* Shrink slowly, one frame per cycle */ 804 diff = 1; 805 806 /* Drop frame(s)! */ 807 diff = jb_framelist_remove_head(&jb->jb_framelist, diff); 808 jb->jb_discard_ref = jb_framelist_origin(&jb->jb_framelist); 809 jb->jb_discard += diff; 810 811 TRACE__((jb->jb_name.ptr, 812 "JB shrinking %d frame(s), cur size=%d", diff, 813 jb_framelist_eff_size(&jb->jb_framelist))); 814 } 815 } 816 } 817 818 819 static void jbuf_discard_progressive(pjmedia_jbuf *jb) 820 { 821 unsigned cur_size, burst_level, overflow, T, discard_dist; 822 int last_seq; 823 824 /* Should be done in PUT operation */ 825 if (jb->jb_last_op != JB_OP_PUT) 826 return; 827 828 /* Check if latency is longer than burst */ 829 cur_size = jb_framelist_eff_size(&jb->jb_framelist); 830 burst_level = PJ_MAX(jb->jb_eff_level, jb->jb_level); 831 if (cur_size <= burst_level) { 832 /* Reset any scheduled discard */ 833 jb->jb_discard_dist = 0; 834 return; 835 } 836 837 /* Estimate discard duration needed for adjusting latency */ 838 if (burst_level <= PJMEDIA_JBUF_PRO_DISC_MIN_BURST) 839 T = PJMEDIA_JBUF_PRO_DISC_T1; 840 else if (burst_level >= PJMEDIA_JBUF_PRO_DISC_MAX_BURST) 841 T = PJMEDIA_JBUF_PRO_DISC_T2; 842 else 843 T = PJMEDIA_JBUF_PRO_DISC_T1 + 844 (PJMEDIA_JBUF_PRO_DISC_T2 - PJMEDIA_JBUF_PRO_DISC_T1) * 845 (burst_level - PJMEDIA_JBUF_PRO_DISC_MIN_BURST) / 846 (PJMEDIA_JBUF_PRO_DISC_MAX_BURST-PJMEDIA_JBUF_PRO_DISC_MIN_BURST); 847 848 /* Calculate current discard distance */ 849 overflow = cur_size - burst_level; 850 discard_dist = T / overflow / jb->jb_frame_ptime; 851 852 /* Get last seq number in the JB */ 853 last_seq = jb_framelist_origin(&jb->jb_framelist) + 854 jb_framelist_size(&jb->jb_framelist) - 1; 855 856 /* Setup new discard schedule if none, otherwise, update the existing 857 * discard schedule (can be delayed or accelerated). 858 */ 859 if (jb->jb_discard_dist == 0) { 860 /* Setup new discard schedule */ 861 jb->jb_discard_ref = last_seq; 862 } else if (last_seq < jb->jb_discard_ref) { 863 /* Seq restarted, update discard reference */ 864 jb->jb_discard_ref = last_seq; 865 } 866 jb->jb_discard_dist = PJ_MAX(jb->jb_min_shrink_gap, (int)discard_dist); 867 868 /* Check if we need to discard now */ 869 if (last_seq >= (jb->jb_discard_ref + (int)jb->jb_discard_dist)) { 870 int discard_seq; 871 872 discard_seq = jb->jb_discard_ref + jb->jb_discard_dist; 873 if (discard_seq < jb_framelist_origin(&jb->jb_framelist)) 874 discard_seq = jb_framelist_origin(&jb->jb_framelist); 875 876 jb_framelist_discard(&jb->jb_framelist, discard_seq); 877 878 TRACE__((jb->jb_name.ptr, 879 "Discard #%d: ref=#%d dist=%d orig=%d size=%d/%d " 880 "burst=%d/%d", 881 discard_seq, 882 jb->jb_discard_ref, 883 jb->jb_discard_dist, 884 jb_framelist_origin(&jb->jb_framelist), 885 cur_size, 886 jb_framelist_size(&jb->jb_framelist), 887 jb->jb_eff_level, 888 burst_level)); 889 890 /* Update discard reference */ 891 jb->jb_discard_ref = discard_seq; 892 } 893 } 894 714 895 715 896 PJ_INLINE(void) jbuf_update(pjmedia_jbuf *jb, int oper) … … 748 929 } 749 930 750 /* These code is used for shortening the delay in the jitter buffer. 751 * It needs shrink only when there is possibility of drift. Drift 752 * detection is performed by inspecting the jitter buffer size, if 753 * its size is twice of current burst level, there can be drift. 754 * 755 * Moreover, normally drift level is quite low, so JB shouldn't need 756 * to shrink aggresively, it will shrink maximum one frame per 757 * MIN_SHRINK_GAP_MSEC ms. Theoritically, JB may handle drift level 758 * as much as = FRAME_PTIME/MIN_SHRINK_GAP_MSEC * 100% 759 * 760 * Whenever there is drift, where PUT > GET, this method will keep 761 * the latency (JB size) as much as twice of burst level. 762 */ 763 764 /* Shrinking due of drift will be implicitly done by progressive discard, 765 * so just disable it when progressive discard is active. 766 */ 767 #if !PROGRESSIVE_DISCARD 768 769 if (jb->jb_status != JB_STATUS_PROCESSING) 770 return; 771 772 { 773 int diff, burst_level; 774 775 burst_level = PJ_MAX(jb->jb_eff_level, jb->jb_level); 776 diff = jb_framelist_eff_size(&jb->jb_framelist) - burst_level*2; 777 778 if (diff >= SAFE_SHRINKING_DIFF) { 779 int seq_origin; 780 781 /* Check and adjust jb_last_del_seq, in case there was 782 * seq restart 783 */ 784 seq_origin = jb_framelist_origin(&jb->jb_framelist); 785 if (seq_origin < jb->jb_last_del_seq) 786 jb->jb_last_del_seq = seq_origin; 787 788 if (seq_origin - jb->jb_last_del_seq >= jb->jb_min_shrink_gap) 789 { 790 /* Shrink slowly, one frame per cycle */ 791 diff = 1; 792 793 /* Drop frame(s)! */ 794 diff = jb_framelist_remove_head(&jb->jb_framelist, diff); 795 jb->jb_last_del_seq = jb_framelist_origin(&jb->jb_framelist); 796 jb->jb_discard += diff; 797 798 TRACE__((jb->jb_name.ptr, 799 "JB shrinking %d frame(s), cur size=%d", diff, 800 jb_framelist_eff_size(&jb->jb_framelist))); 801 } 802 } 803 } 804 805 #endif /* !PROGRESSIVE_DISCARD */ 806 931 /* Call discard algorithm */ 932 if (jb->jb_status == JB_STATUS_PROCESSING && jb->jb_discard_algo) { 933 (*jb->jb_discard_algo)(jb); 934 } 807 935 } 808 936 … … 835 963 { 836 964 pj_size_t min_frame_size; 837 int new_size, cur_size , frame_type = PJMEDIA_JB_NORMAL_FRAME;965 int new_size, cur_size; 838 966 pj_status_t status; 839 967 840 968 cur_size = jb_framelist_eff_size(&jb->jb_framelist); 841 842 #if PROGRESSIVE_DISCARD843 {844 unsigned interval, seq_delta;845 unsigned burst_level, burst_factor;846 847 /* Calculating discard interval (aggressiveness) based on848 * (current size / burst level).849 */850 if (jb->jb_status == JB_STATUS_PROCESSING) {851 burst_level = PJ_MAX(jb->jb_eff_level, jb->jb_level);852 burst_factor = cur_size / burst_level;853 /* Tolerate small spikes */854 if ((burst_level <= 5) && (burst_factor < 3))855 burst_factor = 0;856 } else {857 burst_factor = 0;858 }859 860 switch (burst_factor) {861 case 0:862 interval = 0;863 break;864 case 1:865 interval = 7;866 break;867 case 2:868 interval = 5;869 break;870 default:871 interval = 4;872 break;873 }874 875 /* Do the math now to see if we should discard this packet.876 * Calculate the distance from the last sequence877 * discarded. If negative, then this is an out of878 * order frame so just proceed with discard. Else879 * see if the delta is at least the intervals worth away880 * from the last frame discarded.881 */882 seq_delta = (pj_uint16_t)(frame_seq - jb->jb_last_discard_seq);883 if ((0 != interval) && (seq_delta >= interval)) {884 frame_type = PJMEDIA_JB_DISCARDED_FRAME;885 jb->jb_last_discard_seq = frame_seq;886 887 TRACE__((jb->jb_name.ptr,888 "Discarding frame #%d: eff=%d disc=%d orig:%d"889 " seq_delta:%d",890 frame_seq,891 cur_size,892 jb_framelist_size(&jb->jb_framelist) - cur_size,893 jb_framelist_origin(&jb->jb_framelist),894 (int)seq_delta));895 }896 }897 #endif /* PROGRESSIVE_DISCARD */898 899 969 900 970 /* Attempt to store the frame */ 901 971 min_frame_size = PJ_MIN(frame_size, jb->jb_frame_size); 902 972 status = jb_framelist_put_at(&jb->jb_framelist, frame_seq, frame, 903 min_frame_size, bit_info, ts, frame_type); 973 min_frame_size, bit_info, ts, 974 PJMEDIA_JB_NORMAL_FRAME); 904 975 905 976 /* Jitter buffer is full, remove some older frames */ … … 908 979 unsigned removed; 909 980 910 /* When progressive discard activated, just remove as few as possible 911 * just to make this frame in. 912 */ 913 #if PROGRESSIVE_DISCARD 914 /* The cases of seq-jump, out-of-order, and seq restart should have 981 /* Remove as few as possible just to make this frame in. Note that 982 * the cases of seq-jump, out-of-order, and seq restart should have 915 983 * been handled/normalized by previous call of jb_framelist_put_at(). 916 984 * So we're confident about 'distance' value here. … … 919 987 jb->jb_max_count + 1; 920 988 pj_assert(distance > 0); 921 #else 922 distance = PJ_MAX(jb->jb_max_count/4, 1); 923 #endif 989 924 990 removed = jb_framelist_remove_head(&jb->jb_framelist, distance); 925 991 status = jb_framelist_put_at(&jb->jb_framelist, frame_seq, frame, 926 min_frame_size, bit_info, ts, frame_type); 992 min_frame_size, bit_info, ts, 993 PJMEDIA_JB_NORMAL_FRAME); 927 994 928 995 jb->jb_discard += removed; … … 937 1004 938 1005 if (status == PJ_SUCCESS) { 939 if (jb->jb_ status == JB_STATUS_PREFETCHING) {1006 if (jb->jb_prefetching) { 940 1007 TRACE__((jb->jb_name.ptr, "PUT prefetch_cnt=%d/%d", 941 1008 new_size, jb->jb_prefetch)); 942 1009 if (new_size >= jb->jb_prefetch) 943 jb->jb_ status = JB_STATUS_PROCESSING;1010 jb->jb_prefetching = PJ_FALSE; 944 1011 } 945 1012 jb->jb_level += (new_size > cur_size ? new_size-cur_size : 1); … … 984 1051 int *seq) 985 1052 { 986 if (jb->jb_ status == JB_STATUS_PREFETCHING) {1053 if (jb->jb_prefetching) { 987 1054 988 1055 /* Can't return frame because jitter buffer is filling up … … 1031 1098 /* Jitter buffer is empty */ 1032 1099 if (jb->jb_prefetch) 1033 jb->jb_ status = JB_STATUS_PREFETCHING;1100 jb->jb_prefetching = PJ_TRUE; 1034 1101 1035 1102 //pj_bzero(frame, jb->jb_frame_size);
Note: See TracChangeset
for help on using the changeset viewer.