Ticket #513: xr.patch

File xr.patch, 62.9 KB (added by nanang, 16 years ago)
  • pjmedia/include/pjmedia/config.h

     
    339339#   define  PJMEDIA_RTCP_IGNORE_FIRST_PACKETS   25 
    340340#endif 
    341341 
     342/** 
     343 * Specify whether RTCP XR support should be built into PJMEDIA. Disabling 
     344 * this feature will reduce footprint slightly. Note that even when this  
     345 * setting is enabled, RTCP XR processing will only be performed in stream  
     346 * if it is enabled on run-time on per stream basis. See   
     347 * PJMEDIA_STREAM_ENABLE_XR setting for more info. 
     348 * 
     349 * Default: 1 (yes). 
     350 */ 
     351#ifndef PJMEDIA_HAS_RTCP_XR 
     352#   define PJMEDIA_HAS_RTCP_XR                  1 
     353#endif 
    342354 
     355 
    343356/** 
     357 * The RTCP XR feature is activated and used by stream if \a enable_rtcp_xr 
     358 * field of \a pjmedia_stream_info structure is non-zero. This setting  
     359 * controls the default value of this field. 
     360 * 
     361 * Default: 0 (disabled) 
     362 */ 
     363#ifndef PJMEDIA_STREAM_ENABLE_XR 
     364#   define PJMEDIA_STREAM_ENABLE_XR             0 
     365#endif 
     366 
     367/** 
    344368 * Specify how long (in miliseconds) the stream should suspend the 
    345369 * silence detector/voice activity detector (VAD) during the initial 
    346370 * period of the session. This feature is useful to open bindings in 
  • pjmedia/include/pjmedia/rtcp_xr.h

     
     1/* $Id$ */ 
     2/*  
     3 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org> 
     4 * 
     5 * This program is free software; you can redistribute it and/or modify 
     6 * it under the terms of the GNU General Public License as published by 
     7 * the Free Software Foundation; either version 2 of the License, or 
     8 * (at your option) any later version. 
     9 * 
     10 * This program is distributed in the hope that it will be useful, 
     11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 
     12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
     13 * GNU General Public License for more details. 
     14 * 
     15 * You should have received a copy of the GNU General Public License 
     16 * along with this program; if not, write to the Free Software 
     17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  
     18 */ 
     19#ifndef __PJMEDIA_RTCP_XR_H__ 
     20#define __PJMEDIA_RTCP_XR_H__ 
     21 
     22/** 
     23 * @file rtcp_xr.h 
     24 * @brief RTCP XR implementation. 
     25 */ 
     26 
     27#include <pjmedia/types.h> 
     28 
     29 
     30PJ_BEGIN_DECL 
     31 
     32 
     33/** 
     34 * @defgroup PJMED_RTCP_XR RTCP Extended Report (XR) - RFC 3611 
     35 * @ingroup PJMEDIA_TRANSPORT 
     36 * @{ 
     37 * PJMEDIA implements subsets of RTCP XR specification (RFC 3611) to monitor 
     38 * the quality of the real-time media (audio/video) transmission. 
     39 */ 
     40 
     41/** 
     42 * Enumeration of report types of RTCP XR. Useful for user to enable varying 
     43 * combinations of RTCP XR report blocks. 
     44 */ 
     45typedef enum { 
     46    PJMEDIA_RTCP_XR_LOSS_RLE        = (1 << 0), 
     47    PJMEDIA_RTCP_XR_DUP_RLE         = (1 << 1), 
     48    PJMEDIA_RTCP_XR_RCPT_TIMES      = (1 << 2), 
     49    PJMEDIA_RTCP_XR_RR_TIME         = (1 << 3), 
     50    PJMEDIA_RTCP_XR_DLRR            = (1 << 4), 
     51    PJMEDIA_RTCP_XR_STATS           = (1 << 5), 
     52    PJMEDIA_RTCP_XR_VOIP_METRICS    = (1 << 6) 
     53} pjmedia_rtcp_xr_type; 
     54 
     55/** 
     56 * Enumeration of info need to be updated manually to RTCP XR. Most info 
     57 * could be updated automatically each time RTP received. 
     58 */ 
     59typedef enum { 
     60    PJMEDIA_RTCP_XR_INFO_SIGNAL_LVL = 1, 
     61    PJMEDIA_RTCP_XR_INFO_NOISE_LVL  = 2, 
     62    PJMEDIA_RTCP_XR_INFO_RERL       = 3, 
     63    PJMEDIA_RTCP_XR_INFO_R_FACTOR   = 4, 
     64    PJMEDIA_RTCP_XR_INFO_MOS_LQ     = 5, 
     65    PJMEDIA_RTCP_XR_INFO_MOS_CQ     = 6, 
     66    PJMEDIA_RTCP_XR_INFO_CONF_PLC   = 7, 
     67    PJMEDIA_RTCP_XR_INFO_CONF_JBA   = 8, 
     68    PJMEDIA_RTCP_XR_INFO_CONF_JBR   = 9, 
     69    PJMEDIA_RTCP_XR_INFO_JB_NOM     = 10, 
     70    PJMEDIA_RTCP_XR_INFO_JB_MAX     = 11, 
     71    PJMEDIA_RTCP_XR_INFO_JB_ABS_MAX = 12 
     72} pjmedia_rtcp_xr_info; 
     73 
     74/** 
     75 * Enumeration of PLC types definitions for RTCP XR report. 
     76 */ 
     77typedef enum { 
     78    PJMEDIA_RTCP_XR_PLC_UNK         = 0, 
     79    PJMEDIA_RTCP_XR_PLC_DIS         = 1, 
     80    PJMEDIA_RTCP_XR_PLC_ENH         = 2, 
     81    PJMEDIA_RTCP_XR_PLC_STD         = 3 
     82} pjmedia_rtcp_xr_plc_type; 
     83 
     84/** 
     85 * Enumeration of jitter buffer types definitions for RTCP XR report. 
     86 */ 
     87typedef enum { 
     88    PJMEDIA_RTCP_XR_JB_UNKNOWN      = 0, 
     89    PJMEDIA_RTCP_XR_JB_FIXED        = 2, 
     90    PJMEDIA_RTCP_XR_JB_ADAPTIVE     = 3 
     91} pjmedia_rtcp_xr_jb_type; 
     92 
     93 
     94#pragma pack(1) 
     95 
     96/** 
     97 * This type declares RTCP XR Report Header. 
     98 */ 
     99typedef struct pjmedia_rtcp_xr_rb_header 
     100{ 
     101    pj_uint8_t           bt;            /**< Block type.                */ 
     102    pj_uint8_t           specific;      /**< Block specific data.       */ 
     103    pj_uint16_t          length;        /**< Block length.              */ 
     104} pjmedia_rtcp_xr_rb_header; 
     105 
     106/** 
     107 * This type declares RTCP XR Receiver Reference Time Report Block. 
     108 */ 
     109typedef struct pjmedia_rtcp_xr_rb_rr_time 
     110{ 
     111    pjmedia_rtcp_xr_rb_header header;   /**< Block header.              */ 
     112    pj_uint32_t          ntp_sec;       /**< NTP time, seconds part.    */ 
     113    pj_uint32_t          ntp_frac;      /**< NTP time, fractions part.  */ 
     114} pjmedia_rtcp_xr_rb_rr_time; 
     115 
     116 
     117/** 
     118 * This type declares RTCP XR DLRR Report Sub-block 
     119 */ 
     120typedef struct pjmedia_rtcp_xr_rb_dlrr_item 
     121{ 
     122    pj_uint32_t          ssrc;          /**< receiver SSRC              */ 
     123    pj_uint32_t          lrr;           /**< last receiver report       */ 
     124    pj_uint32_t          dlrr;          /**< delay since last receiver 
     125                                             report                     */ 
     126} pjmedia_rtcp_xr_rb_dlrr_item; 
     127 
     128/** 
     129 * This type declares RTCP XR DLRR Report Block 
     130 */ 
     131typedef struct pjmedia_rtcp_xr_rb_dlrr 
     132{ 
     133    pjmedia_rtcp_xr_rb_header header;   /**< Block header.              */ 
     134    pjmedia_rtcp_xr_rb_dlrr_item item;  /**< Block contents,  
     135                                             variable length list       */ 
     136} pjmedia_rtcp_xr_rb_dlrr; 
     137 
     138/** 
     139 * This type declares RTCP XR Statistics Summary Report Block 
     140 */ 
     141typedef struct pjmedia_rtcp_xr_rb_stats 
     142{ 
     143    pjmedia_rtcp_xr_rb_header header;   /**< Block header.                   */ 
     144    pj_uint32_t          ssrc;          /**< Receiver SSRC                   */ 
     145    pj_uint16_t          begin_seq;     /**< Begin RTP sequence reported     */ 
     146    pj_uint16_t          end_seq;       /**< End RTP sequence reported       */ 
     147    pj_uint32_t          lost;          /**< Number of packet lost in this  
     148                                             interval  */ 
     149    pj_uint32_t          dup;           /**< Number of duplicated packet in  
     150                                             this interval */ 
     151    pj_uint32_t          jitter_min;    /**< Minimum jitter in this interval */ 
     152    pj_uint32_t          jitter_max;    /**< Maximum jitter in this interval */ 
     153    pj_uint32_t          jitter_mean;   /**< Average jitter in this interval */ 
     154    pj_uint32_t          jitter_dev;    /**< Jitter deviation in this  
     155                                             interval */ 
     156    pj_uint32_t          toh_min:8;     /**< Minimum ToH in this interval    */ 
     157    pj_uint32_t          toh_max:8;     /**< Maximum ToH in this interval    */ 
     158    pj_uint32_t          toh_mean:8;    /**< Average ToH in this interval    */ 
     159    pj_uint32_t          toh_dev:8;     /**< ToH deviation in this interval  */ 
     160} pjmedia_rtcp_xr_rb_stats; 
     161 
     162/** 
     163 * This type declares RTCP XR VoIP Metrics Report Block 
     164 */ 
     165typedef struct pjmedia_rtcp_xr_rb_voip_mtc 
     166{ 
     167    pjmedia_rtcp_xr_rb_header header;   /**< Block header.              */ 
     168    pj_uint32_t          ssrc;          /**< Receiver SSRC              */ 
     169    pj_uint8_t           loss_rate;     /**< Packet loss rate           */ 
     170    pj_uint8_t           discard_rate;  /**< Packet discarded rate      */ 
     171    pj_uint8_t           burst_den;     /**< Burst density              */ 
     172    pj_uint8_t           gap_den;       /**< Gap density                */ 
     173    pj_uint16_t          burst_dur;     /**< Burst duration             */ 
     174    pj_uint16_t          gap_dur;       /**< Gap duration               */ 
     175    pj_uint16_t          rnd_trip_delay;/**< Round trip delay           */ 
     176    pj_uint16_t          end_sys_delay; /**< End system delay           */ 
     177    pj_uint8_t           signal_lvl;    /**< Signal level               */ 
     178    pj_uint8_t           noise_lvl;     /**< Noise level                */ 
     179    pj_uint8_t           rerl;          /**< Residual Echo Return Loss  */ 
     180    pj_uint8_t           gmin;          /**< The gap threshold          */ 
     181    pj_uint8_t           r_factor;      /**< Voice quality metric carried 
     182                                             over this RTP session      */ 
     183    pj_uint8_t           ext_r_factor;  /**< Voice quality metric carried  
     184                                             outside of this RTP session*/ 
     185    pj_uint8_t           mos_lq;        /**< Mean Opinion Score for  
     186                                             Listening Quality          */ 
     187    pj_uint8_t           mos_cq;        /**< Mean Opinion Score for  
     188                                             Conversation Quality       */ 
     189    pj_uint8_t           rx_config;     /**< Receiver configuration     */ 
     190    pj_uint8_t           reserved2;     /**< Not used                   */ 
     191    pj_uint16_t          jb_nom;        /**< Current delay by jitter 
     192                                             buffer                     */ 
     193    pj_uint16_t          jb_max;        /**< Maximum delay by jitter 
     194                                             buffer                     */ 
     195    pj_uint16_t          jb_abs_max;    /**< Maximum possible delay by 
     196                                             jitter buffer              */ 
     197} pjmedia_rtcp_xr_rb_voip_mtc; 
     198 
     199/** 
     200 * This structure declares RTCP XR (Extended Report) packet. 
     201 */ 
     202typedef struct pjmedia_rtcp_xr_pkt 
     203{ 
     204    struct { 
     205#if defined(PJ_IS_BIG_ENDIAN) && PJ_IS_BIG_ENDIAN!=0 
     206        unsigned         version:2;     /**< packet type            */ 
     207        unsigned         p:1;           /**< padding flag           */ 
     208        unsigned         count:5;       /**< varies by payload type */ 
     209        unsigned         pt:8;          /**< payload type           */ 
     210#else 
     211        unsigned         count:5;       /**< varies by payload type */ 
     212        unsigned         p:1;           /**< padding flag           */ 
     213        unsigned         version:2;     /**< packet type            */ 
     214        unsigned         pt:8;          /**< payload type           */ 
     215#endif 
     216        unsigned         length:16;     /**< packet length          */ 
     217        pj_uint32_t      ssrc;          /**< SSRC identification    */ 
     218    } common; 
     219 
     220    pj_int8_t            buf[PJMEDIA_MAX_MTU];/**< Content buffer   */ 
     221} pjmedia_rtcp_xr_pkt; 
     222 
     223#pragma pack() 
     224 
     225 
     226/** 
     227 * This structure describes RTCP XR statitic. 
     228 */ 
     229typedef struct pjmedia_rtcp_xr_stream_stat 
     230{ 
     231    struct { 
     232        pj_uint32_t         begin_seq; 
     233        pj_uint32_t         end_seq; 
     234        unsigned            count;      /**< Number of packets.             */ 
     235 
     236        /** 
     237         * Flags represent whether the such report is valid/updated 
     238         */ 
     239        unsigned            l:1;        /**< Lost flag                      */ 
     240        unsigned            d:1;        /**< Duplicated flag                */ 
     241        unsigned            j:1;        /**< Jitter flag                    */ 
     242        unsigned            t:2;        /**< TTL or Hop Limit,  
     243                                             0=none, 1=TTL, 2=HL            */ 
     244 
     245        unsigned            lost;       /**< Number of packets lost         */ 
     246        unsigned            dup;        /**< Number of duplicated packets   */ 
     247         
     248        struct { 
     249            unsigned        min;        /**< Minimum jitter (in usec)       */ 
     250            unsigned        max;        /**< Maximum jitter (in usec)       */ 
     251            unsigned        dev;        /**< Jitter deviation (in usec)     */ 
     252            unsigned        mean;       /**< Average jitter (in usec)       */ 
     253            unsigned        count;      /**< Update count                   */ 
     254        } jitter;                       /**< Jitter history.                */ 
     255 
     256        struct { 
     257            unsigned        min;        /**< Minimum ToH                    */ 
     258            unsigned        max;        /**< Maximum ToH                    */ 
     259            unsigned        dev;        /**< ToH deviation                  */ 
     260            unsigned        mean;       /**< Average ToH                    */ 
     261            unsigned        count;      /**< Update count                   */ 
     262        } toh;                          /**< TTL of hop limit history.      */ 
     263    } stat_sum; 
     264 
     265    struct { 
     266        pj_uint8_t          loss_rate;      /**< Packet loss rate           */ 
     267        pj_uint8_t          discard_rate;   /**< Packet discarded rate      */ 
     268        pj_uint8_t          burst_den;      /**< Burst density              */ 
     269        pj_uint8_t          gap_den;        /**< Gap density                */ 
     270        pj_uint16_t         burst_dur;      /**< Burst duration             */ 
     271        pj_uint16_t         gap_dur;        /**< Gap duration               */ 
     272        pj_uint16_t         rnd_trip_delay; /**< Round trip delay           */ 
     273        pj_uint16_t         end_sys_delay;  /**< End system delay           */ 
     274        pj_uint8_t          signal_lvl;     /**< Signal level               */ 
     275        pj_uint8_t          noise_lvl;      /**< Noise level                */ 
     276        pj_uint8_t          rerl;           /**< Residual Echo Return Loss  */ 
     277        pj_uint8_t          gmin;           /**< The gap threshold          */ 
     278        pj_uint8_t          r_factor;       /**< Voice quality metric carried 
     279                                                 over this RTP session      */ 
     280        pj_uint8_t          ext_r_factor;   /**< Voice quality metric carried  
     281                                                 outside of this RTP session*/ 
     282        pj_uint8_t          mos_lq;         /**< Mean Opinion Score for  
     283                                                 Listening Quality          */ 
     284        pj_uint8_t          mos_cq;         /**< Mean Opinion Score for  
     285                                                 Conversation Quality       */ 
     286        pj_uint8_t          rx_config;      /**< Receiver configuration     */ 
     287        pj_uint16_t         jb_nom;         /**< Current delay by jitter 
     288                                                 buffer                     */ 
     289        pj_uint16_t         jb_max;         /**< Maximum delay by jitter 
     290                                                 buffer                     */ 
     291        pj_uint16_t         jb_abs_max;     /**< Maximum possible delay by 
     292                                                 jitter buffer              */ 
     293    } voip_mtc; 
     294 
     295} pjmedia_rtcp_xr_stream_stat; 
     296 
     297typedef struct pjmedia_rtcp_xr_stat 
     298{ 
     299    pjmedia_rtcp_xr_stream_stat  rx; 
     300    pjmedia_rtcp_xr_stream_stat  tx; 
     301 
     302    /* RTT calculated from receiver side */ 
     303    struct { 
     304        unsigned    min;            /**< Minimum round-trip delay (in usec) */ 
     305        unsigned    avg;            /**< Average round-trip delay (in usec) */ 
     306        unsigned    max;            /**< Maximum round-trip delay (in usec) */ 
     307        unsigned    last;           /**< Last round-trip delay (in usec)    */ 
     308        unsigned    update_cnt;     /**< Nb of times rtt is updated.        */ 
     309    } rtt;                          /**< Round trip delay history.          */ 
     310 
     311} pjmedia_rtcp_xr_stat; 
     312 
     313/** 
     314 * Forward declaration of RTCP session 
     315 */ 
     316struct pjmedia_rtcp_session; 
     317 
     318/** 
     319 * RTCP session is used to monitor the RTP session of one endpoint. There 
     320 * should only be one RTCP session for a bidirectional RTP streams. 
     321 */ 
     322struct pjmedia_rtcp_xr_session 
     323{ 
     324    char                   *name;       /**< Name identification.           */ 
     325    pjmedia_rtcp_xr_pkt     pkt;        /**< Cached RTCP XR packet.         */ 
     326 
     327    pj_uint32_t             rx_lrr;     /**< NTP ts in last RR received.    */ 
     328    pj_timestamp            rx_lrr_time;/**< Time when last RR is received. */ 
     329    pj_uint32_t             rx_last_rr; /**< # pkt received since last  
     330                                             sending RR time.               */ 
     331 
     332    pjmedia_rtcp_xr_stat    stat;       /**< RTCP XR statistics.            */ 
     333 
     334    /* The reference sequence number is an extended sequence number 
     335     * that serves as the basis for determining whether a new 16 bit 
     336     * sequence number comes earlier or later in the 32 bit sequence 
     337     * space. 
     338     */ 
     339    pj_uint32_t             src_ref_seq; 
     340    pj_bool_t               uninitialized_src_ref_seq; 
     341 
     342    /* This structure contains variables needed for calculating  
     343     * burst metrics. 
     344     */ 
     345    struct { 
     346        pj_uint32_t         pkt; 
     347        pj_uint32_t         lost; 
     348        pj_uint32_t         loss_count; 
     349        pj_uint32_t         discard_count; 
     350        pj_uint32_t         c11; 
     351        pj_uint32_t         c13; 
     352        pj_uint32_t         c14; 
     353        pj_uint32_t         c22; 
     354        pj_uint32_t         c23; 
     355        pj_uint32_t         c33; 
     356    } voip_mtc_stat; 
     357 
     358    unsigned ptime;                     /**< Packet time.                   */ 
     359    unsigned frames_per_packet;         /**< # frames per packet.           */ 
     360 
     361    struct pjmedia_rtcp_session *rtcp_session; 
     362                                        /**< Parent/RTCP session.           */ 
     363}; 
     364 
     365typedef struct pjmedia_rtcp_xr_session pjmedia_rtcp_xr_session; 
     366 
     367/** 
     368 * Build an RTCP XR packet which contains one or more RTCP XR report blocks. 
     369 * There are seven report types as defined in RFC 3611. 
     370 * 
     371 * @param session   The RTCP XR session. 
     372 * @param rpt_types Report types to be included in the packet, report types 
     373 *                  are defined in pjmedia_rtcp_xr_type, set this to zero 
     374 *                  will make this function build all reports appropriately. 
     375 * @param rtcp_pkt  Upon return, it will contain pointer to the RTCP XR packet. 
     376 * @param len       Upon return, it will indicate the size of the generated  
     377 *                  RTCP XR packet. 
     378 */ 
     379PJ_DECL(void) pjmedia_rtcp_build_rtcp_xr( pjmedia_rtcp_xr_session *session, 
     380                                          unsigned rpt_types, 
     381                                          void **rtcp_pkt, int *len); 
     382 
     383/** 
     384 * Call this function to manually update some info needed by RTCP XR to  
     385 * generate report which could not be populated directly when receiving 
     386 * RTP. 
     387 * 
     388 * @param session   The RTCP XR session. 
     389 * @param info      Info type to be updated, @see pjmedia_rtcp_xr_info. 
     390 * @param val       Value. 
     391 */ 
     392PJ_DECL(pj_status_t) pjmedia_rtcp_xr_update_info( 
     393                                          pjmedia_rtcp_xr_session *session, 
     394                                          unsigned info, 
     395                                          pj_int32_t val); 
     396 
     397/* 
     398 * Private APIs: 
     399 */ 
     400 
     401/** 
     402 * This function is called internally by RTCP session when RTCP XR is enabled 
     403 * to initialize the RTCP XR session. 
     404 * 
     405 * @param session   RTCP XR session. 
     406 * @param r_session RTCP session. 
     407 * @param gmin      Gmin value (defined in RFC 3611), set to 0 for default (16). 
     408 * @param ptime     Packet time. 
     409 * @param frames_per_packet 
     410                    Number of frames per packet. 
     411 */ 
     412void pjmedia_rtcp_xr_init( pjmedia_rtcp_xr_session *session,  
     413                           struct pjmedia_rtcp_session *r_session, 
     414                           pj_uint8_t gmin, 
     415                           unsigned frames_per_packet); 
     416 
     417/** 
     418 * This function is called internally by RTCP session to destroy  
     419 * the RTCP XR session. 
     420 * 
     421 * @param session   RTCP XR session. 
     422 */ 
     423void pjmedia_rtcp_xr_fini( pjmedia_rtcp_xr_session *session ); 
     424 
     425/** 
     426 * This function is called internally by RTCP session when it receives  
     427 * incoming RTCP XR packets. 
     428 * 
     429 * @param session   RTCP XR session. 
     430 * @param rtcp_pkt  The received RTCP XR packet. 
     431 * @param size      Size of the incoming packet. 
     432 */ 
     433void pjmedia_rtcp_xr_rx_rtcp_xr( pjmedia_rtcp_xr_session *session, 
     434                                 const void *rtcp_xr_pkt, 
     435                                 pj_size_t size); 
     436 
     437/** 
     438 * This function is called internally by RTCP session whenever an RTP packet 
     439 * is received or lost to let the RTCP XR session update its statistics. 
     440 * Data passed to this function is a result of analyzation by RTCP and the 
     441 * jitter buffer. Whenever some info is available, the value should be zero 
     442 * or more (no negative info), otherwise if info is not available the info 
     443 * should be -1 so no update will be done for this info in the RTCP XR session. 
     444 * 
     445 * @param session   RTCP XR session. 
     446 * @param seq       Sequence number of RTP packet. 
     447 * @param lost      Info if this packet is lost.  
     448 * @param dup       Info if this packet is a duplication.  
     449 * @param discarded Info if this packet is discarded  
     450 *                  (not because of duplication). 
     451 * @param jitter    Info jitter of this packet. 
     452 * @param toh       Info Time To Live or Hops Limit of this packet. 
     453 * @param toh_ipv4  Set PJ_TRUE if packet is transported over IPv4. 
     454 */ 
     455void pjmedia_rtcp_xr_rx_rtp( pjmedia_rtcp_xr_session *session, 
     456                             unsigned seq,  
     457                             int lost, 
     458                             int dup, 
     459                             int discarded, 
     460                             int jitter, 
     461                             int toh, pj_bool_t toh_ipv4); 
     462 
     463/** 
     464 * This function is called internally by RTCP session whenever an RTP  
     465 * packet is sent to let the RTCP XR session do its internal calculations. 
     466 * 
     467 * @param session   RTCP XR session. 
     468 * @param ptsize    Size of RTP payload being sent. 
     469 */ 
     470void pjmedia_rtcp_xr_tx_rtp( pjmedia_rtcp_xr_session *session,  
     471                             unsigned ptsize ); 
     472 
     473/** 
     474 * @} 
     475 */ 
     476 
     477PJ_END_DECL 
     478 
     479 
     480#endif  /* __PJMEDIA_RTCP_XR_H__ */ 
  • pjmedia/include/pjmedia/jbuf.h

     
    7676    unsigned    min_prefetch;       /**< Minimum allowed prefetch, in frms. */ 
    7777    unsigned    max_prefetch;       /**< Maximum allowed prefetch, in frms. */ 
    7878    unsigned    size;               /**< Current buffer size, in frames.    */ 
     79    unsigned    max_size;           /**< Maximum size ever.                 */ 
    7980}; 
    8081 
    8182 
     
    184185 */ 
    185186PJ_DECL(pj_status_t) pjmedia_jbuf_reset(pjmedia_jbuf *jb); 
    186187 
    187  
    188188/** 
    189189 * Put a frame to the jitter buffer. If the frame can be accepted (based 
    190190 * on the sequence number), the jitter buffer will copy the frame and put 
     
    198198 *                      buffer. 
    199199 * @param size          The frame size. 
    200200 * @param frame_seq     The frame sequence number. 
    201  * 
    202  * @return              PJ_SUCCESS on success. 
    203201 */ 
    204202PJ_DECL(void) pjmedia_jbuf_put_frame( pjmedia_jbuf *jb,  
    205203                                      const void *frame,  
     
    207205                                      int frame_seq); 
    208206 
    209207/** 
     208 * Put a frame to the jitter buffer. If the frame can be accepted (based 
     209 * on the sequence number), the jitter buffer will copy the frame and put 
     210 * it in the appropriate position in the buffer. 
     211 * 
     212 * Application MUST manage it's own synchronization when multiple threads 
     213 * are accessing the jitter buffer at the same time. 
     214 * 
     215 * @param jb            The jitter buffer. 
     216 * @param frame         Pointer to frame buffer to be stored in the jitter 
     217 *                      buffer. 
     218 * @param size          The frame size. 
     219 * @param frame_seq     The frame sequence number. 
     220 * @param discarded     Flag whether the frame is discarded by jitter buffer. 
     221 */ 
     222PJ_DECL(void) pjmedia_jbuf_put_frame2( pjmedia_jbuf *jb,  
     223                                       const void *frame,  
     224                                       pj_size_t size,  
     225                                       int frame_seq, 
     226                                       pj_bool_t *discarded); 
     227 
     228/** 
    210229 * Get a frame from the jitter buffer. The jitter buffer will return the 
    211230 * oldest frame from it's buffer, when it is available. 
    212231 * 
  • pjmedia/include/pjmedia/rtcp.h

     
    2525 */ 
    2626 
    2727#include <pjmedia/types.h> 
     28#include <pjmedia/rtcp_xr.h> 
    2829#include <pjmedia/rtp.h> 
    2930 
    3031 
     
    246247  typedef pj_uint32_t PJMEDIA_AVG_JITTER_TYPE; 
    247248#endif 
    248249 
    249  
    250250/** 
    251251 * RTCP session is used to monitor the RTP session of one endpoint. There 
    252252 * should only be one RTCP session for a bidirectional RTP streams. 
     
    254254struct pjmedia_rtcp_session 
    255255{ 
    256256    char                   *name;       /**< Name identification.           */ 
    257     pjmedia_rtcp_sr_pkt     rtcp_sr_pkt;/**< Cached RTCP packet.            */ 
     257    pjmedia_rtcp_sr_pkt     rtcp_sr_pkt;/**< Cached RTCP SR packet.         */ 
    258258    pjmedia_rtcp_rr_pkt     rtcp_rr_pkt;/**< Cached RTCP RR packet.         */ 
    259259     
    260260    pjmedia_rtp_seq_session seq_ctrl;   /**< RTCP sequence number control.  */ 
     
    281281     * from being rounded-down to nearest integer. 
    282282     */ 
    283283    PJMEDIA_AVG_JITTER_TYPE avg_jitter; /**< Average RX jitter.             */ 
     284 
     285#if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0) 
     286    /** 
     287     * Specify whether RTCP XR processing is enabled on this session. 
     288     */ 
     289    pj_bool_t               xr_enabled; 
     290 
     291    /** 
     292     * RTCP XR session, only valid if RTCP XR processing is enabled 
     293     * on this session. 
     294     */ 
     295    pjmedia_rtcp_xr_session xr_session; 
     296#endif 
    284297}; 
    285298 
    286299/** 
     
    342355 
    343356 
    344357/** 
     358 * Call this function everytime an RTP packet is received to let the RTCP 
     359 * session do its internal calculations. 
     360 * 
     361 * @param session   The session. 
     362 * @param seq       The RTP packet sequence number, in host byte order. 
     363 * @param ts        The RTP packet timestamp, in host byte order. 
     364 * @param payload   Size of the payload. 
     365 * @param discarded Flag to specify whether the packet is discarded. 
     366 */ 
     367PJ_DECL(void) pjmedia_rtcp_rx_rtp2(pjmedia_rtcp_session *session,  
     368                                   unsigned seq,  
     369                                   unsigned ts, 
     370                                   unsigned payload, 
     371                                   pj_bool_t discarded); 
     372 
     373 
     374/** 
    345375 * Call this function everytime an RTP packet is sent to let the RTCP session 
    346376 * do its internal calculations. 
    347377 * 
     
    385415 
    386416 
    387417/** 
     418 * Call this function if RTCP XR needs to be enabled/disabled in the  
     419 * RTCP session. 
     420 * 
     421 * @param session   The RTCP session. 
     422 * @param enable    Enable/disable RTCP XR. 
     423 * 
     424 * @return          PJ_SUCCESS on success. 
     425 */ 
     426PJ_DECL(pj_status_t) pjmedia_rtcp_enable_xr( pjmedia_rtcp_session *session,  
     427                                             pj_bool_t enable); 
     428 
     429 
     430/** 
    388431 * @} 
    389432 */ 
    390433 
  • pjmedia/src/pjmedia/rtcp_xr.c

     
     1/* $Id$ */ 
     2/*  
     3 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org> 
     4 * 
     5 * This program is free software; you can redistribute it and/or modify 
     6 * it under the terms of the GNU General Public License as published by 
     7 * the Free Software Foundation; either version 2 of the License, or 
     8 * (at your option) any later version. 
     9 * 
     10 * This program is distributed in the hope that it will be useful, 
     11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 
     12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
     13 * GNU General Public License for more details. 
     14 * 
     15 * You should have received a copy of the GNU General Public License 
     16 * along with this program; if not, write to the Free Software 
     17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  
     18 */ 
     19 
     20#include <pjmedia/rtcp_xr.h> 
     21#include <pjmedia/errno.h> 
     22#include <pjmedia/rtcp.h> 
     23#include <pj/assert.h> 
     24#include <pj/log.h> 
     25#include <pj/os.h> 
     26#include <pj/sock.h> 
     27#include <pj/string.h> 
     28 
     29#if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0) 
     30 
     31#define THIS_FILE "rtcp_xr.c" 
     32 
     33 
     34#if PJ_HAS_HIGH_RES_TIMER==0 
     35#   error "High resolution timer needs to be enabled" 
     36#endif 
     37 
     38 
     39/* RTCP XR payload type */ 
     40#define RTCP_XR             207 
     41 
     42/* RTCP XR block types */ 
     43#define BT_LOSS_RLE         1 
     44#define BT_DUP_RLE          2 
     45#define BT_RCPT_TIMES       3 
     46#define BT_RR_TIME          4 
     47#define BT_DLRR             5 
     48#define BT_STATS            6 
     49#define BT_VOIP_METRICS     7 
     50 
     51 
     52#define DEFAULT_GMIN        16 
     53 
     54 
     55#if 0 
     56#   define TRACE_(x)    PJ_LOG(3,x) 
     57#else 
     58#   define TRACE_(x)    ; 
     59#endif 
     60 
     61/* Integer square root for calculating standard deviation */ 
     62static pj_uint32_t my_isqrt(pj_uint32_t i) 
     63{ 
     64    pj_uint32_t res = 1, prev; 
     65     
     66    /* Rough guess */ 
     67    prev = i >> 2; 
     68    while (prev) { 
     69        prev >>= 2; 
     70        res <<= 1; 
     71    } 
     72 
     73    /* Babilonian method */ 
     74    do { 
     75        prev = res; 
     76        res = (prev + i/prev) >> 1; 
     77    } while ((prev+res)>>1 != res); 
     78 
     79    return res; 
     80} 
     81 
     82void pjmedia_rtcp_xr_init( pjmedia_rtcp_xr_session *session,  
     83                           struct pjmedia_rtcp_session *parent_session, 
     84                           pj_uint8_t gmin, 
     85                           unsigned frames_per_packet) 
     86{ 
     87    pj_bzero(session, sizeof(pjmedia_rtcp_xr_session)); 
     88 
     89    session->rtcp_session = parent_session; 
     90    pj_memcpy(&session->pkt.common, &session->rtcp_session->rtcp_sr_pkt.common, 
     91              sizeof(pjmedia_rtcp_common)); 
     92    session->pkt.common.pt = RTCP_XR; 
     93 
     94    /* Init config */ 
     95    session->stat.tx.voip_mtc.gmin = (pj_uint8_t)(gmin? gmin : DEFAULT_GMIN); 
     96    session->ptime = session->rtcp_session->pkt_size * 1000 /  
     97                     session->rtcp_session->clock_rate; 
     98    session->frames_per_packet = frames_per_packet; 
     99 
     100    /* Init Statistics Summary fields which have non-zero default */ 
     101    session->stat.tx.stat_sum.jitter.min = (unsigned) -1; 
     102    session->stat.tx.stat_sum.toh.min = (unsigned) -1; 
     103 
     104    /* Init VoIP Metrics fields which have non-zero default */ 
     105    session->stat.tx.voip_mtc.signal_lvl = 127; 
     106    session->stat.tx.voip_mtc.noise_lvl = 127; 
     107    session->stat.tx.voip_mtc.rerl = 127; 
     108    session->stat.tx.voip_mtc.r_factor = 127; 
     109    session->stat.tx.voip_mtc.ext_r_factor = 127; 
     110    session->stat.tx.voip_mtc.mos_lq = 127; 
     111    session->stat.tx.voip_mtc.mos_cq = 127; 
     112} 
     113 
     114void pjmedia_rtcp_xr_fini(pjmedia_rtcp_xr_session *session) 
     115{ 
     116    PJ_UNUSED_ARG(session); 
     117} 
     118 
     119PJ_DEF(void) pjmedia_rtcp_build_rtcp_xr( pjmedia_rtcp_xr_session *sess,  
     120                                         unsigned rpt_types, 
     121                                         void **rtcp_pkt, int *len) 
     122{ 
     123    pj_uint16_t size = 0; 
     124 
     125    /* Receiver Reference Time Report Block */ 
     126    /* Build this block if we have received packets since last build */ 
     127    if ((rpt_types == 0 || (rpt_types & PJMEDIA_RTCP_XR_RR_TIME)) && 
     128        sess->rx_last_rr != sess->rtcp_session->stat.rx.pkt) 
     129    { 
     130        pjmedia_rtcp_xr_rb_rr_time *r; 
     131        pjmedia_rtcp_ntp_rec ntp; 
     132 
     133        r = (pjmedia_rtcp_xr_rb_rr_time*) &sess->pkt.buf[size]; 
     134        pj_bzero(r, sizeof(pjmedia_rtcp_xr_rb_rr_time)); 
     135 
     136        /* Init block header */ 
     137        r->header.bt = BT_RR_TIME; 
     138        r->header.specific = 0; 
     139        r->header.length = pj_htons(2); 
     140 
     141        /* Generate block contents */ 
     142        pjmedia_rtcp_get_ntp_time(sess->rtcp_session, &ntp); 
     143        r->ntp_sec = pj_htonl(ntp.hi); 
     144        r->ntp_frac = pj_htonl(ntp.lo); 
     145 
     146        /* Finally */ 
     147        size += sizeof(pjmedia_rtcp_xr_rb_rr_time); 
     148        sess->rx_last_rr = sess->rtcp_session->stat.rx.pkt; 
     149    } 
     150 
     151    /* DLRR Report Block */ 
     152    /* Build this block if we have received RR NTP (rx_lrr) before */ 
     153    if ((rpt_types == 0 || (rpt_types & PJMEDIA_RTCP_XR_DLRR)) &&  
     154        sess->rx_lrr) 
     155    { 
     156        pjmedia_rtcp_xr_rb_dlrr *r; 
     157        pjmedia_rtcp_xr_rb_dlrr_item *dlrr_item; 
     158        pj_timestamp ts; 
     159 
     160        r = (pjmedia_rtcp_xr_rb_dlrr*) &sess->pkt.buf[size]; 
     161        pj_bzero(r, sizeof(pjmedia_rtcp_xr_rb_dlrr)); 
     162 
     163        /* Init block header */ 
     164        r->header.bt = BT_DLRR; 
     165        r->header.specific = 0; 
     166        r->header.length = pj_htons(sizeof(pjmedia_rtcp_xr_rb_dlrr)/4 - 1); 
     167 
     168        /* Generate block contents */ 
     169        dlrr_item = &r->item; 
     170        dlrr_item->ssrc = pj_htonl(sess->rtcp_session->peer_ssrc); 
     171        dlrr_item->lrr = pj_htonl(sess->rx_lrr); 
     172 
     173        /* Calculate DLRR */ 
     174        if (sess->rx_lrr != 0) { 
     175            pj_get_timestamp(&ts); 
     176            ts.u64 -= sess->rx_lrr_time.u64; 
     177         
     178            /* Convert DLRR time to 1/65536 seconds resolution */ 
     179            ts.u64 = (ts.u64 << 16) / sess->rtcp_session->ts_freq.u64; 
     180            dlrr_item->dlrr = pj_htonl(ts.u32.lo); 
     181        } else { 
     182            dlrr_item->dlrr = 0; 
     183        } 
     184 
     185        /* Finally */ 
     186        size += sizeof(pjmedia_rtcp_xr_rb_dlrr); 
     187    } 
     188 
     189    /* Statistics Summary Block */ 
     190    /* Build this block if we have received packets since last build */ 
     191    if ((rpt_types == 0 || (rpt_types & PJMEDIA_RTCP_XR_STATS)) && 
     192        sess->stat.tx.stat_sum.count > 0) 
     193    { 
     194        pjmedia_rtcp_xr_rb_stats *r; 
     195        pj_uint8_t specific = 0; 
     196 
     197        r = (pjmedia_rtcp_xr_rb_stats*) &sess->pkt.buf[size]; 
     198        pj_bzero(r, sizeof(pjmedia_rtcp_xr_rb_stats)); 
     199 
     200        /* Init block header */ 
     201        specific |= sess->stat.tx.stat_sum.l ? (1 << 7) : 0; 
     202        specific |= sess->stat.tx.stat_sum.d ? (1 << 6) : 0; 
     203        specific |= sess->stat.tx.stat_sum.j ? (1 << 5) : 0; 
     204        specific |= (sess->stat.tx.stat_sum.t & 3) << 3; 
     205        r->header.bt = BT_STATS; 
     206        r->header.specific = specific; 
     207        r->header.length = pj_htons(9); 
     208 
     209        /* Generate block contents */ 
     210        r->ssrc = pj_htonl(sess->rtcp_session->peer_ssrc); 
     211        r->begin_seq = pj_htons((pj_uint16_t) 
     212                                (sess->stat.tx.stat_sum.begin_seq & 0xFFFF)); 
     213        r->end_seq = pj_htons((pj_uint16_t) 
     214                              (sess->stat.tx.stat_sum.end_seq & 0xFFFF)); 
     215        if (sess->stat.tx.stat_sum.l) { 
     216            r->lost = pj_htonl(sess->stat.tx.stat_sum.lost); 
     217        } 
     218        if (sess->stat.tx.stat_sum.d) { 
     219            r->dup = pj_htonl(sess->stat.tx.stat_sum.dup); 
     220        } 
     221        if (sess->stat.tx.stat_sum.j) { 
     222            r->jitter_min = pj_htonl(sess->stat.tx.stat_sum.jitter.min); 
     223            r->jitter_max = pj_htonl(sess->stat.tx.stat_sum.jitter.max); 
     224            r->jitter_mean = pj_htonl(sess->stat.tx.stat_sum.jitter.mean); 
     225            sess->stat.tx.stat_sum.jitter.dev =  
     226                                my_isqrt(sess->stat.tx.stat_sum.jitter.dev); 
     227            r->jitter_dev = pj_htonl(sess->stat.tx.stat_sum.jitter.dev); 
     228        } 
     229        if (sess->stat.tx.stat_sum.t) { 
     230            r->toh_min = sess->stat.tx.stat_sum.toh.min; 
     231            r->toh_max = sess->stat.tx.stat_sum.toh.max; 
     232            r->toh_mean = sess->stat.tx.stat_sum.toh.mean; 
     233            sess->stat.tx.stat_sum.toh.dev =  
     234                                my_isqrt(sess->stat.tx.stat_sum.toh.dev); 
     235            r->toh_dev = sess->stat.tx.stat_sum.toh.dev; 
     236        } 
     237 
     238        /* Reset TX statistics summary each time built */ 
     239        pj_bzero(&sess->stat.tx.stat_sum, sizeof(sess->stat.tx.stat_sum)); 
     240        sess->stat.tx.stat_sum.jitter.min = (unsigned) -1; 
     241        sess->stat.tx.stat_sum.toh.min = (unsigned) -1; 
     242 
     243        /* Finally */ 
     244        size += sizeof(pjmedia_rtcp_xr_rb_stats); 
     245    } 
     246 
     247    /* Voip Metrics Block */ 
     248    /* Build this block if we have received packets */ 
     249    if ((rpt_types == 0 || (rpt_types & PJMEDIA_RTCP_XR_VOIP_METRICS)) && 
     250        sess->rtcp_session->stat.rx.pkt) 
     251    { 
     252        pjmedia_rtcp_xr_rb_voip_mtc *r; 
     253        pj_uint32_t c11; 
     254        pj_uint32_t c13; 
     255        pj_uint32_t c14; 
     256        pj_uint32_t c22; 
     257        pj_uint32_t c23; 
     258        pj_uint32_t c31; 
     259        pj_uint32_t c32; 
     260        pj_uint32_t c33; 
     261        pj_uint32_t ctotal, p32, p23, m; 
     262 
     263        r = (pjmedia_rtcp_xr_rb_voip_mtc*) &sess->pkt.buf[size]; 
     264        pj_bzero(r, sizeof(pjmedia_rtcp_xr_rb_voip_mtc)); 
     265 
     266        /* Init block header */ 
     267        r->header.bt = BT_VOIP_METRICS; 
     268        r->header.specific = 0; 
     269        r->header.length = pj_htons(8); 
     270 
     271        /* Calculate additional transition counts. */ 
     272        c11 = sess->voip_mtc_stat.c11; 
     273        c13 = sess->voip_mtc_stat.c13; 
     274        c14 = sess->voip_mtc_stat.c14; 
     275        c22 = sess->voip_mtc_stat.c22; 
     276        c23 = sess->voip_mtc_stat.c23; 
     277        c33 = sess->voip_mtc_stat.c33; 
     278        c31 = c13; 
     279        c32 = c23; 
     280        ctotal = c11 + c14 + c13 + c22 + c23 + c31 + c32 + c33; 
     281        m = sess->ptime * sess->frames_per_packet; 
     282 
     283        /* Calculate burst and densities. */ 
     284        if (ctotal) { 
     285            p32 = c32 / (c31 + c32 + c33); 
     286            if((c22 + c23) < 1) { 
     287                p23 = 1; 
     288            } else { 
     289                p23 = 1 - c22/(c22 + c23); 
     290            } 
     291            sess->stat.tx.voip_mtc.burst_den = (pj_uint8_t)(256*p23/(p23 + p32)); 
     292            sess->stat.tx.voip_mtc.gap_den = (pj_uint8_t)(256*c14/(c11 + c14)); 
     293 
     294            /* Calculate burst and gap durations in ms */ 
     295            sess->stat.tx.voip_mtc.gap_dur = (pj_uint16_t)((c11+c14+c13)*m/c13); 
     296            sess->stat.tx.voip_mtc.burst_dur = (pj_uint16_t)(ctotal*m/c13 -  
     297                                               sess->stat.tx.voip_mtc.gap_dur); 
     298        } else { 
     299            /* No burst occurred yet until this time? 
     300             * Just report full gap. 
     301             */ 
     302            ctotal = sess->rtcp_session->stat.rx.pkt; 
     303 
     304            sess->stat.tx.voip_mtc.burst_den = 0; 
     305            sess->stat.tx.voip_mtc.gap_den = (pj_uint8_t)(256 *  
     306                                        (sess->voip_mtc_stat.loss_count +  
     307                                        sess->voip_mtc_stat.discard_count) /  
     308                                        ctotal); 
     309 
     310            /* Calculate burst and gap durations in ms */ 
     311            sess->stat.tx.voip_mtc.gap_dur = (pj_uint16_t)((m*ctotal) < 0xFFFF? 
     312                                             (m*ctotal) : 0xFFFF); 
     313            sess->stat.tx.voip_mtc.burst_dur = 0; 
     314        } 
     315 
     316        /* Calculate loss and discard rates */ 
     317        sess->stat.tx.voip_mtc.loss_rate = (pj_uint8_t) 
     318                             (256 * sess->voip_mtc_stat.loss_count / ctotal); 
     319        sess->stat.tx.voip_mtc.discard_rate = (pj_uint8_t) 
     320                             (256 * sess->voip_mtc_stat.discard_count / ctotal); 
     321 
     322        /* Set round trip delay (in ms) to RTT calculated after receiving 
     323         * DLRR or DLSR. 
     324         */ 
     325        if (sess->stat.rtt.last) 
     326            sess->stat.tx.voip_mtc.rnd_trip_delay = (pj_uint16_t) 
     327                                    (sess->stat.rtt.last / 1000); 
     328        else if (sess->rtcp_session->stat.rtt.last) 
     329            sess->stat.tx.voip_mtc.rnd_trip_delay = (pj_uint16_t) 
     330                                    (sess->rtcp_session->stat.rtt.last / 1000); 
     331         
     332        /* End system delay estimation = RTT/2 + current jitter buffer size + 
     333         *                               EXTRA 
     334         * EXTRA will cover additional delay introduced by other components of 
     335         * audio engine, e.g: sound device, codec, AEC, PLC, WSOLA. 
     336         * Since it is difficult to get the exact value of EXTRA, estimation 
     337         * is taken to be totally around 50 ms. 
     338         */ 
     339        sess->stat.tx.voip_mtc.end_sys_delay = (pj_uint16_t) 
     340                                (sess->stat.tx.voip_mtc.rnd_trip_delay / 2 + 
     341                                 sess->stat.tx.voip_mtc.jb_nom + 50); 
     342 
     343        /* Generate block contents */ 
     344        r->ssrc             = pj_htonl(sess->rtcp_session->peer_ssrc); 
     345        r->loss_rate        = sess->stat.tx.voip_mtc.loss_rate; 
     346        r->discard_rate     = sess->stat.tx.voip_mtc.discard_rate; 
     347        r->burst_den        = sess->stat.tx.voip_mtc.burst_den; 
     348        r->gap_den          = sess->stat.tx.voip_mtc.gap_den; 
     349        r->burst_dur        = pj_htons(sess->stat.tx.voip_mtc.burst_dur); 
     350        r->gap_dur          = pj_htons(sess->stat.tx.voip_mtc.gap_dur); 
     351        r->rnd_trip_delay   = pj_htons(sess->stat.tx.voip_mtc.rnd_trip_delay); 
     352        r->end_sys_delay    = pj_htons(sess->stat.tx.voip_mtc.end_sys_delay); 
     353        r->signal_lvl       = sess->stat.tx.voip_mtc.signal_lvl; 
     354        r->noise_lvl        = sess->stat.tx.voip_mtc.noise_lvl; 
     355        r->rerl             = sess->stat.tx.voip_mtc.rerl; 
     356        r->gmin             = sess->stat.tx.voip_mtc.gmin; 
     357        r->r_factor         = sess->stat.tx.voip_mtc.r_factor; 
     358        r->ext_r_factor     = sess->stat.tx.voip_mtc.ext_r_factor; 
     359        r->mos_lq           = sess->stat.tx.voip_mtc.mos_lq; 
     360        r->mos_cq           = sess->stat.tx.voip_mtc.mos_cq; 
     361        r->rx_config        = sess->stat.tx.voip_mtc.rx_config; 
     362        r->jb_nom           = pj_htons(sess->stat.tx.voip_mtc.jb_nom); 
     363        r->jb_max           = pj_htons(sess->stat.tx.voip_mtc.jb_max); 
     364        r->jb_abs_max       = pj_htons(sess->stat.tx.voip_mtc.jb_abs_max); 
     365 
     366        /* Finally */ 
     367        size += sizeof(pjmedia_rtcp_xr_rb_voip_mtc); 
     368    } 
     369 
     370    /* Add RTCP XR header size */ 
     371    size += sizeof(sess->pkt.common); 
     372 
     373    /* Set RTCP XR header 'length' to packet size in 32-bit unit minus one */ 
     374    sess->pkt.common.length = pj_htons((pj_uint16_t)(size/4 - 1)); 
     375 
     376    /* Set the return values */ 
     377    *rtcp_pkt = (void*) &sess->pkt; 
     378    *len = size; 
     379} 
     380 
     381 
     382void pjmedia_rtcp_xr_rx_rtcp_xr( pjmedia_rtcp_xr_session *sess, 
     383                                 const void *pkt, 
     384                                 pj_size_t size) 
     385{ 
     386    const pjmedia_rtcp_xr_pkt         *rtcp_xr = (pjmedia_rtcp_xr_pkt*) pkt; 
     387    const pjmedia_rtcp_xr_rb_rr_time  *rb_rr_time = NULL; 
     388    const pjmedia_rtcp_xr_rb_dlrr     *rb_dlrr = NULL; 
     389    const pjmedia_rtcp_xr_rb_stats    *rb_stats = NULL; 
     390    const pjmedia_rtcp_xr_rb_voip_mtc *rb_voip_mtc = NULL; 
     391    const pjmedia_rtcp_xr_rb_header   *rb_hdr = (pjmedia_rtcp_xr_rb_header*)  
     392                                                rtcp_xr->buf; 
     393    unsigned pkt_len, rb_len; 
     394 
     395    if (rtcp_xr->common.pt != RTCP_XR) 
     396        return; 
     397 
     398    pkt_len = pj_ntohs((pj_uint16_t)rtcp_xr->common.length); 
     399 
     400    pj_assert((pkt_len + 1) <= (size / 4)); 
     401 
     402    /* Parse report rpt_types */ 
     403    while ((pj_int32_t*)rb_hdr < (pj_int32_t*)pkt + pkt_len) 
     404    {    
     405        rb_len = pj_ntohs((pj_uint16_t)rb_hdr->length); 
     406 
     407        /* Just skip any block with length == 0 (no report content) */ 
     408        if (rb_len) { 
     409            switch (rb_hdr->bt) { 
     410                case BT_RR_TIME: 
     411                    rb_rr_time = (pjmedia_rtcp_xr_rb_rr_time*) rb_hdr; 
     412                    break; 
     413                case BT_DLRR: 
     414                    rb_dlrr = (pjmedia_rtcp_xr_rb_dlrr*) rb_hdr; 
     415                    break; 
     416                case BT_STATS: 
     417                    rb_stats = (pjmedia_rtcp_xr_rb_stats*) rb_hdr; 
     418                    break; 
     419                case BT_VOIP_METRICS: 
     420                    rb_voip_mtc = (pjmedia_rtcp_xr_rb_voip_mtc*) rb_hdr; 
     421                    break; 
     422                default: 
     423                    break; 
     424            } 
     425        } 
     426        rb_hdr = (pjmedia_rtcp_xr_rb_header*) 
     427                 ((pj_int32_t*)rb_hdr + rb_len + 1); 
     428    } 
     429 
     430    /* Receiving RR Time */ 
     431    if (rb_rr_time) { 
     432        /* Save LRR from NTP timestamp of the RR time block report */ 
     433        sess->rx_lrr = ((pj_ntohl(rb_rr_time->ntp_sec) & 0x0000FFFF) << 16) |  
     434                       ((pj_ntohl(rb_rr_time->ntp_frac) >> 16) & 0xFFFF); 
     435 
     436        /* Calculate RR arrival time for DLRR */ 
     437        pj_get_timestamp(&sess->rx_lrr_time); 
     438 
     439        TRACE_((sess->name, "Rx RTCP SR: ntp_ts=%p", sess->rx_lrr, 
     440               (pj_uint32_t)(sess->rx_lrr_time.u64*65536/ 
     441                             sess->rtcp_session->ts_freq.u64))); 
     442    } 
     443 
     444    /* Receiving DLRR */ 
     445    if (rb_dlrr) { 
     446        pj_uint32_t lrr, now, dlrr; 
     447        pj_uint64_t eedelay; 
     448        pjmedia_rtcp_ntp_rec ntp; 
     449 
     450        /* LRR is the middle 32bit of NTP. It has 1/65536 second  
     451         * resolution  
     452         */ 
     453        lrr = pj_ntohl(rb_dlrr->item.lrr); 
     454 
     455        /* DLRR is delay since LRR, also in 1/65536 resolution */ 
     456        dlrr = pj_ntohl(rb_dlrr->item.dlrr); 
     457 
     458        /* Get current time, and convert to 1/65536 resolution */ 
     459        pjmedia_rtcp_get_ntp_time(sess->rtcp_session, &ntp); 
     460        now = ((ntp.hi & 0xFFFF) << 16) + (ntp.lo >> 16); 
     461 
     462        /* End-to-end delay is (now-lrr-dlrr) */ 
     463        eedelay = now - lrr - dlrr; 
     464 
     465        /* Convert end to end delay to usec (keeping the calculation in 
     466         * 64bit space):: 
     467         *   sess->ee_delay = (eedelay * 1000) / 65536; 
     468         */ 
     469        if (eedelay < 4294) { 
     470            eedelay = (eedelay * 1000000) >> 16; 
     471        } else { 
     472            eedelay = (eedelay * 1000) >> 16; 
     473            eedelay *= 1000; 
     474        } 
     475 
     476        TRACE_((sess->name, "Rx RTCP XR DLRR: lrr=%p, dlrr=%p (%d:%03dms), " 
     477                           "now=%p, rtt=%p", 
     478                lrr, dlrr, dlrr/65536, (dlrr%65536)*1000/65536, 
     479                now, (pj_uint32_t)eedelay)); 
     480         
     481        /* Only save calculation if "now" is greater than lrr, or 
     482         * otherwise rtt will be invalid  
     483         */ 
     484        if (now-dlrr >= lrr) { 
     485            unsigned rtt = (pj_uint32_t)eedelay; 
     486             
     487            /* Check that eedelay value really makes sense.  
     488             * We allow up to 30 seconds RTT! 
     489             */ 
     490            if (eedelay <= 30 * 1000 * 1000UL) { 
     491                if (sess->stat.rtt.update_cnt == 0) 
     492                    sess->stat.rtt.min = rtt; 
     493 
     494                /* "Normalize" rtt value that is exceptionally high. 
     495                 * For such values, "normalize" the rtt to be three times 
     496                 * the average value. 
     497                 */ 
     498                if (rtt>(sess->stat.rtt.avg*3) && sess->stat.rtt.update_cnt!=0) 
     499                { 
     500                    unsigned orig_rtt = rtt; 
     501                    rtt = sess->stat.rtt.avg*3; 
     502                    PJ_LOG(5,(sess->name,  
     503                              "RTT value %d usec is normalized to %d usec", 
     504                              orig_rtt, rtt)); 
     505                } 
     506         
     507                TRACE_((sess->name, "RTCP RTT is set to %d usec", rtt)); 
     508 
     509                if (rtt < sess->stat.rtt.min && rtt) 
     510                    sess->stat.rtt.min = rtt; 
     511                if (rtt > sess->stat.rtt.max) 
     512                    sess->stat.rtt.max = rtt; 
     513 
     514                sess->stat.rtt.avg =  
     515                    (sess->stat.rtt.avg * sess->stat.rtt.update_cnt + rtt) /  
     516                    (sess->stat.rtt.update_cnt + 1); 
     517 
     518                sess->stat.rtt.last = rtt; 
     519                sess->stat.rtt.update_cnt++; 
     520            } 
     521        } else { 
     522            PJ_LOG(5, (sess->name, "Internal RTCP NTP clock skew detected: " 
     523                                   "lrr=%p, now=%p, dlrr=%p (%d:%03dms), " 
     524                                   "diff=%d", 
     525                                   lrr, now, dlrr, dlrr/65536, 
     526                                   (dlrr%65536)*1000/65536, 
     527                                   dlrr-(now-lrr))); 
     528        } 
     529    } 
     530 
     531    /* Receiving Statistics Summary */ 
     532    if (rb_stats) { 
     533        pj_uint8_t flags = rb_stats->header.specific; 
     534 
     535        pj_bzero(&sess->stat.rx.stat_sum, sizeof(sess->stat.rx.stat_sum)); 
     536 
     537        /* Range of packets sequence reported in this blocks */ 
     538        sess->stat.rx.stat_sum.begin_seq = pj_ntohs(rb_stats->begin_seq); 
     539        sess->stat.rx.stat_sum.end_seq   = pj_ntohs(rb_stats->end_seq); 
     540 
     541        /* Get flags of valid fields */ 
     542        sess->stat.rx.stat_sum.l = (flags & (1 << 7)) != 0; 
     543        sess->stat.rx.stat_sum.d = (flags & (1 << 6)) != 0; 
     544        sess->stat.rx.stat_sum.j = (flags & (1 << 5)) != 0; 
     545        sess->stat.rx.stat_sum.t = (flags & (3 << 3)) != 0; 
     546 
     547        /* Fetch the reports info */ 
     548        if (sess->stat.rx.stat_sum.l) { 
     549            sess->stat.rx.stat_sum.lost = pj_ntohl(rb_stats->lost); 
     550        } 
     551 
     552        if (sess->stat.rx.stat_sum.d) { 
     553            sess->stat.rx.stat_sum.dup = pj_ntohl(rb_stats->dup); 
     554        } 
     555 
     556        if (sess->stat.rx.stat_sum.j) { 
     557            sess->stat.rx.stat_sum.jitter.min = pj_ntohl(rb_stats->jitter_min); 
     558            sess->stat.rx.stat_sum.jitter.max = pj_ntohl(rb_stats->jitter_max); 
     559            sess->stat.rx.stat_sum.jitter.mean = pj_ntohl(rb_stats->jitter_mean); 
     560            sess->stat.rx.stat_sum.jitter.dev = pj_ntohl(rb_stats->jitter_dev); 
     561        } 
     562 
     563        if (sess->stat.rx.stat_sum.t) { 
     564            sess->stat.rx.stat_sum.toh.min = rb_stats->toh_min; 
     565            sess->stat.rx.stat_sum.toh.max = rb_stats->toh_max; 
     566            sess->stat.rx.stat_sum.toh.mean = rb_stats->toh_mean; 
     567            sess->stat.rx.stat_sum.toh.dev = rb_stats->toh_dev; 
     568        } 
     569    } 
     570 
     571    /* Receiving VoIP Metrics */ 
     572    if (rb_voip_mtc) { 
     573        sess->stat.rx.voip_mtc.loss_rate = rb_voip_mtc->loss_rate; 
     574        sess->stat.rx.voip_mtc.discard_rate = rb_voip_mtc->discard_rate; 
     575        sess->stat.rx.voip_mtc.burst_den = rb_voip_mtc->burst_den; 
     576        sess->stat.rx.voip_mtc.gap_den = rb_voip_mtc->gap_den; 
     577        sess->stat.rx.voip_mtc.burst_dur = pj_ntohs(rb_voip_mtc->burst_dur); 
     578        sess->stat.rx.voip_mtc.gap_dur = pj_ntohs(rb_voip_mtc->gap_dur); 
     579        sess->stat.rx.voip_mtc.rnd_trip_delay =  
     580                                        pj_ntohs(rb_voip_mtc->rnd_trip_delay); 
     581        sess->stat.rx.voip_mtc.end_sys_delay =  
     582                                        pj_ntohs(rb_voip_mtc->end_sys_delay); 
     583        sess->stat.rx.voip_mtc.signal_lvl = rb_voip_mtc->signal_lvl; 
     584        sess->stat.rx.voip_mtc.noise_lvl = rb_voip_mtc->noise_lvl; 
     585        sess->stat.rx.voip_mtc.rerl = rb_voip_mtc->rerl; 
     586        sess->stat.rx.voip_mtc.gmin = rb_voip_mtc->gmin; 
     587        sess->stat.rx.voip_mtc.r_factor = rb_voip_mtc->r_factor; 
     588        sess->stat.rx.voip_mtc.ext_r_factor = rb_voip_mtc->ext_r_factor; 
     589        sess->stat.rx.voip_mtc.mos_lq = rb_voip_mtc->mos_lq; 
     590        sess->stat.rx.voip_mtc.mos_cq = rb_voip_mtc->mos_cq; 
     591        sess->stat.rx.voip_mtc.rx_config = rb_voip_mtc->rx_config; 
     592        sess->stat.rx.voip_mtc.jb_nom = pj_ntohs(rb_voip_mtc->jb_nom); 
     593        sess->stat.rx.voip_mtc.jb_max = pj_ntohs(rb_voip_mtc->jb_max); 
     594        sess->stat.rx.voip_mtc.jb_abs_max = pj_ntohs(rb_voip_mtc->jb_abs_max); 
     595    } 
     596} 
     597 
     598/* Place seq into a 32-bit sequence number space based upon a 
     599 * heuristic for its most likely location. 
     600 */ 
     601static pj_uint32_t extend_seq(pjmedia_rtcp_xr_session *sess, 
     602                              const pj_uint16_t seq) 
     603{ 
     604 
     605    pj_uint32_t extended_seq, seq_a, seq_b, diff_a, diff_b; 
     606    if(sess->uninitialized_src_ref_seq) { 
     607        /* This is the first sequence number received.  Place 
     608         * it in the middle of the extended sequence number 
     609         * space. 
     610         */ 
     611        sess->src_ref_seq = seq | 0x80000000u; 
     612        sess->uninitialized_src_ref_seq = PJ_FALSE; 
     613        extended_seq = sess->src_ref_seq; 
     614    } else { 
     615        /* Prior sequence numbers have been received. 
     616         * Propose two candidates for the extended sequence 
     617         * number: seq_a is without wraparound, seq_b with 
     618         * wraparound. 
     619         */ 
     620        seq_a = seq | (sess->src_ref_seq & 0xFFFF0000u); 
     621        if(sess->src_ref_seq < seq_a) { 
     622            seq_b  = seq_a - 0x00010000u; 
     623            diff_a = seq_a - sess->src_ref_seq; 
     624            diff_b = sess->src_ref_seq - seq_b; 
     625        } else { 
     626            seq_b  = seq_a + 0x00010000u; 
     627            diff_a = sess->src_ref_seq - seq_a; 
     628            diff_b = seq_b - sess->src_ref_seq; 
     629        } 
     630 
     631        /* Choose the closer candidate.  If they are equally 
     632         * close, the choice is somewhat arbitrary: we choose 
     633         * the candidate for which no rollover is necessary. 
     634         */ 
     635        if(diff_a < diff_b) { 
     636            extended_seq = seq_a; 
     637        } else { 
     638            extended_seq = seq_b; 
     639        } 
     640 
     641        /* Set the reference sequence number to be this most 
     642         * recently-received sequence number. 
     643         */ 
     644        sess->src_ref_seq = extended_seq; 
     645    } 
     646 
     647    /* Return our best guess for a 32-bit sequence number that 
     648     * corresponds to the 16-bit number we were given. 
     649     */ 
     650    return extended_seq; 
     651} 
     652 
     653void pjmedia_rtcp_xr_rx_rtp( pjmedia_rtcp_xr_session *sess, 
     654                             unsigned seq,  
     655                             int lost, 
     656                             int dup, 
     657                             int discarded, 
     658                             int jitter, 
     659                             int toh, pj_bool_t toh_ipv4) 
     660{ 
     661    pj_uint32_t ext_seq; 
     662 
     663    /* Get 32 bit version of sequence */ 
     664    ext_seq = extend_seq(sess, (pj_uint16_t)seq); 
     665 
     666    /* Update statistics summary */ 
     667    sess->stat.tx.stat_sum.count++; 
     668 
     669    if (sess->stat.tx.stat_sum.begin_seq == 0 ||  
     670        sess->stat.tx.stat_sum.begin_seq > ext_seq) 
     671    { 
     672        sess->stat.tx.stat_sum.begin_seq = ext_seq; 
     673    } 
     674 
     675    if (sess->stat.tx.stat_sum.end_seq == 0 ||  
     676        sess->stat.tx.stat_sum.end_seq < ext_seq) 
     677    { 
     678        sess->stat.tx.stat_sum.end_seq = ext_seq; 
     679    } 
     680 
     681    if (lost >= 0) { 
     682        sess->stat.tx.stat_sum.l = PJ_TRUE; 
     683        if (lost > 0) 
     684            sess->stat.tx.stat_sum.lost++; 
     685    } 
     686 
     687    if (dup >= 0) { 
     688        sess->stat.tx.stat_sum.d = PJ_TRUE; 
     689        if (dup > 0) 
     690            sess->stat.tx.stat_sum.dup++; 
     691    } 
     692 
     693    if (jitter >= 0) { 
     694        pj_int32_t diff; 
     695 
     696        sess->stat.tx.stat_sum.j = PJ_TRUE; 
     697        if (sess->stat.tx.stat_sum.jitter.min > (pj_uint32_t)jitter) 
     698            sess->stat.tx.stat_sum.jitter.min = jitter; 
     699        if (sess->stat.tx.stat_sum.jitter.max < (pj_uint32_t)jitter) 
     700            sess->stat.tx.stat_sum.jitter.max = jitter; 
     701        sess->stat.tx.stat_sum.jitter.mean =  
     702            (jitter + sess->stat.tx.stat_sum.jitter.mean *  
     703             sess->stat.tx.stat_sum.jitter.count) / 
     704            (sess->stat.tx.stat_sum.jitter.count + 1); 
     705 
     706        diff = sess->stat.tx.stat_sum.jitter.mean - jitter; 
     707        sess->stat.tx.stat_sum.jitter.dev = 
     708            (diff * diff + sess->stat.tx.stat_sum.jitter.dev *  
     709             sess->stat.tx.stat_sum.jitter.count) / 
     710            (sess->stat.tx.stat_sum.jitter.count + 1); 
     711 
     712        ++sess->stat.tx.stat_sum.jitter.count; 
     713    } 
     714 
     715    if (toh >= 0) { 
     716        pj_int32_t diff; 
     717 
     718        sess->stat.tx.stat_sum.t = toh_ipv4? 1 : 2; 
     719 
     720        if (sess->stat.tx.stat_sum.toh.min > (pj_uint32_t)toh) 
     721            sess->stat.tx.stat_sum.toh.min = toh; 
     722        if (sess->stat.tx.stat_sum.toh.max < (pj_uint32_t)toh) 
     723            sess->stat.tx.stat_sum.toh.max = toh; 
     724        sess->stat.tx.stat_sum.toh.mean =  
     725            (toh + sess->stat.tx.stat_sum.toh.mean *  
     726             sess->stat.tx.stat_sum.toh.count) / 
     727            (sess->stat.tx.stat_sum.toh.count + 1); 
     728 
     729        diff = sess->stat.tx.stat_sum.toh.mean - toh; 
     730        sess->stat.tx.stat_sum.toh.dev = 
     731            (diff * diff + sess->stat.tx.stat_sum.toh.dev *  
     732             sess->stat.tx.stat_sum.toh.count) / 
     733            (sess->stat.tx.stat_sum.toh.count + 1); 
     734 
     735        ++sess->stat.tx.stat_sum.toh.count; 
     736    } 
     737 
     738    /* Update burst metrics. 
     739     * There are two terms introduced in the RFC 3611: gap & burst. 
     740     * Gap represents good stream condition, lost+discard rate <= 1/Gmin. 
     741     * Burst represents the opposite, lost+discard rate > 1/Gmin. 
     742     */ 
     743    if (lost >= 0 && discarded >= 0) { 
     744        if(lost > 0) { 
     745            sess->voip_mtc_stat.loss_count++; 
     746        } 
     747        if(discarded > 0) { 
     748            sess->voip_mtc_stat.discard_count++; 
     749        } 
     750        if(!lost && !discarded) { 
     751            /* Number of good packets since last lost/discarded */ 
     752            sess->voip_mtc_stat.pkt++; 
     753        } 
     754        else { 
     755            if(sess->voip_mtc_stat.pkt >= sess->stat.tx.voip_mtc.gmin) { 
     756                /* Gap condition */ 
     757                if(sess->voip_mtc_stat.lost == 1) { 
     758                    /* Gap -> Gap */ 
     759                    sess->voip_mtc_stat.c14++; 
     760                } 
     761                else { 
     762                    /* Burst -> Gap */ 
     763                    sess->voip_mtc_stat.c13++; 
     764                } 
     765                sess->voip_mtc_stat.lost = 1; 
     766                sess->voip_mtc_stat.c11 += sess->voip_mtc_stat.pkt; 
     767            } 
     768            else { 
     769                /* Burst condition */ 
     770                sess->voip_mtc_stat.lost++; 
     771                if(sess->voip_mtc_stat.pkt == 0) { 
     772                    /* Consecutive losts */ 
     773                    sess->voip_mtc_stat.c33++; 
     774                } 
     775                else { 
     776                    /* Any good packets, but still bursting */ 
     777                    sess->voip_mtc_stat.c23++; 
     778                    sess->voip_mtc_stat.c22 += (sess->voip_mtc_stat.pkt - 1); 
     779                } 
     780            } 
     781 
     782            sess->voip_mtc_stat.pkt = 0; 
     783        } 
     784    } 
     785} 
     786 
     787void pjmedia_rtcp_xr_tx_rtp( pjmedia_rtcp_xr_session *session,  
     788                             unsigned ptsize ) 
     789{ 
     790    PJ_UNUSED_ARG(session); 
     791    PJ_UNUSED_ARG(ptsize); 
     792} 
     793 
     794PJ_DEF(pj_status_t) pjmedia_rtcp_xr_update_info(  
     795                                         pjmedia_rtcp_xr_session *sess, 
     796                                         unsigned info, 
     797                                         pj_int32_t val) 
     798{ 
     799    int v = val; 
     800 
     801    switch(info) { 
     802        case PJMEDIA_RTCP_XR_INFO_SIGNAL_LVL: 
     803            sess->stat.tx.voip_mtc.signal_lvl = (pj_uint8_t) v; 
     804            break; 
     805 
     806        case PJMEDIA_RTCP_XR_INFO_NOISE_LVL: 
     807            sess->stat.tx.voip_mtc.noise_lvl = (pj_uint8_t) v; 
     808            break; 
     809 
     810        case PJMEDIA_RTCP_XR_INFO_RERL: 
     811            sess->stat.tx.voip_mtc.rerl = (pj_uint8_t) v; 
     812            break; 
     813 
     814        case PJMEDIA_RTCP_XR_INFO_R_FACTOR: 
     815            sess->stat.tx.voip_mtc.ext_r_factor = (pj_uint8_t) v; 
     816            break; 
     817 
     818        case PJMEDIA_RTCP_XR_INFO_MOS_LQ: 
     819            sess->stat.tx.voip_mtc.mos_lq = (pj_uint8_t) v; 
     820            break; 
     821 
     822        case PJMEDIA_RTCP_XR_INFO_MOS_CQ: 
     823            sess->stat.tx.voip_mtc.mos_cq = (pj_uint8_t) v; 
     824            break; 
     825 
     826        case PJMEDIA_RTCP_XR_INFO_CONF_PLC: 
     827            if (v >= 0 && v <= 3) { 
     828                sess->stat.tx.voip_mtc.rx_config &= 0x3F; 
     829                sess->stat.tx.voip_mtc.rx_config |= (pj_uint8_t) (v << 6); 
     830            } 
     831            break; 
     832 
     833        case PJMEDIA_RTCP_XR_INFO_CONF_JBA: 
     834            if (v >= 0 && v <= 3) { 
     835                sess->stat.tx.voip_mtc.rx_config &= 0xCF; 
     836                sess->stat.tx.voip_mtc.rx_config |= (pj_uint8_t) (v << 4); 
     837            } 
     838            break; 
     839 
     840        case PJMEDIA_RTCP_XR_INFO_CONF_JBR: 
     841            if (v >= 0 && v <= 15) { 
     842                sess->stat.tx.voip_mtc.rx_config &= 0xF0; 
     843                sess->stat.tx.voip_mtc.rx_config |= (pj_uint8_t) v; 
     844            } 
     845            break; 
     846 
     847        case PJMEDIA_RTCP_XR_INFO_JB_NOM: 
     848            sess->stat.tx.voip_mtc.jb_nom = (pj_uint16_t) v; 
     849            break; 
     850 
     851        case PJMEDIA_RTCP_XR_INFO_JB_MAX: 
     852            sess->stat.tx.voip_mtc.jb_max = (pj_uint16_t) v; 
     853            break; 
     854 
     855        case PJMEDIA_RTCP_XR_INFO_JB_ABS_MAX: 
     856            sess->stat.tx.voip_mtc.jb_abs_max = (pj_uint16_t) v; 
     857            break; 
     858 
     859        default: 
     860            return PJ_EINVAL; 
     861    } 
     862 
     863    return PJ_SUCCESS; 
     864} 
     865 
     866#endif 
  • pjmedia/src/pjmedia/jbuf.c

     
    6767    int             jb_max_prefetch;      // Maximum allowable prefetch 
    6868    int             jb_status;            // status is 'init' until the first 'put' operation 
    6969 
    70  
     70    int             jb_max_size;          // Maximum frames buffered ever 
    7171}; 
    7272 
    7373 
     
    368368    jb->jb_stable_hist   = 0; 
    369369    jb->jb_status        = JB_STATUS_INITIALIZING; 
    370370    jb->jb_max_hist_level = 0; 
     371    jb->jb_max_size      = 0; 
    371372 
    372373    jb_framelist_remove_head(&jb->jb_framelist,  
    373374                             jb_framelist_size(&jb->jb_framelist)); 
     
    383384 
    384385static void jbuf_calculate_jitter(pjmedia_jbuf *jb) 
    385386{ 
    386     int diff; 
     387    int diff, cur_size; 
    387388 
     389    /* Update jb_max_size */ 
     390    cur_size = jb_framelist_size(&jb->jb_framelist); 
     391    if (cur_size > jb->jb_max_size) 
     392        jb->jb_max_size = cur_size; 
     393 
    388394    /* Only apply burst-level calculation on PUT operation since if VAD is  
    389395     * active the burst-level may not be accurate. 
    390396     */ 
     
    413419                    jb->jb_prefetch = jb->jb_min_prefetch; 
    414420 
    415421                TRACE__((jb->name.ptr,"jb updated(1), prefetch=%d, size=%d",  
    416                          jb->jb_prefetch, jb_framelist_size(&jb->jb_framelist))); 
     422                         jb->jb_prefetch, cur_size)); 
    417423 
    418424                jb->jb_stable_hist = 0; 
    419425                jb->jb_max_hist_level = 0; 
     
    432438            jb->jb_max_hist_level = 0; 
    433439 
    434440            TRACE__((jb->name.ptr,"jb updated(2), prefetch=%d, size=%d",  
    435                      jb->jb_prefetch, jb_framelist_size(&jb->jb_framelist))); 
     441                     jb->jb_prefetch, cur_size)); 
    436442        } 
    437443 
    438444        /* Level is unchanged */ 
     
    442448    } 
    443449 
    444450    /* These code is used for shortening the delay in the jitter buffer. */ 
    445     diff = jb_framelist_size(&jb->jb_framelist) - jb->jb_prefetch; 
     451    diff = cur_size - jb->jb_prefetch; 
    446452    if (diff > SAFE_SHRINKING_DIFF) { 
    447453        /* Shrink slowly */ 
    448454        diff = 1; 
     
    471477                                     pj_size_t frame_size,  
    472478                                     int frame_seq) 
    473479{ 
     480    pjmedia_jbuf_put_frame2(jb, frame, frame_size, frame_seq, NULL); 
     481} 
     482 
     483PJ_DEF(void) pjmedia_jbuf_put_frame2(pjmedia_jbuf *jb,  
     484                                     const void *frame,  
     485                                     pj_size_t frame_size,  
     486                                     int frame_seq, 
     487                                     pj_bool_t *discarded) 
     488{ 
    474489    pj_size_t min_frame_size; 
    475490    int seq_diff; 
    476491 
     
    493508    if (seq_diff > 0) { 
    494509 
    495510        while (jb_framelist_put_at(&jb->jb_framelist, 
    496                                    frame_seq,frame,min_frame_size) ==PJ_FALSE) 
     511                                   frame_seq,frame,min_frame_size) == PJ_FALSE) 
    497512        { 
    498513            jb_framelist_remove_head(&jb->jb_framelist, 
    499514                                     PJ_MAX(jb->jb_max_count/4,1) ); 
     
    502517        if (jb->jb_prefetch_cnt < jb->jb_prefetch)       
    503518            jb->jb_prefetch_cnt += seq_diff; 
    504519 
     520        if (discarded) 
     521            *discarded = PJ_FALSE; 
    505522    } 
    506523    else 
    507524    { 
    508         jb_framelist_put_at(&jb->jb_framelist,frame_seq,frame,min_frame_size); 
     525        pj_bool_t res; 
     526        res = jb_framelist_put_at(&jb->jb_framelist,frame_seq,frame, 
     527                                  min_frame_size); 
     528        if (discarded) 
     529            *discarded = !res; 
    509530    } 
    510531} 
    511532 
     
    590611    state->min_prefetch = jb->jb_min_prefetch; 
    591612    state->max_prefetch = jb->jb_max_prefetch; 
    592613    state->size = jb_framelist_size(&jb->jb_framelist); 
     614    state->max_size = jb->jb_max_size; 
    593615 
    594616    return PJ_SUCCESS; 
    595617} 
  • pjmedia/src/pjmedia/stream.c

     
    470470        (*stream->transport->op->send_rtcp)(stream->transport,  
    471471                                            rtcp_pkt, len); 
    472472 
     473#if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0) 
     474        /* Temporarily always send RTCP XR after RTCP */ 
     475        if (stream->rtcp.xr_enabled) 
     476        { 
     477            int i; 
     478            pjmedia_jb_state jb_state; 
     479 
     480            pjmedia_jbuf_get_state(stream->jb, &jb_state); 
     481             
     482            i = jb_state.size * stream->codec_param.info.frm_ptime; 
     483            pjmedia_rtcp_xr_update_info(&stream->rtcp.xr_session,  
     484                                        PJMEDIA_RTCP_XR_INFO_JB_NOM, 
     485                                        i); 
     486 
     487            i = jb_state.max_size* stream->codec_param.info.frm_ptime; 
     488            pjmedia_rtcp_xr_update_info(&stream->rtcp.xr_session,  
     489                                        PJMEDIA_RTCP_XR_INFO_JB_MAX, 
     490                                        i); 
     491 
     492            pjmedia_rtcp_build_rtcp_xr(&stream->rtcp.xr_session, 0,  
     493                                       &rtcp_pkt, &len); 
     494 
     495            (*stream->transport->op->send_rtcp)(stream->transport,  
     496                                                rtcp_pkt, len); 
     497        } 
     498#endif 
     499 
    473500        stream->rtcp_last_tx = timestamp; 
    474501    } 
    475  
    476502} 
    477503 
    478504 
     
    9741000    unsigned payloadlen; 
    9751001    pjmedia_rtp_status seq_st; 
    9761002    pj_status_t status; 
     1003    pj_bool_t pkt_discarded = PJ_FALSE; 
    9771004 
    978  
    9791005    /* Check for errors */ 
    9801006    if (bytes_read < 0) { 
    9811007        LOGERR_((stream->port.info.name.ptr, "RTP recv() error", -bytes_read)); 
     
    9951021        return; 
    9961022    } 
    9971023 
    998  
    999     /* Inform RTCP session */ 
    1000     pjmedia_rtcp_rx_rtp(&stream->rtcp, pj_ntohs(hdr->seq), 
    1001                         pj_ntohl(hdr->ts), payloadlen); 
    1002  
    10031024    /* Ignore the packet if decoder is paused */ 
    10041025    if (channel->paused) 
    1005         return; 
     1026        goto on_return; 
    10061027 
    10071028    /* Update RTP session (also checks if RTP session can accept 
    10081029     * the incoming packet. 
     
    10251046                      "Bad RTP pt %d (expecting %d)", 
    10261047                      hdr->pt, channel->rtp.out_pt)); 
    10271048        } 
     1049 
     1050        if (seq_st.status.flag.badssrc) { 
     1051            PJ_LOG(4,(stream->port.info.name.ptr, 
     1052                      "Changed RTP peer SSRC %d (previously %d)", 
     1053                      channel->rtp.peer_ssrc, stream->rtcp.peer_ssrc)); 
     1054            stream->rtcp.peer_ssrc = channel->rtp.peer_ssrc; 
     1055        } 
     1056 
     1057 
    10281058    } 
    10291059 
    10301060    /* Skip bad RTP packet */ 
    1031     if (seq_st.status.flag.bad) 
    1032         return; 
     1061    if (seq_st.status.flag.bad) { 
     1062        pkt_discarded = PJ_TRUE; 
     1063        goto on_return; 
     1064    } 
    10331065 
    10341066    /* Ignore if payloadlen is zero */ 
    1035     if (payloadlen == 0) 
    1036         return; 
     1067    if (payloadlen == 0) { 
     1068        pkt_discarded = PJ_TRUE; 
     1069        goto on_return; 
     1070    } 
    10371071 
    10381072    /* Handle incoming DTMF. */ 
    10391073    if (hdr->pt == stream->rx_event_pt) { 
     
    10411075         * digit. Also ignore duplicate packet as it serves no use. 
    10421076         */ 
    10431077        if (seq_st.status.flag.outorder || seq_st.status.flag.dup) { 
    1044             return; 
     1078            goto on_return; 
    10451079        } 
    10461080 
    10471081        handle_incoming_dtmf(stream, payload, payloadlen); 
    1048         return; 
     1082        goto on_return; 
    10491083    } 
    10501084 
    10511085    /* Put "good" packet to jitter buffer, or reset the jitter buffer 
     
    11511185        /* Put each frame to jitter buffer. */ 
    11521186        for (i=0; i<count; ++i) { 
    11531187            unsigned ext_seq; 
     1188            pj_bool_t discarded; 
    11541189 
    11551190            ext_seq = (unsigned)(frames[i].timestamp.u64 / ts_span); 
    1156             pjmedia_jbuf_put_frame(stream->jb, frames[i].buf,  
    1157                                    frames[i].size, ext_seq); 
    1158  
     1191            pjmedia_jbuf_put_frame2(stream->jb, frames[i].buf, frames[i].size, 
     1192                                    ext_seq, &discarded); 
     1193            if (discarded) 
     1194                pkt_discarded = PJ_TRUE; 
    11591195        } 
    11601196    } 
    11611197    pj_mutex_unlock( stream->jb_mutex ); 
     
    11721208    if (status != 0) { 
    11731209        LOGERR_((stream->port.info.name.ptr, "Jitter buffer put() error",  
    11741210                status)); 
    1175         return; 
     1211        pkt_discarded = PJ_TRUE; 
     1212        goto on_return; 
    11761213    } 
     1214 
     1215on_return: 
     1216    /* Update RTCP session */ 
     1217    if (stream->rtcp.peer_ssrc == 0) 
     1218        stream->rtcp.peer_ssrc = channel->rtp.peer_ssrc; 
     1219 
     1220    pjmedia_rtcp_rx_rtp2(&stream->rtcp, pj_ntohs(hdr->seq), 
     1221                         pj_ntohl(hdr->ts), payloadlen, pkt_discarded); 
    11771222} 
    11781223 
    11791224 
     
    15121557 
    15131558    stream->transport = tp; 
    15141559 
     1560#if PJMEDIA_HAS_RTCP_XR && PJMEDIA_STREAM_ENABLE_XR 
     1561    /* Enable RTCP XR and update some settings */ 
     1562    { 
     1563        int i; 
     1564        pjmedia_rtcp_enable_xr(&stream->rtcp, PJ_TRUE); 
    15151565 
     1566        /* jitter buffer adaptive info */ 
     1567        i = PJMEDIA_RTCP_XR_JB_ADAPTIVE; 
     1568        pjmedia_rtcp_xr_update_info(&stream->rtcp.xr_session,  
     1569                                    PJMEDIA_RTCP_XR_INFO_CONF_JBA, 
     1570                                    i); 
     1571 
     1572        /* Jitter buffer aggressiveness info (estimated) */ 
     1573        i = 7; 
     1574        pjmedia_rtcp_xr_update_info(&stream->rtcp.xr_session,  
     1575                                    PJMEDIA_RTCP_XR_INFO_CONF_JBR, 
     1576                                    i); 
     1577 
     1578        /* Jitter buffer absolute maximum delay */ 
     1579        i = jb_max * stream->codec_param.info.frm_ptime; 
     1580        pjmedia_rtcp_xr_update_info(&stream->rtcp.xr_session,  
     1581                                    PJMEDIA_RTCP_XR_INFO_JB_ABS_MAX, 
     1582                                    i); 
     1583 
     1584        /* PLC info */ 
     1585        if (stream->codec_param.setting.plc == 0) 
     1586            i = PJMEDIA_RTCP_XR_PLC_DIS; 
     1587        else 
     1588#if PJMEDIA_WSOLA_IMP==PJMEDIA_WSOLA_IMP_WSOLA 
     1589            i = PJMEDIA_RTCP_XR_PLC_ENH; 
     1590#else 
     1591            i = PJMEDIA_RTCP_XR_PLC_DIS; 
     1592#endif 
     1593        pjmedia_rtcp_xr_update_info(&stream->rtcp.xr_session,  
     1594                                    PJMEDIA_RTCP_XR_INFO_CONF_PLC, 
     1595                                    i); 
     1596    } 
     1597#endif 
     1598 
    15161599    /* Success! */ 
    15171600    *p_stream = stream; 
    15181601 
    15191602    PJ_LOG(5,(THIS_FILE, "Stream %s created", stream->port.info.name.ptr)); 
     1603 
    15201604    return PJ_SUCCESS; 
    15211605 
    15221606 
  • pjmedia/src/pjmedia/rtcp.c

     
    2828 
    2929#define RTCP_SR   200 
    3030#define RTCP_RR   201 
     31#define RTCP_XR   207 
    3132 
    32  
    3333#if PJ_HAS_HIGH_RES_TIMER==0 
    3434#   error "High resolution timer needs to be enabled" 
    3535#endif 
     
    172172 
    173173PJ_DEF(void) pjmedia_rtcp_fini(pjmedia_rtcp_session *sess) 
    174174{ 
     175#if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0) 
     176    pjmedia_rtcp_xr_fini(&sess->xr_session); 
     177#else 
    175178    /* Nothing to do. */ 
    176179    PJ_UNUSED_ARG(sess); 
     180#endif 
    177181} 
    178182 
    179183static void rtcp_init_seq(pjmedia_rtcp_session *sess) 
     
    185189    sess->jitter = 0; 
    186190} 
    187191 
    188 PJ_DEF(void) pjmedia_rtcp_rx_rtp(pjmedia_rtcp_session *sess,  
    189                                  unsigned seq,  
    190                                  unsigned rtp_ts, 
    191                                  unsigned payload) 
     192PJ_DEF(void) pjmedia_rtcp_rx_rtp( pjmedia_rtcp_session *sess,  
     193                                  unsigned seq,  
     194                                  unsigned rtp_ts, 
     195                                  unsigned payload) 
     196{ 
     197    pjmedia_rtcp_rx_rtp2(sess, seq, rtp_ts, payload, PJ_FALSE); 
     198} 
     199 
     200PJ_DEF(void) pjmedia_rtcp_rx_rtp2(pjmedia_rtcp_session *sess,  
     201                                  unsigned seq,  
     202                                  unsigned rtp_ts, 
     203                                  unsigned payload, 
     204                                  pj_bool_t discarded) 
    192205{    
    193206    pj_timestamp ts; 
    194207    pj_uint32_t arrival; 
     
    196209    pjmedia_rtp_status seq_st; 
    197210    unsigned last_seq; 
    198211 
     212#if !defined(PJMEDIA_HAS_RTCP_XR) || (PJMEDIA_HAS_RTCP_XR == 0) 
     213    PJ_UNUSED_ARG(discarded); 
     214#endif 
     215 
    199216    if (sess->stat.rx.pkt == 0) { 
    200217        /* Init sequence for the first time. */ 
    201218        pjmedia_rtp_seq_init(&sess->seq_ctrl, (pj_uint16_t)seq); 
     
    224241 
    225242    if (seq_st.status.flag.bad) { 
    226243        sess->stat.rx.discard++; 
     244 
     245#if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0) 
     246        pjmedia_rtcp_xr_rx_rtp(&sess->xr_session, seq,  
     247                               -1,                               /* lost    */ 
     248                               (seq_st.status.flag.dup? 1:0),    /* dup     */ 
     249                               (!seq_st.status.flag.dup? 1:-1),  /* discard */ 
     250                               -1,                               /* jitter  */ 
     251                               -1, 0);                           /* toh     */ 
     252#endif 
     253 
    227254        TRACE_((sess->name, "Bad packet discarded")); 
    228255        return; 
    229256    } 
     
    316343                sess->stat.rx.jitter.max = jitter; 
    317344 
    318345            sess->stat.rx.jitter.last = jitter; 
     346 
     347#if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0) 
     348            pjmedia_rtcp_xr_rx_rtp(&sess->xr_session, seq,  
     349                                   0,                       /* lost    */ 
     350                                   0,                       /* dup     */ 
     351                                   discarded,               /* discard */ 
     352                                   (sess->jitter >> 4),     /* jitter  */ 
     353                                   -1, 0);                  /* toh     */ 
     354#endif 
    319355        } 
     356#if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0) 
     357    } else if (seq_st.diff > 1) { 
     358        int i; 
     359 
     360        /* Report RTCP XR about packet losses */ 
     361        for (i=seq_st.diff-1; i>0; --i) { 
     362            pjmedia_rtcp_xr_rx_rtp(&sess->xr_session, seq - i,  
     363                                   1,                       /* lost    */ 
     364                                   0,                       /* dup     */ 
     365                                   0,                       /* discard */ 
     366                                   -1,                      /* jitter  */ 
     367                                   -1, 0);                  /* toh     */ 
     368        } 
     369 
     370        /* Report RTCP XR this packet */ 
     371        pjmedia_rtcp_xr_rx_rtp(&sess->xr_session, seq,  
     372                               0,                           /* lost    */ 
     373                               0,                           /* dup     */ 
     374                               discarded,                   /* discard */ 
     375                               -1,                          /* jitter  */ 
     376                               -1, 0);                      /* toh     */ 
     377#endif 
    320378    } 
    321379 
    322380    /* Update timestamp of last RX RTP packet */ 
     
    348406            rr = (pjmedia_rtcp_rr*)(((char*)pkt) + (sizeof(pjmedia_rtcp_common) 
    349407                                    + sizeof(pjmedia_rtcp_sr))); 
    350408        } 
    351     } else if (common->pt == RTCP_RR && common->count > 0) 
     409    } else if (common->pt == RTCP_RR && common->count > 0) { 
    352410        rr = (pjmedia_rtcp_rr*)(((char*)pkt) + sizeof(pjmedia_rtcp_common)); 
     411#if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0) 
     412    } else if (common->pt == RTCP_XR) { 
     413        if (sess->xr_enabled) 
     414            pjmedia_rtcp_xr_rx_rtcp_xr(&sess->xr_session, pkt, size); 
    353415 
     416        return; 
     417#endif 
     418    } 
    354419 
     420 
    355421    if (sr) { 
    356422        /* Save LSR from NTP timestamp of RTCP packet */ 
    357423        sess->rx_lsr = ((pj_ntohl(sr->ntp_sec) & 0x0000FFFF) << 16) |  
     
    674740    sess->stat.rx.update_cnt++; 
    675741} 
    676742 
    677   
     743PJ_DEF(pj_status_t) pjmedia_rtcp_enable_xr( pjmedia_rtcp_session *sess,  
     744                                            pj_bool_t enable) 
     745{ 
     746#if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0) 
     747 
     748    /* Check if request won't change anything */ 
     749    if (!(enable ^ sess->xr_enabled)) 
     750        return PJ_SUCCESS; 
     751 
     752    if (!enable) { 
     753        sess->xr_enabled = PJ_FALSE; 
     754        return PJ_SUCCESS; 
     755    } 
     756 
     757    pjmedia_rtcp_xr_init(&sess->xr_session, sess, 0, 1); 
     758    sess->xr_enabled = PJ_TRUE; 
     759 
     760    return PJ_SUCCESS; 
     761 
     762#else 
     763 
     764    PJ_UNUSED_ARG(sess); 
     765    PJ_UNUSED_ARG(enable); 
     766    return PJ_ENOTSUP; 
     767 
     768#endif 
     769}