⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rtp.c

📁 MPEG-4编解码的实现(包括MPEG4视音频编解码)
💻 C
📖 第 1 页 / 共 5 页
字号:
/*
 * FILE:     rtp.c
 * AUTHOR:   Colin Perkins   <csp@isi.edu>
 * MODIFIED: Orion Hodson    <o.hodson@cs.ucl.ac.uk>
 *           Markus Germeier <mager@tzi.de>
 *           Bill Fenner     <fenner@research.att.com>
 *           Timur Friedman  <timur@research.att.com>
 *
 * The routines in this file implement the Real-time Transport Protocol,
 * RTP, as specified in RFC1889 with current updates under discussion in
 * the IETF audio/video transport working group. Portions of the code are
 * derived from the algorithms published in that specification.
 *
 * $Revision: 1.24 $ 
 * $Date: 2002/07/05 22:03:53 $
 * 
 * Copyright (c) 1998-2001 University College London
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, is permitted provided that the following conditions 
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed by the Computer Science
 *      Department at University College London.
 * 4. Neither the name of the University nor of the Department may be used
 *    to endorse or promote products derived from this software without
 *    specific prior written permission.
 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 */

#include "config_unix.h"
#include "config_win32.h"
#include "memory.h"
#include "debug.h"
#include "net_udp.h"
#include "crypt_random.h"
#include "rijndael-api-fst.h"
#include "drand48.h"
#include "gettimeofday.h"
#include "qfDES.h"
#include "md5.h"
#include "ntp.h"

#include "rtp.h"
typedef struct {
        uint32_t key;   /* Original allocation number   */
        uint32_t size;  /* Size of allocation requested */
        uint32_t pad;   /* Alignment padding to 8 bytes */
        uint32_t magic; /* Magic number                 */
} chk_header;
	  extern int chk_header_okay(const chk_header *ch);

/*
 * Encryption stuff.
 */
#define MAX_ENCRYPTION_PAD 16

static int rijndael_initialize(struct rtp *session, u_char *hash, int hash_len);

static int rijndael_decrypt(void *ifptr, uint8_t *data,
		    unsigned int *size);
static int rijndael_encrypt(void *ifptr, uint8_t *data,
	    unsigned int *size);

static int des_initialize(struct rtp *session, u_char *hash, int hash_len);
static int des_decrypt(void *ifptr, uint8_t *data,
	       unsigned int *size);
static int des_encrypt(void *ifptr, uint8_t *data,
	       unsigned int *size);

#define MAX_DROPOUT    3000
#define MAX_MISORDER   100
#define MIN_SEQUENTIAL 2

/*
 * Definitions for the RTP/RTCP packets on the wire...
 */

#define RTP_SEQ_MOD        0x10000
#define RTP_MAX_SDES_LEN   256

#define RTP_LOWER_LAYER_OVERHEAD 28	/* IPv4 + UDP */

#define RTCP_SR   200
#define RTCP_RR   201
#define RTCP_SDES 202
#define RTCP_BYE  203
#define RTCP_APP  204

typedef struct {
#ifdef WORDS_BIGENDIAN
	unsigned short  version:2;	/* packet type            */
	unsigned short  p:1;		/* padding flag           */
	unsigned short  count:5;	/* varies by payload type */
	unsigned short  pt:8;		/* payload type           */
#else
	unsigned short  count:5;	/* varies by payload type */
	unsigned short  p:1;		/* padding flag           */
	unsigned short  version:2;	/* packet type            */
	unsigned short  pt:8;		/* payload type           */
#endif
	uint16_t        length;		/* packet length          */
} rtcp_common;

typedef struct {
	rtcp_common   common;	
	union {
		struct {
			rtcp_sr		sr;
			rtcp_rr       	rr[1];		/* variable-length list */
		} sr;
		struct {
			uint32_t        ssrc;		/* source this RTCP packet is coming from */
			rtcp_rr       	rr[1];		/* variable-length list */
		} rr;
		struct rtcp_sdes_t {
			uint32_t	ssrc;
			rtcp_sdes_item 	item[1];	/* list of SDES */
		} sdes;
		struct {
			uint32_t        ssrc[1];	/* list of sources */
							/* can't express the trailing text... */
		} bye;
		struct {
			uint32_t        ssrc;           
			uint8_t         name[4];
			uint8_t         data[1];
		} app;
	} r;
} rtcp_t;

typedef struct _rtcp_rr_wrapper {
	struct _rtcp_rr_wrapper	*next;
	struct _rtcp_rr_wrapper	*prev;
        uint32_t                 reporter_ssrc;
	rtcp_rr			*rr;
	struct timeval		*ts;	/* Arrival time of this RR */
} rtcp_rr_wrapper;

/*
 * The RTP database contains source-specific information needed 
 * to make it all work. 
 */

typedef struct _source {
	struct _source	*next;
	struct _source	*prev;
	uint32_t	 ssrc;
	char		*cname;
	char		*name;
	char		*email;
	char		*phone;
	char		*loc;
	char		*tool;
	char		*note;
	char		*priv;
	rtcp_sr		*sr;
	struct timeval	 last_sr;
	struct timeval	 last_active;
	int		 should_advertise_sdes;	/* TRUE if this source is a CSRC which we need to advertise SDES for */
	int		 sender;
	int		 got_bye;		/* TRUE if we've received an RTCP bye from this source */
	uint32_t	 base_seq;
	uint16_t	 max_seq;
	uint32_t	 bad_seq;
	uint32_t	 cycles;
	int		 received;
	int		 received_prior;
	int		 expected_prior;
	int		 probation;
	uint32_t	 jitter;
	uint32_t	 transit;
	uint32_t	 magic;			/* For debugging... */
} source;

/* The size of the hash table used to hold the source database. */
/* Should be large enough that we're unlikely to get collisions */
/* when sources are added, but not too large that we waste too  */
/* much memory. Sedgewick ("Algorithms", 2nd Ed, Addison-Wesley */
/* 1988) suggests that this should be around 1/10th the number  */
/* of entries that we expect to have in the database and should */
/* be a prime number. Everything continues to work if this is   */
/* too low, it just goes slower... for now we assume around 100 */
/* participants is a sensible limit so we set this to 11.       */   
#define RTP_DB_SIZE	11

/*
 *  Options for an RTP session are stored in the "options" struct.
 */

typedef struct {
	int 	promiscuous_mode;
	int	wait_for_rtcp;
	int	filter_my_packets;
} options;

/*
 * Encryption function types
 */

// moved to rtp.h by nori
/*
 * typedef int (*rtp_encrypt_func)(struct rtp *, unsigned char *data,
 *				unsigned int size);
 *
 * typedef int (*rtp_decrypt_func)(struct rtp *, unsigned char *data,
 *				unsigned int size);
 */
typedef int (*rtcp_send_f)(struct rtp *s, uint8_t *buffer, int buflen);

/*
 * The "struct rtp" defines an RTP session.
 */

struct rtp {
	socket_udp	*rtp_socket;
	socket_udp	*rtcp_socket;
	char		*addr;
	uint16_t	 rx_port;
	uint16_t	 tx_port;
	int		 ttl;
	uint32_t	 my_ssrc;
	int		 last_advertised_csrc;
	source		*db[RTP_DB_SIZE];
        rtcp_rr_wrapper  rr[RTP_DB_SIZE][RTP_DB_SIZE]; 	/* Indexed by [hash(reporter)][hash(reportee)] */
	options		*opt;
	uint8_t		*userdata;
	int		 invalid_rtp_count;
	int		 invalid_rtcp_count;
	int		 bye_count;
	int		 csrc_count;
	int		 ssrc_count;
	int		 ssrc_count_prev;		/* ssrc_count at the time we last recalculated our RTCP interval */
	int		 sender_count;
	int		 initial_rtcp;
	int		 sending_bye;			/* TRUE if we're in the process of sending a BYE packet */
	double		 avg_rtcp_size;
	int		 we_sent;
	double		 rtcp_bw;			/* RTCP bandwidth fraction, in octets per second. */
	struct timeval	 last_update;
	struct timeval	 last_rtp_send_time;
	struct timeval	 last_rtcp_send_time;
	struct timeval	 next_rtcp_send_time;
	double		 rtcp_interval;
	int		 sdes_count_pri;
	int		 sdes_count_sec;
	int		 sdes_count_ter;
	uint16_t	 rtp_seq;
	uint32_t	 rtp_pcount;
	uint32_t	 rtp_bcount;
    char *encryption_algorithm;
 	int encryption_enabled;
 	rtp_encrypt_func encrypt_func;
 	rtp_decrypt_func decrypt_func;
 	int encryption_pad_length;
  int encryption_lenadd;
  void *encrypt_userdata; // added by nori
 	union {
 		struct {
 			keyInstance keyInstEncrypt;
 			keyInstance keyInstDecrypt;
 			cipherInstance cipherInst;
 		} rijndael;
 		struct {
 			char            *encryption_key;
 		} des;
 	} crypto_state;
	rtp_callback	 callback;
  rtcp_send_f rtcp_send;
  rtcp_send_packet_t rtcp_send_packet;
	uint32_t	 magic;				/* For debugging...  */
};

static int filter_event(struct rtp *session, uint32_t ssrc)
{
	int	filter;

	rtp_get_option(session, RTP_OPT_FILTER_MY_PACKETS, &filter);
	return filter && (ssrc == rtp_my_ssrc(session));
}

static double tv_diff(struct timeval curr_time, struct timeval prev_time)
{
    /* Return curr_time - prev_time */
    double	ct, pt;

    ct = (double) curr_time.tv_sec + (((double) curr_time.tv_usec) / 1000000.0);
    pt = (double) prev_time.tv_sec + (((double) prev_time.tv_usec) / 1000000.0);
    return (ct - pt);
}

static void tv_add(struct timeval *ts, double offset)
{
	/* Add offset seconds to ts */
	double offset_sec, offset_usec;

	offset_usec = modf(offset, &offset_sec) * 1000000;
	ts->tv_sec  += (long) offset_sec;
	ts->tv_usec += (long) offset_usec;
	if (ts->tv_usec > 1000000) {
		ts->tv_sec++;
		ts->tv_usec -= 1000000;
	}
}

static int tv_gt(struct timeval a, struct timeval b)
{
	/* Returns (a>b) */
	if (a.tv_sec > b.tv_sec) {
		return TRUE;
	}
	if (a.tv_sec < b.tv_sec) {
		return FALSE;
	}
	ASSERT(a.tv_sec == b.tv_sec);
	return a.tv_usec > b.tv_usec;
}

static uint32_t next_csrc(struct rtp *session)
{
	/* This returns each source marked "should_advertise_sdes" in turn. */
	int	 chain, cc;
	source	*s;

	cc = 0;
	for (chain = 0; chain < RTP_DB_SIZE; chain++) {
		/* Check that the linked lists making up the chains in */
		/* the hash table are correctly linked together...     */
		for (s = session->db[chain]; s != NULL; s = s->next) {
			if (s->should_advertise_sdes) {
				if (cc == session->last_advertised_csrc) {
                                        session->last_advertised_csrc++;
                                        if (session->last_advertised_csrc == session->csrc_count) {
                                                session->last_advertised_csrc = 0;
                                        }
					return s->ssrc;
				} else {
					cc++;
				}
			}
		}
	}
	/* We should never get here... */
	abort();
}

static int ssrc_hash(uint32_t ssrc)
{
	/* Hash from an ssrc to a position in the source database.   */
	/* Assumes that ssrc values are uniformly distributed, which */
	/* should be true but probably isn't (Rosenberg has reported */
	/* that many implementations generate ssrc values which are  */
	/* not uniformly distributed over the space, and the H.323   */
	/* spec requires that they are non-uniformly distributed).   */
	/* This routine is written as a function rather than inline  */
	/* code to allow it to be made smart in future: probably we  */
	/* should run MD5 on the ssrc and derive a hash value from   */
	/* that, to ensure it's more uniformly distributed?          */
	return ssrc % RTP_DB_SIZE;
}

static void insert_rr(struct rtp *session, uint32_t reporter_ssrc, rtcp_rr *rr, struct timeval *ts)
{
        /* Insert the reception report into the receiver report      */
        /* database. This database is a two dimensional table of     */
        /* rr_wrappers indexed by hashes of reporter_ssrc and        */
        /* reportee_src.  The rr_wrappers in the database are        */
        /* sentinels to reduce conditions in list operations.        */
	/* The ts is used to determine when to timeout this rr.      */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -