📄 rtp.c
字号:
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; 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. */uint8_t *rtp_get_userdata(struct rtp *session){ check_database(session); return session->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 int validate_rtp(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; } /* 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) { rtp_message(LOG_WARNING, "rtp_header_validation: payload-type invalid %d - seq%d", packet->rtp_pak_pt, packet->rtp_pak_seq); if (packet->rtp_pak_m) { rtp_message(LOG_WARNING, " (RTCP packet on RTP port?)"); } return FALSE; } /* Check that the length of the packet is sensible... */ if (len < (12 + (4 * packet->rtp_pak_cc))) { rtp_message(LOG_WARNING, "rtp_header_validation: packet length is smaller than the header"); 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) { rtp_message(LOG_WARNING, "rtp_header_validation: padding greater than payload length"); return FALSE; } if (packet->rtp_data[packet->rtp_data_len - 1] < 1) { rtp_message(LOG_WARNING, "rtp_header_validation: padding zero"); return FALSE; } } return TRUE;}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); }}int rtp_process_recv_data (struct rtp *session, uint32_t curr_rtp_ts, rtp_packet *packet, int buflen){ uint8_t *buffer = ((uint8_t *) packet) + RTP_PACKET_HEADER_SIZE; source *s; int ret; packet->pd.rtp_pd_buflen = buflen; if (buflen > 0) { if (session->encryption_enabled) { ret = (session->decrypt_func)(session->encrypt_userdata, buffer, &buflen); if (ret != TRUE) return -1; packet->pd.rtp_pd_buflen = 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(packet, buflen)) { int weak = 0, promisc = 0; rtp_get_option(session, RTP_OPT_WEAK_VALIDATION, &weak); if (weak) { s = get_source(session, packet->rtp_pak_ssrc); } else { s = create_source(session, packet->rtp_pak_ssrc, TRUE); } rtp_get_option(session, RTP_OPT_PROMISC, &promisc); if (promisc) { if (s == NULL) { create_source(session, packet->rtp_pak_ssrc, FALSE); 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; int buflen; buflen = udp_recv(session->rtp_socket, buffer, RTP_MAX_PACKET_LEN); if (rtp_process_recv_data(session, curr_rtp_ts, packet, buflen) < 0) xfree(packet);}static int validate_rtcp(uint8_t *packet, int 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; int l = 0; int pc = 1; int p = 0; /* All RTCP packets must be compound packets (RFC1889, section 6.1) */ if (((ntohs(pkt->common.length) + 1) * 4) == 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; } if (r->common.version != 2) { rtp_message(LOG_WARNING, "Bogus RTCP packet: version number != 2 in sub-packet %d", pc); return FALSE; } l += (ntohs(r->common.length) + 1) * 4; r = (rtcp_t *) (((uint32_t *) r) + ntohs(r->common.length) + 1); pc++; /* count of sub-packets, for debugging... */ } while (r < end); /* Check that the length of the packets matches the length of the UDP */ /* packet in which they were received... */ if (l != len) { rtp_message(LOG_WARNING, "Bogus RTCP packet: RTCP packet length does not match UDP packet length (%d != %d)", l, len); return FALSE; } if (r != end) { rtp_message(LOG_WARNING, "Bogus RTCP packet: RTCP packet length does not match UDP packet length (%p != %p)", r, end); return FALSE; } return TRUE;}static void process_report_blocks(struct rtp *session, rtcp_t *packet, uint32_t ssrc, rtcp_rr *rrp, struct timeval *event_ts){ int i; rtp_event event; rtcp_rr *rr; /* ...process RRs... */ if (packet->common.count == 0) { if (!filter_event(session, ssrc)) { event.ssrc = ssrc; event.type = RX_RR_EMPTY; event.data = NULL; event.ts = event_ts; session->callback(session, &event); } } else { for (i = 0; i < packet->common.count; i++, rrp++) { rr = (rtcp_rr *) xmalloc(sizeof(rtcp_rr)); rr->ssrc = ntohl(rrp->ssrc); rr->fract_lost = rrp->fract_lost; /* Endian conversion handled in the */ rr->total_lost = rrp->total_lost; /* definition of the rtcp_rr type. */ rr->last_seq = ntohl(rrp->last_seq); rr->jitter = ntohl(rrp->jitter); rr->lsr = ntohl(rrp->lsr); rr->dlsr = ntohl(rrp->dlsr); /* Create a database entry for this SSRC, if one doesn't already exist... */ create_source(session, rr->ssrc, FALSE); /* Store the RR for later use... */ insert_rr(session, ssrc, rr, event_ts); /* Call the event handler... */ if (!filter_event(session, ssrc)) { event.ssrc = ssrc; event.type = RX_RR; event.data = (void *) rr; event.ts = event_ts; session->callback(session, &event); } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -