📄 rtp.c
字号:
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 255static 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);}struct rtp *rtp_init_xmitter (const char *addr, uint16_t rx_port, uint16_t tx_port, int ttl, double rtcp_bw, rtp_callback callback, uint8_t *userdata){ struct rtp *session = rtp_init(addr, rx_port, tx_port, ttl, rtcp_bw, callback, userdata); gettimeofday(&(session->next_rtcp_send_time), NULL); return session;}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 ? rx_port + 1 : 0), (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: * @session: the RTP session * @ssrc: the SSRC to be used by the RTP session * * This function coerces the local SSRC identifer to be ssrc. For * this function to succeed it must be called immediately after * rtp_init or rtp_init_if. The intended purpose of this * function is to co-ordinate SSRC's between layered sessions, it * should not be used otherwise. * * Returns: TRUE on success, FALSE otherwise. */int rtp_set_my_ssrc(struct rtp *session, uint32_t ssrc){ source *s; uint32_t h; if (session->ssrc_count != 1 && session->sender_count != 0) { return FALSE; } /* Remove existing source */ h = ssrc_hash(session->my_ssrc); s = session->db[h]; session->db[h] = NULL; /* Fill in new ssrc */ session->my_ssrc = ssrc; s->ssrc = ssrc; h = ssrc_hash(ssrc); /* Put source back */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -