📄 rtp.c
字号:
session->use_mutex = 1; /* Calculate when we're supposed to send our first RTCP packet... */ if (rsp->transmit_initial_rtcp == 0) { tv_add(&(session->next_rtcp_send_time), rtcp_interval(session)); } else { session->last_rtcp_send_time.tv_sec -= 100; } /* 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); lock_mutex(session); 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; unlock_mutex(session); 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; default: rtp_message(LOG_ALERT, "Ignoring unknown option (%d) in call to rtp_set_option().", 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; default: *optval = 0; rtp_message(LOG_ALERT, "Ignoring unknown option (%d) in call to rtp_get_option().", 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. */void *rtp_get_recv_userdata(struct rtp *session){ check_database(session); return session->recv_userdata;}/** * rtp_my_ssrc: * @session: The RTP Session. * * Returns: The SSRC we are currently using in this session. Note that our * SSRC can change at any time (due to collisions) so applications must not * store the value returned, but rather should call this function each time * they need it. */uint32_t rtp_my_ssrc(struct rtp *session){ check_database(session); return session->my_ssrc;}static void process_rtp(struct rtp *session, uint32_t curr_rtp_ts, rtp_packet *packet, source *s){ int i, d, transit; rtp_event event; struct timeval event_ts; if (packet->rtp_pak_cc > 0) { for (i = 0; i < packet->rtp_pak_cc; i++) { create_source(session, packet->rtp_csrc[i], FALSE); } } /* Update the source database... */ if (s->sender == FALSE) { s->sender = TRUE; session->sender_count++; } transit = curr_rtp_ts - packet->rtp_pak_ts; d = transit - s->transit; s->transit = transit; if (d < 0) { d = -d; } s->jitter += d - ((s->jitter + 8) / 16); /* Callback to the application to process the packet... */ if (!filter_event(session, packet->rtp_pak_ssrc)) { gettimeofday(&event_ts, NULL); event.ssrc = packet->rtp_pak_ssrc; event.type = RX_RTP; event.data = (void *) packet; /* The callback function MUST free this! */ event.ts = &event_ts; session->callback(session, &event); }}static int validate_rtp2(rtp_packet *packet, int len){ /* Check for valid payload types..... 72-76 are RTCP payload type numbers, with */ /* the high bit missing so we report that someone is running on the wrong port. */ if (packet->rtp_pak_pt >= 72 && packet->rtp_pak_pt <= 76) { debug_msg("rtp_header_validation: payload-type invalid"); if (packet->rtp_pak_m) { debug_msg(" (RTCP packet on RTP port?)"); } debug_msg("\n"); return FALSE; } /* Check that the length of the packet is sensible... */ if (len < (12 + (4 * packet->rtp_pak_cc))) { debug_msg("rtp_header_validation: packet length is smaller than the header\n"); return FALSE; } /* Check that the amount of padding specified is sensible. */ /* Note: have to include the size of any extension header! */ if (packet->rtp_pak_p) { int payload_len = len - 12 - (packet->rtp_pak_cc * 4); if (packet->rtp_pak_x) { /* extension header and data */ payload_len -= 4 * (1 + packet->rtp_extn_len); } if (packet->rtp_data[packet->rtp_data_len - 1] > payload_len) { debug_msg("rtp_header_validation: padding greater than payload length\n"); return FALSE; } if (packet->rtp_data[packet->rtp_data_len - 1] < 1) { debug_msg("rtp_header_validation: padding zero\n"); return FALSE; } } return TRUE;}static int validate_rtp(struct rtp *session, rtp_packet *packet, int len){ /* This function checks the header info to make sure that the packet */ /* is valid. We return TRUE if the packet is valid, FALSE otherwise. */ /* See Appendix A.1 of the RTP specification. */ /* We only accept RTPv2 packets... */ if (packet->rtp_pak_v != 2) { rtp_message(LOG_WARNING, "rtp_header_validation: v != 2"); return FALSE; } if (!session->opt->wait_for_rtcp) { /* We prefer speed over accuracy... */ return TRUE; } return validate_rtp2(packet, len);}int rtp_process_recv_data (struct rtp *session, uint32_t curr_rtp_ts, rtp_packet *packet){ uint8_t *buffer; uint32_t buflen; source *s; int srtp_status; buffer = packet->packet_start; buflen = packet->packet_length; packet->pd.ph = (rtp_packet_header *)buffer; if (buflen > 0) { if (session->rtp_encryption_enabled) { srtp_status = (session->rtp_decrypt_func)(session->encrypt_userdata, buffer, &buflen); if (srtp_status == FALSE) return -1; packet->packet_length = buflen; } /* Convert header fields to host byte order... */ packet->rtp_next = packet->rtp_prev = NULL; packet->rtp_pak_seq = ntohs(packet->rtp_pak_seq); packet->rtp_pak_ts = ntohl(packet->rtp_pak_ts); packet->rtp_pak_ssrc = ntohl(packet->rtp_pak_ssrc); /* Setup internal pointers, etc... */ if (packet->rtp_pak_cc) { int i; packet->rtp_csrc = (uint32_t *)(buffer + 12); for (i = 0; i < packet->rtp_pak_cc; i++) { packet->rtp_csrc[i] = ntohl(packet->rtp_csrc[i]); } } else { packet->rtp_csrc = NULL; } if (packet->rtp_pak_x) { packet->rtp_extn = buffer + 12 + (packet->rtp_pak_cc * 4); packet->rtp_extn_len = (packet->rtp_extn[2] << 8) | packet->rtp_extn[3]; packet->rtp_extn_type = (packet->rtp_extn[0] << 8) | packet->rtp_extn[1]; } else { packet->rtp_extn = NULL; packet->rtp_extn_len = 0; packet->rtp_extn_type = 0; } packet->rtp_data = buffer + 12 + (packet->rtp_pak_cc * 4); packet->rtp_data_len = buflen - (packet->rtp_pak_cc * 4) - 12; if (packet->rtp_extn != NULL) { packet->rtp_data += ((packet->rtp_extn_len + 1) * 4); packet->rtp_data_len -= ((packet->rtp_extn_len + 1) * 4); } if (validate_rtp(session, packet, buflen)) { if (session->opt->wait_for_rtcp) { s = create_source(session, packet->rtp_pak_ssrc, TRUE); } else { s = get_source(session, packet->rtp_pak_ssrc); } if (session->opt->promiscuous_mode) { if (s == NULL) { s = create_source(session, packet->rtp_pak_ssrc, FALSE); // redundant - s = get_source(session, packet->rtp_pak_ssrc); } if (s->probation == -1) { s->probation = MIN_SEQUENTIAL; s->max_seq = packet->rtp_pak_seq - 1; } update_seq(s, packet->rtp_pak_seq); process_rtp(session, curr_rtp_ts, packet, s); return 0; /* We don't free "packet", that's done by the callback function... */ } if (s != NULL) { if (s->probation == -1) { s->probation = MIN_SEQUENTIAL; s->max_seq = packet->rtp_pak_seq - 1; } if (update_seq(s, packet->rtp_pak_seq)) { process_rtp(session, curr_rtp_ts, packet, s); return 0; /* we don't free "packet", that's done by the callback function... */ } else { /* This source is still on probation... */ rtp_message(LOG_INFO, "RTP packet from probationary source ignored..."); } } else { rtp_message(LOG_WARNING, "RTP packet from unknown source %d ignored", packet->rtp_pak_ssrc); } } else { session->invalid_rtp_count++; rtp_message(LOG_INFO, "Invalid RTP packet discarded"); } } return -1; /* We need to free the packet */}void rtp_recv_data(struct rtp *session, uint32_t curr_rtp_ts){ /* This routine preprocesses an incoming RTP packet, deciding whether to process it. */ rtp_packet *packet = (rtp_packet *) xmalloc(RTP_MAX_PACKET_LEN + RTP_PACKET_HEADER_SIZE); uint8_t *buffer = ((uint8_t *) packet) + RTP_PACKET_HEADER_SIZE; uint32_t buflen; buflen = udp_recv(session->rtp_socket, buffer, RTP_MAX_PACKET_LEN); packet->packet_start = buffer; packet->packet_length = buflen; if (rtp_process_recv_data(session, curr_rtp_ts, packet) < 0) xfree(packet);}static int validate_rtcp(uint8_t *packet, uint32_t len){ /* Validity check for a compound RTCP packet. This function returns */ /* TRUE if the packet is okay, FALSE if the validity check fails. */ /* */ /* The following checks can be applied to RTCP packets [RFC1889]: */ /* o RTP version field must equal 2. */ /* o The payload type field of the first RTCP packet in a compound */ /* packet must be equal to SR or RR. */ /* o The padding bit (P) should be zero for the first packet of a */ /* compound RTCP packet because only the last should possibly */ /* need padding. */ /* o The length fields of the individual RTCP packets must total to */ /* the overall length of the compound RTCP packet as received. */ rtcp_t *pkt = (rtcp_t *) packet; rtcp_t *end = (rtcp_t *) (((char *) pkt) + len); rtcp_t *r = pkt; uint32_t l = 0; int pc = 1; int p = 0; uint32_t rtcp_len = (ntohs(pkt->common.length) + 1) * 4; /* All RTCP packets must be compound packets (RFC1889, section 6.1) */ if (rtcp_len == len) { rtp_message(LOG_WARNING, "Bogus RTCP packet: not a compound packet"); return FALSE; } /* Check the RTCP version, payload type and padding of the first in */ /* the compund RTCP packet... */ if (pkt->common.version != 2) { rtp_message(LOG_WARNING, "Bogus RTCP packet: version number != 2 in the first sub-packet"); return FALSE; } if (pkt->common.p != 0) { rtp_message(LOG_WARNING, "Bogus RTCP packet: padding bit is set on first packet in compound"); return FALSE; } if ((pkt->common.pt != RTCP_SR) && (pkt->common.pt != RTCP_RR)) { rtp_message(LOG_WARNING, "Bogus RTCP packet: compund packet does not start with SR or RR"); return FALSE; } /* Check all following parts of the compund RTCP packet. The RTP version */ /* number must be 2, and the padding bit must be zero on all apart from */ /* the last packet. */ do { if (p == 1) { rtp_message(LOG_WARNING, "Bogus RTCP packet: padding bit set before last in compound (sub-packet %d)", pc); return FALSE; } if (r->common.p) { p = 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -