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

📄 rtp.c

📁 MPEG-4编解码的实现(包括MPEG4视音频编解码)
💻 C
📖 第 1 页 / 共 5 页
字号:
 * @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;
        	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;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -