Changeset 3814 for pjproject/branches/1.x/pjmedia/src/pjmedia/jbuf.c
- Timestamp:
- Oct 13, 2011 9:02:41 AM (12 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/branches/1.x/pjmedia/src/pjmedia/jbuf.c
r3779 r3814 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 … … 82 80 83 81 82 typedef void (*discard_algo)(pjmedia_jbuf *jb); 83 static void jbuf_discard_static(pjmedia_jbuf *jb); 84 static void jbuf_discard_progressive(pjmedia_jbuf *jb); 85 86 84 87 struct pjmedia_jbuf 85 88 { … … 98 101 calculation */ 99 102 int jb_min_shrink_gap; /**< How often can we shrink */ 103 discard_algo jb_discard_algo; /**< Discard algorithm */ 100 104 101 105 /* Buffer */ … … 125 129 int jb_init_cycle_cnt; /**< status is 'init' until the first 126 130 '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 */ 131 132 int jb_discard_ref; /**< Seq # of last frame deleted or 133 discarded */ 134 unsigned jb_discard_dist; /**< Distance from jb_discard_ref 135 to perform discard (in frm) */ 130 136 131 137 /* Statistics */ … … 393 399 enum { MAX_DROPOUT = 3000 }; 394 400 395 assert(frame_size <= framelist->frame_size);401 PJ_ASSERT_RETURN(frame_size <= framelist->frame_size, PJ_EINVAL); 396 402 397 403 /* too late or sequence restart */ … … 448 454 pj_memcpy(framelist->content + pos * framelist->frame_size, 449 455 frame, frame_size); 450 return PJ_SUCCESS; 451 } else { 452 /* frame is being discarded */ 453 framelist->discarded_num++; 454 return PJ_EIGNORED; 455 } 456 } 457 456 } 457 458 return PJ_SUCCESS; 459 } 460 461 462 static pj_status_t jb_framelist_discard(jb_framelist_t *framelist, 463 int index) 464 { 465 unsigned pos; 466 467 PJ_ASSERT_RETURN(index >= framelist->origin && 468 index < framelist->origin + (int)framelist->size, 469 PJ_EINVAL); 470 471 /* Get the slot position */ 472 pos = (framelist->head + (index - framelist->origin)) % 473 framelist->max_count; 474 475 /* Discard the frame */ 476 framelist->frame_type[pos] = PJMEDIA_JB_DISCARDED_FRAME; 477 framelist->discarded_num++; 478 479 return PJ_SUCCESS; 480 } 458 481 459 482 … … 489 512 jb->jb_max_prefetch = max_count*4/5; 490 513 jb->jb_max_count = max_count; 491 jb->jb_min_shrink_gap= MIN_SHRINK_GAP_MSEC/ ptime;514 jb->jb_min_shrink_gap= PJMEDIA_JBUF_DISC_MIN_GAP / ptime; 492 515 jb->jb_max_burst = PJ_MAX(MAX_BURST_MSEC / ptime, max_count*3/4); 493 jb->jb_last_discard_seq = 0;494 516 495 517 pj_math_stat_init(&jb->jb_delay); 496 518 pj_math_stat_init(&jb->jb_burst); 497 519 520 pjmedia_jbuf_set_discard(jb, PJMEDIA_JB_DISCARD_PROGRESSIVE); 498 521 pjmedia_jbuf_reset(jb); 499 522 … … 538 561 jb->jb_min_prefetch = min_prefetch; 539 562 jb->jb_max_prefetch = max_prefetch; 563 564 return PJ_SUCCESS; 565 } 566 567 568 PJ_DEF(pj_status_t) pjmedia_jbuf_set_discard( pjmedia_jbuf *jb, 569 pjmedia_jb_discard_algo algo) 570 { 571 PJ_ASSERT_RETURN(jb, PJ_EINVAL); 572 PJ_ASSERT_RETURN(algo >= PJMEDIA_JB_DISCARD_NONE && 573 algo <= PJMEDIA_JB_DISCARD_PROGRESSIVE, 574 PJ_EINVAL); 575 576 switch(algo) { 577 case PJMEDIA_JB_DISCARD_PROGRESSIVE: 578 jb->jb_discard_algo = &jbuf_discard_progressive; 579 break; 580 case PJMEDIA_JB_DISCARD_STATIC: 581 jb->jb_discard_algo = &jbuf_discard_static; 582 break; 583 default: 584 jb->jb_discard_algo = NULL; 585 break; 586 } 540 587 541 588 return PJ_SUCCESS; … … 552 599 jb->jb_max_hist_level= 0; 553 600 jb->jb_prefetching = (jb->jb_prefetch != 0); 601 jb->jb_discard_dist = 0; 554 602 555 603 jb_framelist_reset(&jb->jb_framelist); … … 563 611 PJ_LOG(5, (jb->jb_name.ptr, "" 564 612 "JB summary:\n" 565 " size=%d prefetch=%d level=%d\n"613 " size=%d/eff=%d prefetch=%d level=%d\n" 566 614 " delay (min/max/avg/dev)=%d/%d/%d/%d ms\n" 567 615 " burst (min/max/avg/dev)=%d/%d/%d/%d frames\n" 568 616 " lost=%d discard=%d empty=%d", 569 jb->jb_framelist.size, jb->jb_prefetch, jb->jb_eff_level, 617 jb_framelist_size(&jb->jb_framelist), 618 jb_framelist_eff_size(&jb->jb_framelist), 619 jb->jb_prefetch, jb->jb_eff_level, 570 620 jb->jb_delay.min, jb->jb_delay.max, jb->jb_delay.mean, 571 621 pj_math_stat_get_stddev(&jb->jb_delay), … … 649 699 } 650 700 } 701 702 703 static void jbuf_discard_static(pjmedia_jbuf *jb) 704 { 705 /* These code is used for shortening the delay in the jitter buffer. 706 * It needs shrink only when there is possibility of drift. Drift 707 * detection is performed by inspecting the jitter buffer size, if 708 * its size is twice of current burst level, there can be drift. 709 * 710 * Moreover, normally drift level is quite low, so JB shouldn't need 711 * to shrink aggresively, it will shrink maximum one frame per 712 * PJMEDIA_JBUF_DISC_MIN_GAP ms. Theoritically, JB may handle drift level 713 * as much as = FRAME_PTIME/PJMEDIA_JBUF_DISC_MIN_GAP * 100% 714 * 715 * Whenever there is drift, where PUT > GET, this method will keep 716 * the latency (JB size) as much as twice of burst level. 717 */ 718 719 /* Shrinking due of drift will be implicitly done by progressive discard, 720 * so just disable it when progressive discard is active. 721 */ 722 int diff, burst_level; 723 724 burst_level = PJ_MAX(jb->jb_eff_level, jb->jb_level); 725 diff = jb_framelist_eff_size(&jb->jb_framelist) - burst_level*2; 726 727 if (diff >= STA_DISC_SAFE_SHRINKING_DIFF) { 728 int seq_origin; 729 730 /* Check and adjust jb_discard_ref, in case there was 731 * seq restart 732 */ 733 seq_origin = jb_framelist_origin(&jb->jb_framelist); 734 if (seq_origin < jb->jb_discard_ref) 735 jb->jb_discard_ref = seq_origin; 736 737 if (seq_origin - jb->jb_discard_ref >= jb->jb_min_shrink_gap) 738 { 739 /* Shrink slowly, one frame per cycle */ 740 diff = 1; 741 742 /* Drop frame(s)! */ 743 diff = jb_framelist_remove_head(&jb->jb_framelist, diff); 744 jb->jb_discard_ref = jb_framelist_origin(&jb->jb_framelist); 745 jb->jb_discard += diff; 746 747 TRACE__((jb->jb_name.ptr, 748 "JB shrinking %d frame(s), cur size=%d", diff, 749 jb_framelist_eff_size(&jb->jb_framelist))); 750 } 751 } 752 } 753 754 755 static void jbuf_discard_progressive(pjmedia_jbuf *jb) 756 { 757 unsigned cur_size, burst_level, overflow, T, discard_dist; 758 int last_seq; 759 760 /* Should be done in PUT operation */ 761 if (jb->jb_last_op != JB_OP_PUT) 762 return; 763 764 /* Check if latency is longer than burst */ 765 cur_size = jb_framelist_eff_size(&jb->jb_framelist); 766 burst_level = PJ_MAX(jb->jb_eff_level, jb->jb_level); 767 if (cur_size <= burst_level) { 768 /* Reset any scheduled discard */ 769 jb->jb_discard_dist = 0; 770 return; 771 } 772 773 /* Estimate discard duration needed for adjusting latency */ 774 if (burst_level <= PJMEDIA_JBUF_PRO_DISC_MIN_BURST) 775 T = PJMEDIA_JBUF_PRO_DISC_T1; 776 else if (burst_level >= PJMEDIA_JBUF_PRO_DISC_MAX_BURST) 777 T = PJMEDIA_JBUF_PRO_DISC_T2; 778 else 779 T = PJMEDIA_JBUF_PRO_DISC_T1 + 780 (PJMEDIA_JBUF_PRO_DISC_T2 - PJMEDIA_JBUF_PRO_DISC_T1) * 781 (burst_level - PJMEDIA_JBUF_PRO_DISC_MIN_BURST) / 782 (PJMEDIA_JBUF_PRO_DISC_MAX_BURST-PJMEDIA_JBUF_PRO_DISC_MIN_BURST); 783 784 /* Calculate current discard distance */ 785 overflow = cur_size - burst_level; 786 discard_dist = T / overflow / jb->jb_frame_ptime; 787 788 /* Get last seq number in the JB */ 789 last_seq = jb_framelist_origin(&jb->jb_framelist) + 790 jb_framelist_size(&jb->jb_framelist) - 1; 791 792 /* Setup new discard schedule if none, otherwise, update the existing 793 * discard schedule (can be delayed or accelerated). 794 */ 795 if (jb->jb_discard_dist == 0) { 796 /* Setup new discard schedule */ 797 jb->jb_discard_ref = last_seq; 798 } else if (last_seq < jb->jb_discard_ref) { 799 /* Seq restarted, update discard reference */ 800 jb->jb_discard_ref = last_seq; 801 } 802 jb->jb_discard_dist = PJ_MAX(jb->jb_min_shrink_gap, (int)discard_dist); 803 804 /* Check if we need to discard now */ 805 if (last_seq >= (jb->jb_discard_ref + (int)jb->jb_discard_dist)) { 806 int discard_seq; 807 808 discard_seq = jb->jb_discard_ref + jb->jb_discard_dist; 809 if (discard_seq < jb_framelist_origin(&jb->jb_framelist)) 810 discard_seq = jb_framelist_origin(&jb->jb_framelist); 811 812 jb_framelist_discard(&jb->jb_framelist, discard_seq); 813 814 TRACE__((jb->jb_name.ptr, 815 "Discard #%d: ref=#%d dist=%d orig=%d size=%d/%d " 816 "burst=%d/%d", 817 discard_seq, 818 jb->jb_discard_ref, 819 jb->jb_discard_dist, 820 jb_framelist_origin(&jb->jb_framelist), 821 cur_size, 822 jb_framelist_size(&jb->jb_framelist), 823 jb->jb_eff_level, 824 burst_level)); 825 826 /* Update discard reference */ 827 jb->jb_discard_ref = discard_seq; 828 } 829 } 830 651 831 652 832 PJ_INLINE(void) jbuf_update(pjmedia_jbuf *jb, int oper) … … 685 865 } 686 866 687 /* These code is used for shortening the delay in the jitter buffer. 688 * It needs shrink only when there is possibility of drift. Drift 689 * detection is performed by inspecting the jitter buffer size, if 690 * its size is twice of current burst level, there can be drift. 691 * 692 * Moreover, normally drift level is quite low, so JB shouldn't need 693 * to shrink aggresively, it will shrink maximum one frame per 694 * MIN_SHRINK_GAP_MSEC ms. Theoritically, JB may handle drift level 695 * as much as = FRAME_PTIME/MIN_SHRINK_GAP_MSEC * 100% 696 * 697 * Whenever there is drift, where PUT > GET, this method will keep 698 * the latency (JB size) as much as twice of burst level. 699 */ 700 701 /* Shrinking due of drift will be implicitly done by progressive discard, 702 * so just disable it when progressive discard is active. 703 */ 704 #if !PROGRESSIVE_DISCARD 705 706 if (jb->jb_status != JB_STATUS_PROCESSING) 707 return; 708 709 { 710 int diff, burst_level; 711 712 burst_level = PJ_MAX(jb->jb_eff_level, jb->jb_level); 713 diff = jb_framelist_eff_size(&jb->jb_framelist) - burst_level*2; 714 715 if (diff >= SAFE_SHRINKING_DIFF) { 716 int seq_origin; 717 718 /* Check and adjust jb_last_del_seq, in case there was 719 * seq restart 720 */ 721 seq_origin = jb_framelist_origin(&jb->jb_framelist); 722 if (seq_origin < jb->jb_last_del_seq) 723 jb->jb_last_del_seq = seq_origin; 724 725 if (seq_origin - jb->jb_last_del_seq >= jb->jb_min_shrink_gap) 726 { 727 /* Shrink slowly, one frame per cycle */ 728 diff = 1; 729 730 /* Drop frame(s)! */ 731 diff = jb_framelist_remove_head(&jb->jb_framelist, diff); 732 jb->jb_last_del_seq = jb_framelist_origin(&jb->jb_framelist); 733 jb->jb_discard += diff; 734 735 TRACE__((jb->jb_name.ptr, 736 "JB shrinking %d frame(s), cur size=%d", diff, 737 jb_framelist_eff_size(&jb->jb_framelist))); 738 } 739 } 740 } 741 742 #endif /* !PROGRESSIVE_DISCARD */ 743 867 /* Call discard algorithm */ 868 if (jb->jb_status == JB_STATUS_PROCESSING && jb->jb_discard_algo) { 869 (*jb->jb_discard_algo)(jb); 870 } 744 871 } 745 872 … … 760 887 { 761 888 pj_size_t min_frame_size; 762 int new_size, cur_size , frame_type = PJMEDIA_JB_NORMAL_FRAME;889 int new_size, cur_size; 763 890 pj_status_t status; 764 891 765 892 cur_size = jb_framelist_eff_size(&jb->jb_framelist); 766 767 #if PROGRESSIVE_DISCARD768 {769 unsigned interval, seq_delta;770 unsigned burst_level = 0, overflow_pct = 0;771 772 /* Calculating percentage of burst overflow */773 if (jb->jb_status == JB_STATUS_PROCESSING) {774 burst_level = PJ_MAX(jb->jb_eff_level, jb->jb_level);775 if (cur_size > (int)burst_level)776 overflow_pct = (cur_size - burst_level) * 100 / burst_level;777 }778 779 /* Deciding discard interval (aggressiveness) based on780 * burst overflow percentage.781 */782 if (burst_level <= 5 && overflow_pct < 200) {783 /* Tolerate spikes on relatively small burst level */784 interval = 0;785 } else if (overflow_pct >= 200) {786 /* Overflow >= 200% */787 interval = 4;788 } else if (overflow_pct >= 100) {789 /* Overflow >= 100% */790 interval = 5;791 } else if (overflow_pct >= 10) {792 /* Overflow >= 10% */793 interval = 7;794 } else {795 /* Overflow < 10%, tolerable */796 interval = 0;797 }798 799 /* Do the math now to see if we should discard this packet.800 * Calculate the distance from the last sequence801 * discarded. If negative, then this is an out of802 * order frame so just proceed with discard. Else803 * see if the delta is at least the intervals worth away804 * from the last frame discarded.805 */806 seq_delta = (pj_uint16_t)(frame_seq - jb->jb_last_discard_seq);807 if ((0 != interval) && (seq_delta >= interval)) {808 frame_type = PJMEDIA_JB_DISCARDED_FRAME;809 jb->jb_last_discard_seq = frame_seq;810 811 TRACE__((jb->jb_name.ptr,812 "Discarding frame #%d: eff=%d disc=%d orig:%d"813 " seq_delta:%d",814 frame_seq,815 cur_size,816 jb_framelist_size(&jb->jb_framelist) - cur_size,817 jb_framelist_origin(&jb->jb_framelist),818 (int)seq_delta));819 }820 }821 #endif /* PROGRESSIVE_DISCARD */822 823 893 824 894 /* Attempt to store the frame */ 825 895 min_frame_size = PJ_MIN(frame_size, jb->jb_frame_size); 826 896 status = jb_framelist_put_at(&jb->jb_framelist, frame_seq, frame, 827 min_frame_size, bit_info, frame_type); 897 min_frame_size, bit_info, 898 PJMEDIA_JB_NORMAL_FRAME); 828 899 829 900 /* Jitter buffer is full, remove some older frames */ … … 832 903 unsigned removed; 833 904 834 /* When progressive discard activated, just remove as few as possible 835 * just to make this frame in. 836 */ 837 #if PROGRESSIVE_DISCARD 838 /* The cases of seq-jump, out-of-order, and seq restart should have 905 /* Remove as few as possible just to make this frame in. Note that 906 * the cases of seq-jump, out-of-order, and seq restart should have 839 907 * been handled/normalized by previous call of jb_framelist_put_at(). 840 908 * So we're confident about 'distance' value here. … … 843 911 jb->jb_max_count + 1; 844 912 pj_assert(distance > 0); 845 #else 846 distance = PJ_MAX(jb->jb_max_count/4, 1); 847 #endif 913 848 914 removed = jb_framelist_remove_head(&jb->jb_framelist, distance); 849 915 status = jb_framelist_put_at(&jb->jb_framelist, frame_seq, frame, 850 min_frame_size, bit_info, frame_type); 916 min_frame_size, bit_info, 917 PJMEDIA_JB_NORMAL_FRAME); 851 918 852 919 jb->jb_discard += removed;
Note: See TracChangeset
for help on using the changeset viewer.