/*=========================================================================*\
  Copyright (c) 2000-2001 Computer & Communications Research Laboratories,
                          Industrial Technology Research Institute
  
  RTP - RTP header file
  
  Author: Jiun-Yao Huang <jyhuang@wizs.org>
  Revision: $Id: rtp.h,v 1.28 2001/06/19 07:15:46 jyhuang Exp $
\*=========================================================================*/
#ifndef	__RTP_H__
#define	__RTP_H__

#include "config.h"
#include "rtp_error.h"


/*--[ types ]---------------------------------------------------------------*/
typedef unsigned char   u_int8;
typedef unsigned short  u_int16;
typedef unsigned int    u_int32;
typedef short           int16;
/*--------------------------------------------------------------------------*/

/*--[ macros ]--------------------------------------------------------------*/
#define RTP_VERSION	2
#define	RTP_SEQ_MOD	(1<<16)
#define	RTP_MAX_SDES	255

#define	RTP_PORT_BASE	9000
#define	RTP_PORT_MAX	9999

#define	RTP_MAX_DROPOUT		3000
#define	RTP_MAX_MISORDER	100
#define	RTP_MIN_SEQUENTIAL	2

/* RTP Events */
#define	RTPEVT_TIMEOUT	0	/* timeout */
#define	RTPEVT_READ	1	/* readable */
#define	RTPEVT_WRITE	2	/* writable */
#define	RTPEVT_ERROR	4	/* exception */

typedef enum {
	RTCP_SR   = 200,	/* sender report */
	RTCP_RR   = 201,	/* receiver report */
	RTCP_SDES = 202,	/* source description */
	RTCP_BYE  = 203,	/* goodbye */
	RTCP_APP  = 204		/* appliciation specific */
} rtcp_type_t ;

typedef enum {
	RTCP_SDES_END   = 0,	/* end of SDES list */
	RTCP_SDES_CNAME = 1,	/* canonical name */
	RTCP_SDES_NAME  = 2,	/* user name */
	RTCP_SDES_EMAIL = 3,	/* user's e-mail address */
	RTCP_SDES_PHONE = 4,	/* phone number */
	RTCP_SDES_LOC   = 5,	/* geographic user location */
	RTCP_SDES_TOOL  = 6,	/* application or tool name */
	RTCP_SDES_NOTE  = 7,	/* notice/status */
	RTCP_SDES_PRIV  = 8	/* private extension */
} rtcp_sdes_type_t;

#pragma	pack(1)

/**
 * RTP packet header
 */
typedef struct rtp_hdr {
#ifdef	WORDS_BIGENDIAN
	u_int32 ver  :2;        /* protocol version */
	u_int32 p    :1;        /* padding flag */
	u_int32 x    :1;        /* header extension flag */
	u_int32 cc   :4;        /* CSRC count */
	u_int32 m    :1;        /* marker bit */
	u_int32 pt   :7;        /* payload type */
#else	/* little endian */
	u_int32 cc   :4;        /* CSRC count */
	u_int32 x    :1;        /* header extension flag */
	u_int32 p    :1;        /* padding flag */
	u_int32 ver  :2;        /* protocol version */
	u_int32 pt   :7;        /* payload type */
	u_int32 m    :1;        /* marker bit */
#endif	/* WORDS_BIGENDIAN */
	u_int32 seq  :16;       /* sequence number */
	u_int32 ts;             /* timestamp */
	u_int32 ssrc;           /* synchronization source */
	u_int32 csrc[1];        /* optional CSRC list */
} rtp_hdr_t;

/**
 * RTCP common header word
 */
typedef struct rtcp_common {
#ifdef	WORDS_BIGENDIAN
	u_int32 ver   :2;       /* protocol version */
	u_int32 p     :1;       /* padding flag */
	u_int32 count :5;       /* varies by packet type */
#else	/* little endian */
	u_int32 count :5;       /* varies by packet type */
	u_int32 p     :1;       /* padding flag */
	u_int32 ver   :2;       /* protocol version */
#endif	/* WORDS_BIGENDIAN */
	u_int32 pt    :8;       /* RTCP packet type */
	u_int32 len   :16;      /* pkt len in words, w/o this word */
} rtcp_common_t;

/**
 * Reception report block
 */
typedef struct rtcp_rr {
	u_int32 ssrc;           /* data source being reported */
	u_int32 fraction :8;    /* fraction lost since last SR/RR */
	u_int32 lost     :24;   /* cumul. no. pkts lost (signed!) */
	u_int32 lseq;           /* extended last seq. no. received */
	u_int32 jitter;         /* interarrival jitter */
	u_int32 lsr;            /* last SR packet from this source */
	u_int32 dlsr;           /* delay since last SR packet */
} rtcp_rr_t;

/**
 * SDES item
 */
typedef struct rtcp_sdes_item {
	u_int8 type;            /* type of item (rtcp_sdes_type_t) */
	u_int8 len;             /* length of item (in octets) */
	char data[1];           /* text, not null-terminated */
} rtcp_sdes_item_t ;

/**
 * One RTCP packet
 */
typedef struct rtcp {
	rtcp_common_t common;   /* common header */
	union r_t {
		/* sender report (SR) */
		struct sr_s {
			u_int32   ssrc;     /* sender generating this report */
			u_int32   ntp_sec;  /* NTP timestamp */
			u_int32   ntp_frac;
			u_int32   rtp_ts;  /* RTP timestamp */
			u_int32   psent;   /* packets sent */
			u_int32   osent;   /* octets sent */
			rtcp_rr_t rr[1];   /* variable-length list */
		} sr;

		/* reception report (RR) */
		struct rr_s {
			u_int32   ssrc;  /* receiver generating this report */
			rtcp_rr_t rr[1]; /* variable-length list */
		} rr;

		/* source description (SDES) */
		struct rtcp_sdes_s {
			u_int32          src;      /* first SSRC/CSRC */
			rtcp_sdes_item_t item[1];  /* list of SDES items */
		} sdes;

		/* BYE */
		struct byt_s {
			u_int32 src[1];   /* list of sources */
			/* can't express trailing text for reason */
		} bye;
	} r;
} rtcp_t;

#pragma	pack()

typedef struct rtcp_sdes_s rtcp_sdes_t;

struct rtp_s;
struct rtcp_s;

typedef struct rtp_source {
	u_int32	ssrc;		/* SSRC */
	u_int16 max_seq;        /* highest seq. number seen */
	u_int32 cycles;         /* shifted count of seq. number cycles */
	u_int32 base_seq;       /* base seq number */
	u_int32 bad_seq;        /* last 'bad' seq number + 1 */
	u_int32 probation;      /* sequ. packets till source is valid */
	u_int32 received;       /* packets received */
	u_int32 expected_prior; /* packet expected at last interval */
	u_int32 received_prior; /* packet received at last interval */
	u_int32 transit;        /* relative trans time for prev pkt */
	u_int32 jitter;         /* estimated jitter */
} rtp_source_t;

typedef struct rtp_source_list {
	rtp_source_t	*psrc;
	unsigned int	capacity;	/* capacity that psrc points to */
	unsigned int	size;
} rtp_source_list_t;

/** 
 * rtp structure
 */
typedef struct rtp_s {
	SOCKET sock;
	struct sockaddr_in	laddr;	/* local address */
	struct sockaddr_in	paddr;	/* peer address */

	u_int32	ssrc;			/* SSRC */
	int	err;			/* error code */
	int	auto_rtcp;		/* nonzero: auto control RTCP */
	struct rtcp_s	*rtcp;		/* pointer to RTCP structure */
	
	u_int16	last_seq;		/* last output seq # */
	
	rtp_source_list_t	srclist;	/* source information list */
} RTP;

typedef struct rtcp_s {
	SOCKET sock;
	struct sockaddr_in	laddr;	/* local address */
	struct sockaddr_in	paddr;	/* peer address */
	
	int	err;			/* error code */
} RTCP;


/**
 * RTP packet buffer
 */
typedef struct {
	char	*data;		/* pointer to payload data */
	size_t	datalen;	/* payload length */
	char	*buf;		/* packet buffer */
	size_t	buflen;		/* buffer length */
} rtp_pkt_t;

/* rtp packet parameters (host order) */
typedef struct {
	u_int32	ts;		/* timestamp */
	u_int8	m;		/* marker */
	u_int8	pt;		/* payload type */
	u_int16	seq;		/* seq. number */
	u_int32	ssrc;		/* SSRC */
	u_int32 *csrc_list;	/* CSRC list */
	u_int8	cc;		/* CSRC count */
} rtp_pkt_param_t;

#ifdef	__cplusplus
extern "C" {
#endif

/* initialize an RTP module */
int rtp_startup(void);
/* finish an RTP module */
int rtp_cleanup(void);

/*--[ RTP ]----------------------------------------------------------------*/
/* open an RTP session */
RTP *rtp_open(u_int16 port, u_int32 ssrc);
/* close an RTP session */
int rtp_close(RTP *rtp);
/* open an RTP session with an associated RTCP session */
RTP *rtp_openx(u_int16 port, u_int32 ssrc, const char *cname);

SOCKET rtp_getsocket(RTP *rtp);

/* Returns: #bytes received if ok, -1 on error */
int rtp_read(RTP *rtp, rtp_pkt_t *pkt);
int rtp_readx(RTP *rtp, rtp_pkt_t *pkt, long timeout);
/* Returns: #bytes sent if ok, -1 on error */
int rtp_write(RTP *rtp, const rtp_pkt_t *pkt);

/* Returns nonnegative event value if ok, -1 on error */
int rtp_wait(RTP *rtp, int events, long timeout);

/* RTP: set peer address */
int rtp_setpeeraddr(RTP *rtp, const char *host, u_int16 port);
int rtp_setpeeraddrx(RTP *rtp, const struct sockaddr_in *addr);

const struct sockaddr_in *rtp_getlocaladdr(RTP *rtp);
const struct sockaddr_in *rtp_getpeeraddr(RTP *rtp);
const int rtp_getlocalport(RTP *rtp);
const int rtp_getpeerport(RTP *rtp);
u_int32 rtp_getssrc(const RTP *rtp);
u_int32 rtp_setssrc(RTP *rtp, u_int32 ssrc);

/* get the data pointer from an RTP buffer */
/* char *rtp_getdataptr(char *rtpbuf, size_t ncsrc); */

/* RTP packet buffer functions */
int rtp_pkt_init(rtp_pkt_t *pkt, size_t payload_size);
int rtp_pkt_free(rtp_pkt_t *pkt);
int rtp_pkt_getparam(const rtp_pkt_t *pkt, rtp_pkt_param_t *param);
int rtp_pkt_setparam(rtp_pkt_t *pkt, const rtp_pkt_param_t *param);

/*--[ RTCP ]---------------------------------------------------------------*/
/* open an RTCP sesion */
RTCP *rtcp_open(u_int16 port, const char *cname);
/* close an RTCP session */
int rtcp_close(RTCP *rtcp);

SOCKET rtcp_getsocket(RTCP *rtcp);

/* RTCP: set peer address */
int rtcp_setpeeraddr(RTCP *rtcp, const char *host, u_int16 port);
int rtcp_setpeeraddrx(RTCP *rtcp, const struct sockaddr_in *addr);

/* get RTP error number */
int rtp_errno(const RTP *rtp);
int rtcp_errno(const RTCP *rtcp);

#ifdef	__cplusplus
}
#endif

#endif /* #ifndef __RTP_H__ */
