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

📄 rtp.c

📁 MPEG-4编解码的实现(包括MPEG4视音频编解码)
💻 C
📖 第 1 页 / 共 5 页
字号:
				s->max_seq = seq;
		  }
		  return 0;
	} else if (udelta < MAX_DROPOUT) {
		  /* in order, with permissible gap */
		  if (seq < s->max_seq) {
				/*
				 * Sequence number wrapped - count another 64K cycle.
				 */
				s->cycles += RTP_SEQ_MOD;
		  }
		  s->max_seq = seq;
	} else if (udelta <= RTP_SEQ_MOD - MAX_MISORDER) {
		  /* the sequence number made a very large jump */
		  if (seq == s->bad_seq) {
				/*
				 * Two sequential packets -- assume that the other side
				 * restarted without telling us so just re-sync
				 * (i.e., pretend this was the first packet).
				 */
				init_seq(s, seq);
		  } else {
				s->bad_seq = (seq + 1) & (RTP_SEQ_MOD-1);
				return 0;
		  }
	} else {
		  /* duplicate or reordered packet */
	}
	s->received++;
	return 1;
}

static double rtcp_interval(struct rtp *session)
{
	/* Minimum average time between RTCP packets from this site (in   */
	/* seconds).  This time prevents the reports from `clumping' when */
	/* sessions are small and the law of large numbers isn't helping  */
	/* to smooth out the traffic.  It also keeps the report interval  */
	/* from becoming ridiculously small during transient outages like */
	/* a network partition.                                           */
	double const RTCP_MIN_TIME = 5.0;
	/* Fraction of the RTCP bandwidth to be shared among active       */
	/* senders.  (This fraction was chosen so that in a typical       */
	/* session with one or two active senders, the computed report    */
	/* time would be roughly equal to the minimum report time so that */
	/* we don't unnecessarily slow down receiver reports.) The        */
	/* receiver fraction must be 1 - the sender fraction.             */
	double const RTCP_SENDER_BW_FRACTION = 0.25;
	double const RTCP_RCVR_BW_FRACTION   = (1-RTCP_SENDER_BW_FRACTION);
	/* To compensate for "unconditional reconsideration" converging   */
	/* to a value below the intended average.                         */
	double const COMPENSATION            = 2.71828 - 1.5;

	double t;				              /* interval */
	double rtcp_min_time = RTCP_MIN_TIME;
	int n;			        /* no. of members for computation */
	double rtcp_bw = session->rtcp_bw;

	/* Very first call at application start-up uses half the min      */
	/* delay for quicker notification while still allowing some time  */
	/* before reporting for randomization and to learn about other    */
	/* sources so the report interval will converge to the correct    */
	/* interval more quickly.                                         */
	if (session->initial_rtcp) {
		rtcp_min_time /= 2;
	}

	/* If there were active senders, give them at least a minimum     */
	/* share of the RTCP bandwidth.  Otherwise all participants share */
	/* the RTCP bandwidth equally.                                    */
	if (session->sending_bye) {
		n = session->bye_count;
	} else {
		n = session->ssrc_count;
	}
	if (session->sender_count > 0 && session->sender_count < n * RTCP_SENDER_BW_FRACTION) {
		if (session->we_sent) {
			rtcp_bw *= RTCP_SENDER_BW_FRACTION;
			n = session->sender_count;
		} else {
			rtcp_bw *= RTCP_RCVR_BW_FRACTION;
			n -= session->sender_count;
		}
	}

	/* The effective number of sites times the average packet size is */
	/* the total number of octets sent when each site sends a report. */
	/* Dividing this by the effective bandwidth gives the time        */
	/* interval over which those packets must be sent in order to     */
	/* meet the bandwidth target, with a minimum enforced.  In that   */
	/* time interval we send one report so this time is also our      */
	/* average time between reports.                                  */
	t = session->avg_rtcp_size * n / rtcp_bw;
	if (t < rtcp_min_time) {
		t = rtcp_min_time;
	}
	session->rtcp_interval = t;

	/* To avoid traffic bursts from unintended synchronization with   */
	/* other sites, we then pick our actual next report interval as a */
	/* random number uniformly distributed between 0.5*t and 1.5*t.   */
	return (t * (drand48() + 0.5)) / COMPENSATION;
}

#define MAXCNAMELEN	255

static char *get_cname(socket_udp *s)
{
        /* Set the CNAME. This is "user@hostname" or just "hostname" if the username cannot be found. */
        char              *hname;
        char                    *uname;
        char                    *cname;
#ifndef WIN32
        struct passwd           *pwent;
#else
        char *name;
        int   namelen;
#endif

        cname = (char *) xmalloc(MAXCNAMELEN + 1);
        cname[0] = '\0';

        /* First, fill in the username... */
#ifdef WIN32
        name = NULL;
        namelen = 0;
        GetUserName(NULL, &namelen);
        if (namelen > 0) {
                name = (char*)xmalloc(namelen+1);
                GetUserName(name, &namelen);
        } else {
                uname = getenv("USER");
                if (uname != NULL) {
                        name = xstrdup(uname);
                }
        }
        if (name != NULL) {
                strncpy(cname, name, MAXCNAMELEN - 1);
                strcat(cname, "@");
                xfree(name);
        }
#else
        pwent = getpwuid(getuid());
        uname = pwent->pw_name;
        if (uname != NULL) {
                strncpy(cname, uname, MAXCNAMELEN - 1);
                strcat(cname, "@");
        }

#endif
        
        /* Now the hostname. Must be dotted-quad IP address. */
        hname = udp_host_addr(s);
	if (hname == NULL) {
		/* If we can't get our IP address we use the loopback address... */
		/* This is horrible, but it stops the code from failing.         */
	  strncpy(cname + strlen(cname),
		  "127.0.0.1",
		  MAXCNAMELEN - strlen(cname));
	} else {
	  strncpy(cname + strlen(cname), hname, MAXCNAMELEN - strlen(cname));
	  xfree(hname);
	}
        return cname;
}

static void init_opt(struct rtp *session)
{
	/* Default option settings. */
	rtp_set_option(session, RTP_OPT_PROMISC,           FALSE);
	rtp_set_option(session, RTP_OPT_WEAK_VALIDATION,   TRUE);
	rtp_set_option(session, RTP_OPT_FILTER_MY_PACKETS, FALSE);
}

static void init_rng(const char *s)
{
        static uint32_t seed;
	if (s == NULL) s = "ARANDOMSTRINGSOWEDONTCOREDUMP";
        if (seed == 0) {
                pid_t p = getpid();
		int32_t i, n;
                while (*s) {
                        seed += (uint32_t)*s++;
                        seed = seed * 31 + 1;
                }
                seed = 1 + seed * 31 + (uint32_t)p;
                srand48(seed);
		/* At time of writing we use srand48 -> srand on Win32
                   which is only 16 bit. lrand48 -> rand which is only
                   15 bits, step a long way through table seq */
#ifdef WIN32
		n = (seed >> 16) & 0xffff;
		for(i = 0; i < n; i++) {
			seed = lrand48();
		}
#endif /* WIN32 */
		UNUSED(i);
		UNUSED(n);
	}
}

/* See rtp_init_if(); calling rtp_init() is just like calling
 * rtp_init_if() with a NULL interface argument.
 */

/**
 * rtp_init:
 * @addr: IP destination of this session (unicast or multicast),
 * as an ASCII string.  May be a host name, which will be looked up,
 * or may be an IPv4 dotted quad or IPv6 literal adddress.
 * @rx_port: The port to which to bind the UDP socket
 * @tx_port: The port to which to send UDP packets
 * @ttl: The TTL with which to send multicasts
 * @rtcp_bw: The total bandwidth (in units of bytes per second) that is
 * allocated to RTCP.
 * @callback: See section on #rtp_callback.
 * @userdata: Opaque data associated with the session.  See
 * rtp_get_userdata().
 *
 *
 * Returns: An opaque session identifier to be used in future calls to
 * the RTP library functions, or NULL on failure.
 */
struct rtp *rtp_init(const char *addr, 
		     uint16_t rx_port, uint16_t tx_port, 
		     int ttl, double rtcp_bw, 
                     rtp_callback callback,
                     uint8_t *userdata)
{
	return rtp_init_if(addr, NULL, rx_port, tx_port, ttl, rtcp_bw, callback, userdata, 0);
}

static int rtcp_local_send (struct rtp *session, uint8_t *buffer, int buflen)
{
  return (session->rtcp_send_packet)(session->userdata, buffer, buflen);
}

static int rtcp_udp_send (struct rtp *session, uint8_t *buffer, int buflen)
{
  return (udp_send(session->rtcp_socket, buffer, buflen));
}

struct rtp *rtp_init_extern_net (const char *addr, 
				 uint16_t rx_port, uint16_t tx_port, 
				 int ttl, double rtcp_bw, 
				 rtp_callback callback,
				 rtcp_send_packet_t rtcp_send_packet,
				 uint8_t *userdata)
{
  rtp_t rtp_ptr = rtp_init_if(addr, NULL, rx_port, tx_port, ttl, rtcp_bw, callback, userdata, 1);
  if (rtp_ptr == NULL) return NULL;
  rtp_ptr->rtcp_send = rtcp_local_send;
  rtp_ptr->rtcp_send_packet = rtcp_send_packet;
  return (rtp_ptr);
}
/**
 * rtp_init_if:
 * @addr: IP destination of this session (unicast or multicast),
 * as an ASCII string.  May be a host name, which will be looked up,
 * or may be an IPv4 dotted quad or IPv6 literal adddress.
 * @iface: If the destination of the session is multicast,
 * the optional interface to bind to.  May be NULL, in which case
 * the default multicast interface as determined by the system
 * will be used.
 * @rx_port: The port to which to bind the UDP socket
 * @tx_port: The port to which to send UDP packets
 * @ttl: The TTL with which to send multicasts
 * @rtcp_bw: The total bandwidth (in units of ___) that is
 * allocated to RTCP.
 * @callback: See section on #rtp_callback.
 * @userdata: Opaque data associated with the session.  See
 * rtp_get_userdata().
 *
 * Creates and initializes an RTP session.
 *
 * Returns: An opaque session identifier to be used in future calls to
 * the RTP library functions, or NULL on failure.
 */
struct rtp *rtp_init_if(const char *addr, char *iface, 
			uint16_t rx_port, uint16_t tx_port, 
			int ttl, double rtcp_bw, 
                        rtp_callback callback,
                        uint8_t *userdata,
			int dont_init_sockets)
{
	struct rtp 	*session;
	int         	 i, j;
	char		*cname;
	char *hname;

        if (ttl < 0) {
                rtp_message(LOG_CRIT, "ttl must be greater than zero");
                return NULL;
        }
        if (rx_port % 2) {
                rtp_message(LOG_CRIT, "rx_port must be even");
                return NULL;
        }
        if (tx_port % 2) {
                rtp_message(LOG_CRIT, "tx_port must be even");
                return NULL;
        }

	session 		= (struct rtp *) xmalloc(sizeof(struct rtp));
	session->magic		= 0xfeedface;
	session->opt		= (options *) xmalloc(sizeof(options));
	session->userdata	= userdata;
	session->addr		= xstrdup(addr);
	session->rx_port	= rx_port;
	session->tx_port	= tx_port;
	session->ttl		= min(ttl, 127);

	init_opt(session);

	if (dont_init_sockets == 0) {
	  session->rtp_socket	= udp_init_if(addr, iface, rx_port, tx_port, ttl);
	  session->rtcp_socket	= udp_init_if(addr, iface, (uint16_t) (rx_port+1), (uint16_t) (tx_port+1), ttl);
	  if (session->rtp_socket == NULL || session->rtcp_socket == NULL) {
	    xfree(session);
	    return NULL;
	  }
	} else {
	  session->rtp_socket = NULL;
	  session->rtcp_socket = NULL;
	}

	hname = udp_host_addr(session->rtp_socket);
        init_rng(hname);
	if (hname != NULL) {
	  xfree(hname);
	}

	session->my_ssrc            = (uint32_t) lrand48();
	session->rtcp_send          = rtcp_udp_send;
	session->callback           = callback;
	session->invalid_rtp_count  = 0;
	session->invalid_rtcp_count = 0;
	session->bye_count          = 0;
	session->csrc_count         = 0;
	session->ssrc_count         = 0;
	session->ssrc_count_prev    = 0;
	session->sender_count       = 0;
	session->initial_rtcp       = TRUE;
	session->sending_bye        = FALSE;
	session->avg_rtcp_size      = -1;	/* Sentinal value: reception of first packet starts initial value... */
	session->we_sent            = FALSE;
	session->rtcp_bw            = rtcp_bw;
	session->sdes_count_pri     = 0;
	session->sdes_count_sec     = 0;
	session->sdes_count_ter     = 0;
	session->rtp_seq            = (uint16_t) lrand48();
	session->rtp_pcount         = 0;
	session->rtp_bcount         = 0;
	gettimeofday(&(session->last_update), NULL);
	gettimeofday(&(session->last_rtcp_send_time), NULL);
	gettimeofday(&(session->next_rtcp_send_time), NULL);
        session->encryption_enabled = 0;
	session->encryption_algorithm = NULL;

	/* Calculate when we're supposed to send our first RTCP packet... */
	tv_add(&(session->next_rtcp_send_time), rtcp_interval(session));

	/* Initialise the source database... */
	for (i = 0; i < RTP_DB_SIZE; i++) {
		session->db[i] = NULL;
	}
	session->last_advertised_csrc = 0;

        /* Initialize sentinels in rr table */
        for (i = 0; i < RTP_DB_SIZE; i++) {
                for (j = 0; j < RTP_DB_SIZE; j++) {
                        session->rr[i][j].next = &session->rr[i][j];
                        session->rr[i][j].prev = &session->rr[i][j];
                }
        }

	/* Create a database entry for ourselves... */
	create_source(session, session->my_ssrc, FALSE);
	cname = get_cname(session->rtp_socket);
	rtp_set_sdes(session, session->my_ssrc, RTCP_SDES_CNAME, cname, strlen(cname));
	xfree(cname);	/* cname is copied by rtp_set_sdes()... */

	return session;
}


/**
 * rtp_set_my_ssrc:

⌨️ 快捷键说明

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