?? rtp.c
?? MPEG-4編解碼的實(shí)現(xiàn)(包括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:
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -