/* 
 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
 */
#ifndef __PJMEDIA_RTCP_XR_H__
#define __PJMEDIA_RTCP_XR_H__

/**
 * @file rtcp_xr.h
 * @brief RTCP XR implementation.
 */

#include <pjmedia/types.h>
#include <pj/math.h>


PJ_BEGIN_DECL


/**
 * @defgroup PJMED_RTCP_XR RTCP Extended Report (XR) - RFC 3611
 * @ingroup PJMEDIA_SESSION
 * @brief RTCP XR extension to RTCP session
 * @{
 *
 * PJMEDIA implements subsets of RTCP XR specification (RFC 3611) to monitor
 * the quality of the real-time media (audio/video) transmission.
 */

/**
 * Enumeration of report types of RTCP XR. Useful for user to enable varying
 * combinations of RTCP XR report blocks.
 */
typedef enum {
    PJMEDIA_RTCP_XR_LOSS_RLE        = (1 << 0),
    PJMEDIA_RTCP_XR_DUP_RLE         = (1 << 1),
    PJMEDIA_RTCP_XR_RCPT_TIMES      = (1 << 2),
    PJMEDIA_RTCP_XR_RR_TIME         = (1 << 3),
    PJMEDIA_RTCP_XR_DLRR            = (1 << 4),
    PJMEDIA_RTCP_XR_STATS           = (1 << 5),
    PJMEDIA_RTCP_XR_VOIP_METRICS    = (1 << 6)
} pjmedia_rtcp_xr_type;

/**
 * Enumeration of info need to be updated manually to RTCP XR. Most info
 * could be updated automatically each time RTP received.
 */
typedef enum {
    PJMEDIA_RTCP_XR_INFO_SIGNAL_LVL = 1,
    PJMEDIA_RTCP_XR_INFO_NOISE_LVL  = 2,
    PJMEDIA_RTCP_XR_INFO_RERL       = 3,
    PJMEDIA_RTCP_XR_INFO_R_FACTOR   = 4,
    PJMEDIA_RTCP_XR_INFO_MOS_LQ     = 5,
    PJMEDIA_RTCP_XR_INFO_MOS_CQ     = 6,
    PJMEDIA_RTCP_XR_INFO_CONF_PLC   = 7,
    PJMEDIA_RTCP_XR_INFO_CONF_JBA   = 8,
    PJMEDIA_RTCP_XR_INFO_CONF_JBR   = 9,
    PJMEDIA_RTCP_XR_INFO_JB_NOM     = 10,
    PJMEDIA_RTCP_XR_INFO_JB_MAX     = 11,
    PJMEDIA_RTCP_XR_INFO_JB_ABS_MAX = 12
} pjmedia_rtcp_xr_info;

/**
 * Enumeration of PLC types definitions for RTCP XR report.
 */
typedef enum {
    PJMEDIA_RTCP_XR_PLC_UNK         = 0,
    PJMEDIA_RTCP_XR_PLC_DIS         = 1,
    PJMEDIA_RTCP_XR_PLC_ENH         = 2,
    PJMEDIA_RTCP_XR_PLC_STD         = 3
} pjmedia_rtcp_xr_plc_type;

/**
 * Enumeration of jitter buffer types definitions for RTCP XR report.
 */
typedef enum {
    PJMEDIA_RTCP_XR_JB_UNKNOWN      = 0,
    PJMEDIA_RTCP_XR_JB_FIXED        = 2,
    PJMEDIA_RTCP_XR_JB_ADAPTIVE     = 3
} pjmedia_rtcp_xr_jb_type;


#pragma pack(1)

/**
 * This type declares RTCP XR Report Header.
 */
typedef struct pjmedia_rtcp_xr_rb_header
{
    pj_uint8_t           bt;            /**< Block type.                */
    pj_uint8_t           specific;      /**< Block specific data.       */
    pj_uint16_t          length;        /**< Block length.              */
} pjmedia_rtcp_xr_rb_header;

/**
 * This type declares RTCP XR Receiver Reference Time Report Block.
 */
typedef struct pjmedia_rtcp_xr_rb_rr_time
{
    pjmedia_rtcp_xr_rb_header header;   /**< Block header.              */
    pj_uint32_t          ntp_sec;       /**< NTP time, seconds part.    */
    pj_uint32_t          ntp_frac;      /**< NTP time, fractions part.  */
} pjmedia_rtcp_xr_rb_rr_time;


/**
 * This type declares RTCP XR DLRR Report Sub-block
 */
typedef struct pjmedia_rtcp_xr_rb_dlrr_item
{
    pj_uint32_t          ssrc;          /**< receiver SSRC              */
    pj_uint32_t          lrr;           /**< last receiver report       */
    pj_uint32_t          dlrr;          /**< delay since last receiver
                                             report                     */
} pjmedia_rtcp_xr_rb_dlrr_item;

/**
 * This type declares RTCP XR DLRR Report Block
 */
typedef struct pjmedia_rtcp_xr_rb_dlrr
{
    pjmedia_rtcp_xr_rb_header header;   /**< Block header.              */
    pjmedia_rtcp_xr_rb_dlrr_item item;  /**< Block contents, 
                                             variable length list       */
} pjmedia_rtcp_xr_rb_dlrr;

/**
 * This type declares RTCP XR Statistics Summary Report Block
 */
typedef struct pjmedia_rtcp_xr_rb_stats
{
    pjmedia_rtcp_xr_rb_header header;   /**< Block header.                   */
    pj_uint32_t          ssrc;          /**< Receiver SSRC                   */
    pj_uint16_t          begin_seq;     /**< Begin RTP sequence reported     */
    pj_uint16_t          end_seq;       /**< End RTP sequence reported       */
    pj_uint32_t          lost;          /**< Number of packet lost in this 
                                             interval  */
    pj_uint32_t          dup;           /**< Number of duplicated packet in 
                                             this interval */
    pj_uint32_t          jitter_min;    /**< Minimum jitter in this interval */
    pj_uint32_t          jitter_max;    /**< Maximum jitter in this interval */
    pj_uint32_t          jitter_mean;   /**< Average jitter in this interval */
    pj_uint32_t          jitter_dev;    /**< Jitter deviation in this 
                                             interval */
    pj_uint32_t          toh_min:8;     /**< Minimum ToH in this interval    */
    pj_uint32_t          toh_max:8;     /**< Maximum ToH in this interval    */
    pj_uint32_t          toh_mean:8;    /**< Average ToH in this interval    */
    pj_uint32_t          toh_dev:8;     /**< ToH deviation in this interval  */
} pjmedia_rtcp_xr_rb_stats;

/**
 * This type declares RTCP XR VoIP Metrics Report Block
 */
typedef struct pjmedia_rtcp_xr_rb_voip_mtc
{
    pjmedia_rtcp_xr_rb_header header;   /**< Block header.              */
    pj_uint32_t          ssrc;          /**< Receiver SSRC              */
    pj_uint8_t           loss_rate;     /**< Packet loss rate           */
    pj_uint8_t           discard_rate;  /**< Packet discarded rate      */
    pj_uint8_t           burst_den;     /**< Burst density              */
    pj_uint8_t           gap_den;       /**< Gap density                */
    pj_uint16_t          burst_dur;     /**< Burst duration             */
    pj_uint16_t          gap_dur;       /**< Gap duration               */
    pj_uint16_t          rnd_trip_delay;/**< Round trip delay           */
    pj_uint16_t          end_sys_delay; /**< End system delay           */
    pj_uint8_t           signal_lvl;    /**< Signal level               */
    pj_uint8_t           noise_lvl;     /**< Noise level                */
    pj_uint8_t           rerl;          /**< Residual Echo Return Loss  */
    pj_uint8_t           gmin;          /**< The gap threshold          */
    pj_uint8_t           r_factor;      /**< Voice quality metric carried
                                             over this RTP session      */
    pj_uint8_t           ext_r_factor;  /**< Voice quality metric carried 
                                             outside of this RTP session*/
    pj_uint8_t           mos_lq;        /**< Mean Opinion Score for 
                                             Listening Quality          */
    pj_uint8_t           mos_cq;        /**< Mean Opinion Score for 
                                             Conversation Quality       */
    pj_uint8_t           rx_config;     /**< Receiver configuration     */
    pj_uint8_t           reserved2;     /**< Not used                   */
    pj_uint16_t          jb_nom;        /**< Current delay by jitter
                                             buffer                     */
    pj_uint16_t          jb_max;        /**< Maximum delay by jitter
                                             buffer                     */
    pj_uint16_t          jb_abs_max;    /**< Maximum possible delay by
                                             jitter buffer              */
} pjmedia_rtcp_xr_rb_voip_mtc;


/**
 * Constant of RTCP-XR content size.
 */
#define PJMEDIA_RTCP_XR_BUF_SIZE \
    sizeof(pjmedia_rtcp_xr_rb_rr_time) + \
    sizeof(pjmedia_rtcp_xr_rb_dlrr) + \
    sizeof(pjmedia_rtcp_xr_rb_stats) + \
    sizeof(pjmedia_rtcp_xr_rb_voip_mtc)


/**
 * This structure declares RTCP XR (Extended Report) packet.
 */
typedef struct pjmedia_rtcp_xr_pkt
{
    struct {
#if defined(PJ_IS_BIG_ENDIAN) && PJ_IS_BIG_ENDIAN!=0
        unsigned         version:2;     /**< packet type            */
        unsigned         p:1;           /**< padding flag           */
        unsigned         count:5;       /**< varies by payload type */
        unsigned         pt:8;          /**< payload type           */
#else
        unsigned         count:5;       /**< varies by payload type */
        unsigned         p:1;           /**< padding flag           */
        unsigned         version:2;     /**< packet type            */
        unsigned         pt:8;          /**< payload type           */
#endif
        unsigned         length:16;     /**< packet length          */
        pj_uint32_t      ssrc;          /**< SSRC identification    */
    } common;

    pj_int8_t            buf[PJMEDIA_RTCP_XR_BUF_SIZE];
                                        /**< Content buffer   */
} pjmedia_rtcp_xr_pkt;

#pragma pack()


/**
 * This structure describes RTCP XR statitic.
 */
typedef struct pjmedia_rtcp_xr_stream_stat
{
    struct {
        pj_time_val         update;     /**< Time of last update.           */

        pj_uint32_t         begin_seq;  /**< Begin # seq of this interval.  */
        pj_uint32_t         end_seq;    /**< End # seq of this interval.    */
        unsigned            count;      /**< Number of packets.             */

        /**
         * Flags represent whether the such report is valid/updated
         */
        unsigned            l:1;        /**< Lost flag                      */
        unsigned            d:1;        /**< Duplicated flag                */
        unsigned            j:1;        /**< Jitter flag                    */
        unsigned            t:2;        /**< TTL or Hop Limit, 
                                             0=none, 1=TTL, 2=HL            */

        unsigned            lost;       /**< Number of packets lost         */
        unsigned            dup;        /**< Number of duplicated packets   */
        pj_math_stat        jitter;     /**< Jitter statistics (in usec)    */
        pj_math_stat        toh;        /**< TTL of hop limit statistics.   */
    } stat_sum;

    struct {
        pj_time_val         update;         /**< Time of last update.       */

        pj_uint8_t          loss_rate;      /**< Packet loss rate           */
        pj_uint8_t          discard_rate;   /**< Packet discarded rate      */
        pj_uint8_t          burst_den;      /**< Burst density              */
        pj_uint8_t          gap_den;        /**< Gap density                */
        pj_uint16_t         burst_dur;      /**< Burst duration             */
        pj_uint16_t         gap_dur;        /**< Gap duration               */
        pj_uint16_t         rnd_trip_delay; /**< Round trip delay           */
        pj_uint16_t         end_sys_delay;  /**< End system delay           */
        pj_int8_t           signal_lvl;     /**< Signal level               */
        pj_int8_t           noise_lvl;      /**< Noise level                */
        pj_uint8_t          rerl;           /**< Residual Echo Return Loss  */
        pj_uint8_t          gmin;           /**< The gap threshold          */
        pj_uint8_t          r_factor;       /**< Voice quality metric carried
                                                 over this RTP session      */
        pj_uint8_t          ext_r_factor;   /**< Voice quality metric carried 
                                                 outside of this RTP session*/
        pj_uint8_t          mos_lq;         /**< Mean Opinion Score for 
                                                 Listening Quality          */
        pj_uint8_t          mos_cq;         /**< Mean Opinion Score for 
                                                 Conversation Quality       */
        pj_uint8_t          rx_config;      /**< Receiver configuration     */
        pj_uint16_t         jb_nom;         /**< Current delay by jitter
                                                 buffer                     */
        pj_uint16_t         jb_max;         /**< Maximum delay by jitter
                                                 buffer                     */
        pj_uint16_t         jb_abs_max;     /**< Maximum possible delay by
                                                 jitter buffer              */
    } voip_mtc;

} pjmedia_rtcp_xr_stream_stat;

typedef struct pjmedia_rtcp_xr_stat
{
    pjmedia_rtcp_xr_stream_stat  rx;  /**< Decoding direction statistics.   */
    pjmedia_rtcp_xr_stream_stat  tx;  /**< Encoding direction statistics.   */
    pj_math_stat                 rtt; /**< Round-trip delay stat (in usec) 
                                           the value is calculated from 
                                           receiver side.                   */
} pjmedia_rtcp_xr_stat;

/**
 * Forward declaration of RTCP session
 */
struct pjmedia_rtcp_session;

/**
 * RTCP session is used to monitor the RTP session of one endpoint. There
 * should only be one RTCP session for a bidirectional RTP streams.
 */
struct pjmedia_rtcp_xr_session
{
    char                   *name;       /**< Name identification.           */
    pjmedia_rtcp_xr_pkt     pkt;        /**< Cached RTCP XR packet.         */

    pj_uint32_t             rx_lrr;     /**< NTP ts in last RR received.    */
    pj_timestamp            rx_lrr_time;/**< Time when last RR is received. */
    pj_uint32_t             rx_last_rr; /**< # pkt received since last 
                                             sending RR time.               */

    pjmedia_rtcp_xr_stat    stat;       /**< RTCP XR statistics.            */

    /* The reference sequence number is an extended sequence number
     * that serves as the basis for determining whether a new 16 bit
     * sequence number comes earlier or later in the 32 bit sequence
     * space.
     */
    pj_uint32_t             src_ref_seq;
    pj_bool_t               uninitialized_src_ref_seq;

    /* This structure contains variables needed for calculating 
     * burst metrics.
     */
    struct {
        pj_uint32_t         pkt;
        pj_uint32_t         lost;
        pj_uint32_t         loss_count;
        pj_uint32_t         discard_count;
        pj_uint32_t         c11;
        pj_uint32_t         c13;
        pj_uint32_t         c14;
        pj_uint32_t         c22;
        pj_uint32_t         c23;
        pj_uint32_t         c33;
    } voip_mtc_stat;

    unsigned ptime;                     /**< Packet time.                   */
    unsigned frames_per_packet;         /**< # frames per packet.           */

    struct pjmedia_rtcp_session *rtcp_session;
                                        /**< Parent/RTCP session.           */
};

typedef struct pjmedia_rtcp_xr_session pjmedia_rtcp_xr_session;

/**
 * Build an RTCP XR packet which contains one or more RTCP XR report blocks.
 * There are seven report types as defined in RFC 3611.
 *
 * @param session   The RTCP XR session.
 * @param rpt_types Report types to be included in the packet, report types
 *                  are defined in pjmedia_rtcp_xr_type, set this to zero
 *                  will make this function build all reports appropriately.
 * @param rtcp_pkt  Upon return, it will contain pointer to the RTCP XR packet.
 * @param len       Upon return, it will indicate the size of the generated 
 *                  RTCP XR packet.
 */
PJ_DECL(void) pjmedia_rtcp_build_rtcp_xr( pjmedia_rtcp_xr_session *session,
                                          unsigned rpt_types,
                                          void **rtcp_pkt, int *len);

/**
 * Call this function to manually update some info needed by RTCP XR to 
 * generate report which could not be populated directly when receiving
 * RTP.
 *
 * @param session   The RTCP XR session.
 * @param info      Info type to be updated, @see pjmedia_rtcp_xr_info.
 * @param val       Value.
 */
PJ_DECL(pj_status_t) pjmedia_rtcp_xr_update_info(
                                          pjmedia_rtcp_xr_session *session,
                                          unsigned info,
                                          pj_int32_t val);

/*
 * Private APIs:
 */

/**
 * This function is called internally by RTCP session when RTCP XR is enabled
 * to initialize the RTCP XR session.
 *
 * @param session   RTCP XR session.
 * @param r_session RTCP session.
 * @param gmin      Gmin value (defined in RFC 3611), set to 0 for default (16).
 * @param frames_per_packet
                    Number of frames per packet.
 */
void pjmedia_rtcp_xr_init( pjmedia_rtcp_xr_session *session, 
                           struct pjmedia_rtcp_session *r_session,
                           pj_uint8_t gmin,
                           unsigned frames_per_packet);

/**
 * This function is called internally by RTCP session to destroy 
 * the RTCP XR session.
 *
 * @param session   RTCP XR session.
 */
void pjmedia_rtcp_xr_fini( pjmedia_rtcp_xr_session *session );

/**
 * This function is called internally by RTCP session when it receives 
 * incoming RTCP XR packets.
 *
 * @param session   RTCP XR session.
 * @param rtcp_pkt  The received RTCP XR packet.
 * @param size      Size of the incoming packet.
 */
void pjmedia_rtcp_xr_rx_rtcp_xr( pjmedia_rtcp_xr_session *session,
                                 const void *rtcp_pkt,
                                 pj_size_t size);

/**
 * This function is called internally by RTCP session whenever an RTP packet
 * is received or lost to let the RTCP XR session update its statistics.
 * Data passed to this function is a result of analyzation by RTCP and the
 * jitter buffer. Whenever some info is available, the value should be zero
 * or more (no negative info), otherwise if info is not available the info
 * should be -1 so no update will be done for this info in the RTCP XR session.
 *
 * @param session   RTCP XR session.
 * @param seq       Sequence number of RTP packet.
 * @param lost      Info if this packet is lost. 
 * @param dup       Info if this packet is a duplication. 
 * @param discarded Info if this packet is discarded 
 *                  (not because of duplication).
 * @param jitter    Info jitter of this packet.
 * @param toh       Info Time To Live or Hops Limit of this packet.
 * @param toh_ipv4  Set PJ_TRUE if packet is transported over IPv4.
 */
void pjmedia_rtcp_xr_rx_rtp( pjmedia_rtcp_xr_session *session,
                             unsigned seq, 
                             int lost,
                             int dup,
                             int discarded,
                             int jitter,
                             int toh, pj_bool_t toh_ipv4);

/**
 * This function is called internally by RTCP session whenever an RTP 
 * packet is sent to let the RTCP XR session do its internal calculations.
 *
 * @param session   RTCP XR session.
 * @param ptsize    Size of RTP payload being sent.
 */
void pjmedia_rtcp_xr_tx_rtp( pjmedia_rtcp_xr_session *session, 
                             unsigned ptsize );

/**
 * @}
 */

PJ_END_DECL


#endif  /* __PJMEDIA_RTCP_XR_H__ */
