⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rtp.c

📁 完整的RTP RTSP代码库
💻 C
📖 第 1 页 / 共 5 页
字号:
  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 + -