?? rtp.c
字號(hào):
* @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;
}
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -