/* $Id$ */
/* 
 * 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__ */
