#ifndef _RTSP_H_
#define _RTSP_H_

#include "dlist.h"
#include "osdep_api.h"
#include "avcodec.h"

#define RTSP_DEBUG 0

#if RTSP_DEBUG
#define RTSP_PRINTF(fmt, args...)    printf("\n\r%s: " fmt, __FUNCTION__, ## args)
#define RTSP_ERROR(fmt, args...)    printf("\n\r%s: " fmt, __FUNCTION__, ## args)
#else
#define RTSP_PRINTF(fmt, args...)
#define RTSP_ERROR(fmt, args...)    printf("\n\r%s: " fmt, __FUNCTION__, ## args)
#endif


/*******************************************************general***************************************************************************/

struct stream_context
{	
	struct list_head payload_entry;
	_Mutex entry_lock;
	_Sema sema;
	void *protoCtx; // tranport layer protocol info.(eg.RTSP/HTTP)
	int isProcess;
        int allowStream;
        int pt; //payload type
        struct codec_info codec;
        void *priv; // pointer to private data
};

/************************************************************** start of rtsp *************************************************************/

/*rtsp command list*/
#define CMD_OPTIONS 1
#define CMD_DESCRIBE 2
#define CMD_SETUP 3
#define CMD_TEARDOWN 4
#define CMD_PLAY 5
#define CMD_PAUSE 6

/*rtsp cast mode list*/
#define UNICAST_UDP_MODE 1
#define UNICAST_TCP_MODE 2
#define MULTICAST_MODE 3

#define CRLF "\r\n"
#define BOUNDARY "amebaimagetest"
#define RTSP_RESPONSE_SIZE 	512 //max size for request/response buffer  
#define SERVER_PORT_RANGE_MIN 55608
#define SERVER_PORT_RANGE_MAX 55625
#define PORT_RANGE_MIN 50020
#define PORT_RANGE_MAX 50036

#if (SERVER_PORT_RANGE_MIN >= SERVER_PORT_RANGE_MAX) || (PORT_RANGE_MIN >= PORT_RANGE_MAX)
 #error "port range invalid"
#endif
#if ((SERVER_PORT_RANGE_MIN%2) != 0) || ((PORT_RANGE_MIN%2) != 0)
 #error "minimal port value should be even"
#endif

#define DEF_RTSP_PORT 554
#define DEF_HTTP_PORT 5008

/************************************************************** end of rtsp *************************************************************/

/************************************************************** start of rtp **************************************************************/

#define DEF_RTP_PORT 27750
#define RTP_BIG_ENDIAN 0
#define RTP_HDR_SZ 12
/*rtp payload type mapping and standard rtp payload type table*/
#define RTP_PT_PCMU     0
#define RTP_PT_GSM      3
#define RTP_PT_G723     4
#define RTP_PT_DVI4_R8000        5
#define RTP_PT_DVI4_R16000       6
#define RTP_PT_LPC      7
#define RTP_PT_PCMA     8
#define RTP_PT_G722     9
#define RTP_PT_L16_C2   10
#define RTP_PT_L16_C1   11
#define RTP_PT_QCELP    12
#define RTP_PT_CN       13
#define RTP_PT_MPA      14
#define RTP_PT_G728     15
#define RTP_PT_DVI4_R11025      16
#define RTP_PT_DVI4_R22050      17
#define RTP_PT_G719     18
#define RTP_PT_CELB     25
#define RTP_PT_JPEG     26
#define RTP_PT_NV       28
#define RTP_PT_H261     31
#define RTP_PT_MPV      32
#define RTP_PT_MP2T     33
#define RTP_PT_H263     34
#define RTP_PT_RTCP_BASE        72
#define RTP_PT_DYN_BASE         96
#undef RTP_PT_UNKNOWN
#define RTP_PT_UNKNOWN          -1

#include "section_config.h"
SDRAM_DATA_SECTION
static const struct {
     int pt; //payload type
     const char enc_name[6];
     int clock_rate;
     int audio_channels;
 } rtp_payload_types[] = {
    //{0, "PCMU", 8000, 1},
    //{3, "GSM", 8000, 1},
    //{4, "G723", 8000, 1},
    //{5, "DVI4", 8000, 1},
    //{6, "DVI4", 16000, 1},
    //{7, "LPC", 8000, 1},
    //{8, "PCMA", 8000, 1},
    //{9, "G722", 8000, 1},
    //{10, "L16", 44100, 2},
    //{11, "L16", 44100, 1},
    //{12, "QCELP", 8000, 1},
    //{13, "CN", 8000, 1},
    //{14, "MPA", -1, -1},
    //{15, "G728", 8000, 1},
    //{16, "DVI4", 11025, 1},
    //{17, "DVI4", 22050, 1},
    //{18, "G729", 8000, 1},
    //{25, "CelB", 90000, -1},
    {26, "JPEG", 90000, -1},
    //{28, "nv", 90000, -1},
    //{31, "H261", 90000, -1},
    //{32, "MPV", 90000, -1},
    //{33, "MP2T", 90000, -1},
    //{34, "H263", 90000, -1},
    {-1, "", -1, -1}
};

#define RTP_STD_PT_SIZE  /*25*/ 2      //length of rtp_payload_types 

/************************************************************** end of rtp **************************************************************/

/************************************************************** start of rtcp *************************************************************/
#define RTP_SEQ_MOD (1<<16)
#define RTP_MAX_SDES 255      /* maximum text length for SDES */

typedef enum {
  RTCP_SR   = 200,
  RTCP_RR   = 201,
  RTCP_SDES = 202,
  RTCP_BYE  = 203,
  RTCP_APP  = 204
} rtcp_type_t;

typedef enum {
  RTCP_SDES_END   = 0,
  RTCP_SDES_CNAME = 1,
  RTCP_SDES_NAME  = 2,
  RTCP_SDES_EMAIL = 3,
  RTCP_SDES_PHONE = 4,
  RTCP_SDES_LOC   = 5,
  RTCP_SDES_TOOL  = 6,
  RTCP_SDES_NOTE  = 7,
  RTCP_SDES_PRIV  = 8
} rtcp_sdes_type_t;

/************************************************************** end of rtcp *************************************************************/

/************************************************************** start of rtsp *************************************************************/

typedef enum _rtsp_state rtsp_state;
enum _rtsp_state {
    RTSP_INIT = 0,
    RTSP_READY = 1,
    RTSP_PLAYING = 2,
};

struct rtsp_session
{
        int id;
        int version;
        int start_time;
        int end_time;
        unsigned char *user;
        unsigned char *name;
};

struct rtsp_transport
{
	int isRtp; //transport protocol
	int isTcp; //lower transport protocol
	int castMode; //unicast UDP(1) or unicast TCP(2) or multicast(3)
	int port_min;
	int port_max;
	int clientport_min;
	int clientport_max;
	int serverport_min;
	int serverport_max;
	int ttl; //multicast time to live
	//to be added if necessary
};

/*sturcture to hold connect info*/
struct connect_context
{
	int socket_id;
	u16 port;
	unsigned char *server_ip;
        unsigned char *remote_ip;
};


struct rtsp_context
{
	rtsp_state state; //state for rtp streaming
	int rtsp_cmd; //store request method type
	int Cseq;
	struct rtsp_transport transport;
        struct rtsp_session session;
	u8 *response; //enough to hold response
	int content_len;
	struct connect_context connect_ctx; //contain rtsp server info.
	void *stream_ctx; //stream context it process
	_Sema start_rtp_sema; //sema to start rtp processing
        int is_rtp_start;
          //to be added if necessary
};

/************************************************************** end of rtsp *************************************************************/

/************************************************************** start of rtp **************************************************************/


/*
 * RTP data header from RFC1889
 */
/*
 *
 *
 *    The RTP header has the following format:
 *
 *  0                   1                   2                   3
 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |V=2|P|X|  CC   |M|     PT      |       sequence number         |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |                           timestamp                           |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |           synchronization source (SSRC) identifier            |
 * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
 * |            contributing source (CSRC) identifiers             |
 * |                             ....                              |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *
 * RTP data header
 */

typedef struct {
#if RTP_BIG_ENDIAN
        unsigned int version:2;   /* protocol version */
        unsigned int p:1;         /* padding flag */
        unsigned int x:1;         /* header extension flag */
        unsigned int cc:4;        /* CSRC count */
        unsigned int m:1;         /* marker bit */
        unsigned int pt:7;        /* payload type */
#else /*RTP_LITTLE_ENDIAN*/
        unsigned int cc:4;        /* CSRC count */
        unsigned int x:1;         /* header extension flag */
        unsigned int p:1;         /* padding flag */
        unsigned int version:2;   /* protocol version */
        unsigned int pt:7;        /* payload type */
        unsigned int m:1;         /* marker bit */
#endif
        u16 seq;              /* sequence number */
        u32 ts;               /* timestamp */
        u32 ssrc;             /* synchronization source */
//        u32 csrc[1];          /* optional CSRC list, skip because cc is set to 0 here*/
} rtp_hdr_t;

enum rtp_object_state
{
    RTP_OBJECT_IDLE = 1,
    RTP_OBJECT_READY,
    RTP_OBJECT_INUSE,
    RTP_OBJECT_USED,
};

struct rtp_object
{
        struct list_head rtp_list;
        _Mutex mutex;
        rtp_hdr_t rtphdr;
        u32 *extra;     //pointer to type specific structure
        int index;      
        unsigned char *data;
        int len;
        enum rtp_object_state state;    //reserved for future use
        struct connect_context connect_ctx;
};

/************************************************************** end of rtp **************************************************************/

/***************************************************************general******************************************************************/
void stream_context_init(struct stream_context *stream_ctx);
void stream_context_free(struct stream_context *stream_ctx);

/************************************************************** start of rtsp *************************************************************/

int rtsp_atoi(char * s);
int rtsp_context_init(struct rtsp_context *rtsp_ctx);
void rtsp_readheader(u8 *request_header);
u8 * rtsp_parsefield(u8 *buffer, char *field); //parse specific field line and return field data
u8 * rtsp_readline(struct rtsp_context *rtsp_ctx, u8 *ptr); //read line starting from ptr and store corresponding parameter in rtsp_ctx 
void rtsp_getparam(struct rtsp_context *rtsp_ctx, u8 *rtsp_header);
void parse_rtsp_type(struct rtsp_context *rtsp_ctx, u8 *rtsp_header);
int rtp_tick_inc_to_fps(int tick_inc, int clock_rate);
int rtp_fps_to_tick_inc(int framerate, int clock_rate);
void gen_session_id(int *session_id);
void rtsp_formSdp(struct rtsp_context *rtsp_ctx, u8 *sdp_buffer, int size);
void rtsp_cmd_options(struct rtsp_context *rtsp_ctx);
void rtsp_cmd_describe(struct rtsp_context *rtsp_ctx);
void rtsp_cmd_setup(struct rtsp_context *rtsp_ctx);
void rtsp_cmd_play(struct rtsp_context *rtsp_ctx);
void rtsp_cmd_pause(struct rtsp_context *rtsp_ctx);
void rtsp_cmd_teardown(struct rtsp_context *rtsp_ctx);
void rtsp_cmd_error(struct rtsp_context *rtsp_ctx);
void rtsp_init(void *param);

/************************************************************** end of rtsp *************************************************************/

/************************************************************** start of rtp **************************************************************/

void fillRtpHeader(rtp_hdr_t *rtphdr, int version, int padding, int extension, int cc, int marker, int pt, u16 seq, u32 ts, u32 ssrc);

/************************************************************** end of rtp **************************************************************/

#endif
