📄 rtp.c
字号:
* 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 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) { /* This should never happen, but just in case */ s = "ARANDOMSTRINGSOWEDONTCOREDUMP"; } if (seed == 0) { pid_t p = getpid(); int32_t i = 0, n = 0; 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); }}rtp_stream_params_t *rtp_default_params (rtp_stream_params_t *ptr){ if (ptr == NULL) { ptr = (rtp_stream_params_t *)malloc(sizeof(rtp_stream_params_t)); } memset(ptr, 0, sizeof(*ptr)); ptr->rtp_socket = NULL; ptr->rtcp_socket = NULL; return ptr;}/* 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_f callback, void *userdata){ rtp_stream_params_t rsp; rtp_default_params(&rsp); rsp.rtp_addr = addr; rsp.rtp_rx_port = rx_port; rsp.rtp_tx_port = tx_port; rsp.rtp_ttl = ttl; rsp.rtcp_bandwidth = rtcp_bw; rsp.rtp_callback = callback; rsp.recv_userdata = userdata; return rtp_init_stream(&rsp);}#if 0// not used any more - use rtp_init_stream with transmit_initial_rtcp = 1struct rtp *rtp_init_xmitter (const char *addr, uint16_t rx_port, uint16_t tx_port, int ttl, double rtcp_bw, rtp_callback_f callback, void *userdata){ rtp_stream_params_t rsp; rtp_default_params(&rsp); rsp.rtp_addr = addr; rsp.rtp_rx_port = rx_port; rsp.rtp_tx_port = tx_port; rsp.rtp_ttl = ttl; rsp.rtcp_bandwidth = rtcp_bw; rsp.rtp_callback = callback; rsp.recv_userdata = userdata; rsp.transmit_initial_rtcp = 1; return rtp_init_stream(&rsp);}#endif/** * 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_f callback, void *userdata, int dont_init_sockets){ rtp_stream_params_t rsp; rtp_default_params(&rsp); rsp.physical_interface_addr = iface; rsp.rtp_addr = addr; rsp.rtp_tx_port = tx_port; rsp.rtp_rx_port = rx_port; rsp.rtp_ttl = ttl; rsp.rtcp_bandwidth = rtcp_bw; rsp.rtp_callback = callback; rsp.recv_userdata = userdata; rsp.dont_init_sockets = dont_init_sockets; return rtp_init_stream(&rsp);}rtp_t rtp_init_stream (rtp_stream_params_t *rsp){ struct rtp *session; int i, j; char *cname; char *hname; session = (struct rtp *) xmalloc(sizeof(struct rtp)); memset(session, 0, sizeof(*session)); session->magic = 0xfeedface; session->opt = (options *) xmalloc(sizeof(options)); session->recv_userdata = rsp->recv_userdata; session->send_userdata = rsp->send_userdata != NULL ? rsp->send_userdata : rsp->recv_userdata; session->addr = rsp->rtp_addr != NULL ? xstrdup(rsp->rtp_addr) : NULL; session->rx_port = rsp->rtp_rx_port; session->tx_port = rsp->rtp_tx_port; session->ttl = min(rsp->rtp_ttl, 127); init_opt(session); if (rsp->dont_init_sockets == 0) { session->udp_session = udp_init_for_session(); session->rtp_socket = udp_init_if(rsp->rtp_addr, rsp->physical_interface_addr, rsp->rtp_rx_port, rsp->rtp_tx_port, rsp->rtp_ttl); if (rsp->rtcp_addr == NULL) rsp->rtcp_addr = rsp->rtp_addr; if (rsp->rtcp_rx_port == 0) { rsp->rtcp_rx_port = rsp->rtp_rx_port ? rsp->rtp_rx_port + 1 : 0; } if (rsp->rtcp_tx_port == 0) { rsp->rtcp_tx_port = rsp->rtp_tx_port + 1; } if (rsp->rtcp_ttl == 0) rsp->rtcp_ttl = rsp->rtp_ttl; session->rtcp_socket = udp_init_if(rsp->rtcp_addr, rsp->physical_interface_addr, rsp->rtcp_rx_port, rsp->rtcp_tx_port, rsp->rtcp_ttl); if (session->udp_session == NULL || session->rtp_socket == NULL || session->rtcp_socket == NULL) { xfree(session); return NULL; } session->free_sockets = 1; } else { session->free_sockets = 0; session->rtp_socket = rsp->rtp_socket; session->rtcp_socket = rsp->rtcp_socket; } hname = udp_host_addr(session->rtp_socket); init_rng(hname); if (hname != NULL) { xfree(hname); } session->my_ssrc = (uint32_t) lrand48(); session->rtcp_send_packet = rsp->rtcp_send_packet; session->rtp_send_packet = rsp->rtp_send_packet;#ifdef HAVE_STRUCT_IOVEC session->rtp_send_packet_iov= rsp->rtp_send_packet_iov;#endif if (rsp->rtp_callback == NULL) { session->callback = local_callback; } else { session->callback = rsp->rtp_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 = rsp->rtcp_bandwidth; 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->rtp_encryption_enabled = 0; session->rtcp_encryption_enabled = 0; session->encryption_algorithm = NULL; session->mutex = MutexCreate();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -