📄 rtp.c
字号:
/* 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. */ const 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. */ hname = "127.0.0.1"; } strncpy(cname + strlen(cname), hname, MAXCNAMELEN - strlen(cname)); 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, FALSE); rtp_set_option(session, RTP_OPT_FILTER_MY_PACKETS, FALSE); rtp_set_option(session, RTP_OPT_REUSE_PACKET_BUFS, 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, 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);}/** * 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){ struct rtp *session; int i, j; char *cname; if (ttl < 0) { debug_msg("ttl must be greater than zero\n"); return NULL; } if (rx_port % 2) { debug_msg("rx_port must be even\n"); return NULL; } if (tx_port % 2) { debug_msg("tx_port must be even\n"); return NULL; } session = (struct rtp *) xmalloc(sizeof(struct rtp)); memset (session, 0, 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); 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); init_opt(session); if (session->rtp_socket == NULL || session->rtcp_socket == NULL) { xfree(session); return NULL; } init_rng(udp_host_addr(session->rtp_socket)); session->my_ssrc = (uint32_t) lrand48(); 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 */ session->db[h] = s; return TRUE;}/** * rtp_set_option: * @session: The RTP session. * @optname: The option name, see #rtp_option. * @optval: The value to set. * * Sets the value of a session option. See #rtp_option for * documentation on the options and their legal values. * * Returns: TRUE on success, else FALSE. */int rtp_set_option(struct rtp *session, rtp_option optname, int optval){ assert((optval == TRUE) || (optval == FALSE)); switch (optname) { case RTP_OPT_WEAK_VALIDATION: session->opt->wait_for_rtcp = optval; break; case RTP_OPT_PROMISC: session->opt->promiscuous_mode = optval; break; case RTP_OPT_FILTER_MY_PACKETS: session->opt->filter_my_packets = optval; break; case RTP_OPT_REUSE_PACKET_BUFS: session->opt->reuse_bufs = optval; break; default: debug_msg("Ignoring unknown option (%d) in call to rtp_set_option().\n", optname); return FALSE; } return TRUE;}/** * rtp_get_option: * @session: The RTP session. * @optname: The option name, see #rtp_option. * @optval: The return value. * * Retrieves the value of a session option. See #rtp_option for * documentation on the options and their legal values. * * Returns: TRUE and the value of the option in optval on success, else FALSE. */int rtp_get_option(struct rtp *session, rtp_option optname, int *optval){ switch (optname) { case RTP_OPT_WEAK_VALIDATION: *optval = session->opt->wait_for_rtcp; break; case RTP_OPT_PROMISC: *optval = session->opt->promiscuous_mode; break; case RTP_OPT_FILTER_MY_PACKETS: *optval = session->opt->filter_my_packets; break; case RTP_OPT_REUSE_PACKET_BUFS: *optval = session->opt->reuse_bufs; break; default: *optval = 0; debug_msg("Ignoring unknown option (%d) in call to rtp_get_option().\n", optname); return FALSE; } return TRUE;}/** * rtp_get_userdata: * @session: The RTP session. * * This function returns the userdata pointer that was passed to the * rtp_init() or rtp_init_if() function when creating this session. * * Returns: pointer to userdata. */uint8_t *rtp_get_userdata(struct rtp *session){ check_database(session); return session->userdata;}/** * rtp_my_ssrc: * @session: The RTP Session. *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -