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

📄 rtp.c

📁 UCL Common Code Library Routines common to a number of multimedia tools. The library originates
💻 C
📖 第 1 页 / 共 5 页
字号:
 * @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.
 *
 * 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->cc > 0) {
		for (i = 0; i < packet->cc; i++) {
			create_source(session, packet->csrc[i], FALSE);
		}
	}
	/* Update the source database... */
	if (s->sender == FALSE) {
		s->sender = TRUE;
		session->sender_count++;
	}
	transit    = curr_rtp_ts - packet->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->ssrc)) {
		gettimeofday(&event_ts, NULL);
		event.ssrc = packet->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->pt >= 72 && packet->pt <= 76) {
		debug_msg("rtp_header_validation: payload-type invalid");
		if (packet->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->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->p) {
		int	payload_len = len - 12 - (packet->cc * 4);
                if (packet->x) {
                        /* extension header and data */
                        payload_len -= 4 * (1 + packet->extn_len);
                }
                if (packet->data[packet->data_len - 1] > payload_len) {
                        debug_msg("rtp_header_validation: padding greater than payload length\n");
                        return FALSE;
                }
                if (packet->data[packet->data_len - 1] < 1) {
			debug_msg("rtp_header_validation: padding zero\n");
			return FALSE;
		}
        }
	return TRUE;
}

static inline 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->v != 2) {
		debug_msg("rtp_header_validation: v != 2\n");
		return FALSE;
	}

	if (!session->opt->wait_for_rtcp) {
		/* We prefer speed over accuracy... */
		return TRUE;
	}
	return validate_rtp2(packet, len);
}

static void 
rtp_recv_data(struct rtp *session, uint32_t curr_rtp_ts)
{
	/* This routine preprocesses an incoming RTP packet, deciding whether to process it. */
	static rtp_packet	*packet   = NULL;
	static uint8_t		*buffer   = NULL;
	static uint8_t		*buffer12 = NULL;
	int			 buflen;
	source			*s;

	if (!session->opt->reuse_bufs || (packet == NULL)) {
		packet   = (rtp_packet *) xmalloc(RTP_MAX_PACKET_LEN);
		buffer   = ((uint8_t *) packet) + RTP_PACKET_HEADER_SIZE;
		buffer12 = buffer + 12;
	}

	buflen = udp_recv(session->rtp_socket, buffer, RTP_MAX_PACKET_LEN - RTP_PACKET_HEADER_SIZE);
	if (buflen > 0) {
		if (session->encryption_enabled) {
			uint8_t 	 initVec[8] = {0,0,0,0,0,0,0,0};
			(session->decrypt_func)(session, buffer, buflen, initVec);
		}
		/* Convert header fields to host byte order... */
		packet->seq      = ntohs(packet->seq);
		packet->ts       = ntohl(packet->ts);
		packet->ssrc     = ntohl(packet->ssrc);
		/* Setup internal pointers, etc... */
		if (packet->cc) {
			int	i;
			packet->csrc = (uint32_t *)(buffer12);
			for (i = 0; i < packet->cc; i++) {
				packet->csrc[i] = ntohl(packet->csrc[i]);
			}
		} else {
			packet->csrc = NULL;
		}
		if (packet->x) {
			packet->extn      = buffer12 + (packet->cc * 4);
			packet->extn_len  = (packet->extn[2] << 8) | packet->extn[3];
			packet->extn_type = (packet->extn[0] << 8) | packet->extn[1];
		} else {
			packet->extn      = NULL;
			packet->extn_len  = 0;
			packet->extn_type = 0;
		}
		packet->data     = buffer12 + (packet->cc * 4);
		packet->data_len = buflen -  (packet->cc * 4) - 12;
		if (packet->extn != NULL) {
			packet->data += ((packet->extn_len + 1) * 4);
			packet->data_len -= ((packet->extn_len + 1) * 4);
		}
		if (validate_rtp(session, packet, buflen)) {
			if (session->opt->wait_for_rtcp) {
				s = create_source(session, packet->ssrc, TRUE);
			} else {
				s = get_source(session, packet->ssrc);
			}
			if (session->opt->promiscuous_mode) {
				if (s == NULL) {
					create_source(session, packet->ssrc, FALSE);
					s = get_source(session, packet->ssrc);
				}
				process_rtp(session, curr_rtp_ts, packet, s);
				return; /* 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->seq - 1;
				}
				if (update_seq(s, packet->seq)) {
					process_rtp(session, curr_rtp_ts, packet, s);
					return;	/* we don't free "packet", that's done by the callback function... */
				} else {
					/* This source is still on probation... */
					debug_msg("RTP packet from probationary source ignored...\n");
				}
			} else {
				debug_msg("RTP packet from unknown source ignored\n");
			}
		} else {
			session->invalid_rtp_count++;
			debug_msg("Invalid RTP packet discarded\n");
		}
	}
	if (!session->opt->reuse_bufs) {
		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) {
		debug_msg("Bogus RTCP packet: not a compound packet\n");
		return FALSE;
	}

	/* Check the RTCP version, payload type and padding of the first in  */
	/* the compund RTCP packet...                                        */
	if (pkt->common.version != 2) {
		debug_msg("Bogus RTCP packet: version number != 2 in the first sub-packet\n");
		return FALSE;
	}
	if (pkt->common.p != 0) {
		debug_msg("Bogus RTCP packet: padding bit is set on first packet in compound\n");
		return FALSE;
	}
	if ((pkt->common.pt != RTCP_SR) && (pkt->common.pt != RTCP_RR)) {
		debug_msg("Bogus RTCP packet: compund packet does not start with SR or RR\n");
		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) {
			debug_msg("Bogus RTCP packet: padding bit set before last in compound (sub-packet %d)\n", pc);
			return FALSE;
		}
		if (r->common.p) {
			p = 1;
		}
		if (r->common.version != 2) {
			debug_msg("Bogus RTCP packet: version number != 2 in sub-packet %d\n", 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) {
		debug_msg("Bogus RTCP packet: RTCP packet length does not match UDP packet length (%d != %d)\n", l, len);
		return FALSE;
	}
	if (r != end) {
		debug_msg("Bogus RTCP packet: RTCP packet length does not match UDP packet length (%p != %p)\n", 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);
			}
		}
	}
}

static void process_rtcp_sr(struct rtp *session, rtcp_t *packet, struct timeval *event_ts)
{
	uint32_t	 ssrc;
	rtp_event	 event;
	rtcp_sr		*sr;
	source		*s;

	ssrc = ntohl(packet->r.sr.sr.ssrc);
	s = create_source(session, ssrc, FALSE);
	if (s == NULL) {
		debug_msg("Source 0x%08x invalid, skipping...\n", ssrc);
		return;
	}

	/* Mark as an active sender, if we get a sender report... */
	if (s->sender == FALSE) {
		s->sender = TRUE;
		session->sender_count++;
	}

	/* Process the SR... */
	sr = (rtcp_sr *) xmalloc(sizeof(rtcp_sr));
	sr->ssrc          = ssrc;
	sr->ntp_sec       = ntohl(packet->r.sr.sr.ntp_sec);
	sr->ntp_frac      = ntohl(packet->r.sr.sr.ntp_frac);
	sr->rtp_ts        = ntohl(packet->r.sr.sr.rtp_ts);
	sr->sender_pcount = ntohl(packet->r.sr.sr.sender_pcount);
	sr->sender_bcount = ntohl(packet->r.sr.sr.sender_bcount);

	/* Store the SR for later retrieval... */

⌨️ 快捷键说明

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