?? rtp.c
字號:
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) {
rtp_message(LOG_WARNING, "Source 0x%08x invalid, skipping...", 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... */
if (s->sr != NULL) {
xfree(s->sr);
}
s->sr = sr;
s->last_sr = *event_ts;
/* Call the event handler... */
if (!filter_event(session, ssrc)) {
event.ssrc = ssrc;
event.type = RX_SR;
event.data = (void *) sr;
event.ts = event_ts;
session->callback(session, &event);
}
process_report_blocks(session, packet, ssrc, packet->r.sr.rr, event_ts);
if (((packet->common.count * 6) + 1) < (ntohs(packet->common.length) - 5)) {
rtp_message(LOG_NOTICE, "Profile specific SR extension ignored");
}
}
static void process_rtcp_rr(struct rtp *session, rtcp_t *packet, struct timeval *event_ts)
{
uint32_t ssrc;
source *s;
ssrc = ntohl(packet->r.rr.ssrc);
s = create_source(session, ssrc, FALSE);
if (s == NULL) {
rtp_message(LOG_WARNING, "Source 0x%08x invalid, skipping...", ssrc);
return;
}
process_report_blocks(session, packet, ssrc, packet->r.rr.rr, event_ts);
if (((packet->common.count * 6) + 1) < ntohs(packet->common.length)) {
rtp_message(LOG_INFO, "Profile specific RR extension ignored");
}
}
static void process_rtcp_sdes(struct rtp *session, rtcp_t *packet, struct timeval *event_ts)
{
int count = packet->common.count;
struct rtcp_sdes_t *sd = &packet->r.sdes;
rtcp_sdes_item *rsp;
rtcp_sdes_item *rspn;
rtcp_sdes_item *end = (rtcp_sdes_item *) ((uint32_t *)packet + packet->common.length + 1);
source *s;
rtp_event event;
while (--count >= 0) {
rsp = &sd->item[0];
if (rsp >= end) {
break;
}
sd->ssrc = ntohl(sd->ssrc);
s = create_source(session, sd->ssrc, FALSE);
if (s == NULL) {
rtp_message(LOG_NOTICE, "Cannot get valid source entry for 0x%08x, skipping...", sd->ssrc);
} else {
for (; rsp->type; rsp = rspn ) {
rspn = (rtcp_sdes_item *)((char*)rsp+rsp->length+2);
if (rspn >= end) {
rsp = rspn;
break;
}
if (rtp_set_sdes(session, sd->ssrc, rsp->type, rsp->data, rsp->length)) {
if (!filter_event(session, sd->ssrc)) {
event.ssrc = sd->ssrc;
event.type = RX_SDES;
event.data = (void *) rsp;
event.ts = event_ts;
session->callback(session, &event);
}
} else {
rtp_message(LOG_WARNING, "Invalid sdes item for source 0x%08x, skipping...", sd->ssrc);
}
}
}
sd = (struct rtcp_sdes_t *) ((uint32_t *)sd + (((char *)rsp - (char *)sd) >> 2)+1);
}
if (count >= 0) {
rtp_message(LOG_INFO, "Invalid RTCP SDES packet, some items ignored.");
}
}
static void process_rtcp_bye(struct rtp *session, rtcp_t *packet, struct timeval *event_ts)
{
int i;
uint32_t ssrc;
rtp_event event;
source *s;
for (i = 0; i < packet->common.count; i++) {
ssrc = ntohl(packet->r.bye.ssrc[i]);
/* This is kind-of strange, since we create a source we are about to delete. */
/* This is done to ensure that the source mentioned in the event which is */
/* passed to the user of the RTP library is valid, and simplify client code. */
create_source(session, ssrc, FALSE);
/* Call the event handler... */
if (!filter_event(session, ssrc)) {
event.ssrc = ssrc;
event.type = RX_BYE;
event.data = NULL;
event.ts = event_ts;
session->callback(session, &event);
}
/* Mark the source as ready for deletion. Sources are not deleted immediately */
/* since some packets may be delayed and arrive after the BYE... */
s = get_source(session, ssrc);
s->got_bye = TRUE;
check_source(s);
session->bye_count++;
}
}
static void process_rtcp_app(struct rtp *session, rtcp_t *packet, struct timeval *event_ts)
{
uint32_t ssrc;
rtp_event event;
rtcp_app *app;
source *s;
int data_len;
/* Update the database for this source. */
ssrc = ntohl(packet->r.app.ssrc);
create_source(session, ssrc, FALSE);
s = get_source(session, ssrc);
if (s == NULL) {
/* This should only occur in the event of database malfunction. */
rtp_message(LOG_NOTICE, "Source 0x%08x invalid, skipping...", ssrc);
return;
}
check_source(s);
/* Copy the entire packet, converting the header (only) into host byte order. */
app = (rtcp_app *) xmalloc(RTP_MAX_PACKET_LEN);
app->version = packet->common.version;
app->p = packet->common.p;
app->subtype = packet->common.count;
app->pt = packet->common.pt;
app->length = ntohs(packet->common.length);
app->ssrc = ssrc;
app->name[0] = packet->r.app.name[0];
app->name[1] = packet->r.app.name[1];
app->name[2] = packet->r.app.name[2];
app->name[3] = packet->r.app.name[3];
data_len = (app->length - 2) * 4;
memcpy(app->data, packet->r.app.data, data_len);
/* Callback to the application to process the app packet... */
if (!filter_event(session, ssrc)) {
event.ssrc = ssrc;
event.type = RX_APP;
event.data = (void *) app; /* The callback function MUST free this! */
event.ts = event_ts;
session->callback(session, &event);
}
}
void rtp_process_ctrl(struct rtp *session, uint8_t *buffer, int buflen)
{
/* This routine processes incoming RTCP packets */
rtp_event event;
struct timeval event_ts;
rtcp_t *packet;
int first;
uint32_t packet_ssrc = rtp_my_ssrc(session);
gettimeofday(&event_ts, NULL);
if (buflen > 0) {
if (session->encryption_enabled)
{
/* Decrypt the packet... */
(session->decrypt_func)(session->encrypt_userdata, buffer, &buflen);
buffer += 4; /* Skip the random prefix... */
buflen -= 4;
}
if (validate_rtcp(buffer, buflen)) {
first = TRUE;
packet = (rtcp_t *) buffer;
while (packet < (rtcp_t *) (buffer + buflen)) {
switch (packet->common.pt) {
case RTCP_SR:
if (first && !filter_event(session, ntohl(packet->r.sr.sr.ssrc))) {
event.ssrc = ntohl(packet->r.sr.sr.ssrc);
event.type = RX_RTCP_START;
event.data = &buflen;
event.ts = &event_ts;
packet_ssrc = event.ssrc;
session->callback(session, &event);
}
process_rtcp_sr(session, packet, &event_ts);
break;
case RTCP_RR:
if (first && !filter_event(session, ntohl(packet->r.rr.ssrc))) {
event.ssrc = ntohl(packet->r.rr.ssrc);
event.type = RX_RTCP_START;
event.data = &buflen;
event.ts = &event_ts;
packet_ssrc = event.ssrc;
session->callback(session, &event);
}
process_rtcp_rr(session, packet, &event_ts);
break;
case RTCP_SDES:
if (first && !filter_event(session, ntohl(packet->r.sdes.ssrc))) {
event.ssrc = ntohl(packet->r.sdes.ssrc);
event.type = RX_RTCP_START;
event.data = &buflen;
event.ts = &event_ts;
packet_ssrc = event.ssrc;
session->callback(session, &event);
}
process_rtcp_sdes(session, packet, &event_ts);
break;
case RTCP_BYE:
if (first && !filter_event(session, ntohl(packet->r.bye.ssrc[0]))) {
event.ssrc = ntohl(packet->r.bye.ssrc[0]);
event.type = RX_RTCP_START;
event.data = &buflen;
event.ts = &event_ts;
packet_ssrc = event.ssrc;
session->callback(session, &event);
}
process_rtcp_bye(session, packet, &event_ts);
break;
case RTCP_APP:
if (first && !filter_event(session, ntohl(packet->r.app.ssrc))) {
event.ssrc = ntohl(packet->r.app.ssrc);
event.type = RX_RTCP_START;
event.data = &buflen;
event.ts = &event_ts;
packet_ssrc = event.ssrc;
session->callback(session, &event);
}
process_rtcp_app(session, packet, &event_ts);
break;
default:
rtp_message(LOG_WARNING, "RTCP packet with unknown type (%d) ignored.", packet->common.pt);
break;
}
packet = (rtcp_t *) ((uint8_t *) packet + (4 * (ntohs(packet->common.length) + 1)));
first = FALSE;
}
if (session->avg_rtcp_size < 0) {
/* This is the first RTCP packet we've received, set our initial estimate */
/* of the average packet size to be the size of this packet. */
session->avg_rtcp_size = buflen + RTP_LOWER_LAYER_OVERHEAD;
} else {
/* Update our estimate of the average RTCP packet size. The constants are */
/* 1/16 and 15/16 (section 6.3.3 of draft-ietf-avt-rtp-new-02.txt). */
session->avg_rtcp_size = (0.0625 * (buflen + RTP_LOWER_LAYER_OVERHEAD)) + (0.9375 * session->avg_rtcp_size);
}
/* Signal that we've finished processing this packet */
if (!filter_event(session, packet_ssrc)) {
event.ssrc = packet_ssrc;
event.type = RX_RTCP_FINISH;
event.data = NULL;
event.ts = &event_ts;
session->callback(session, &event);
}
} else {
rtp_message(LOG_INFO, "Invalid RTCP packet discarded");
session->invalid_rtcp_count++;
}
}
}
/**
* rtp_recv:
* @session: the session pointer (returned by rtp_init())
* @timeout: the amount of time that rtcp_recv() is allowed to block
* @curr_rtp_ts: the current time expressed in units of the media
* timestamp.
*
* Receive RTP packets and dispatch them.
*
* Returns: TRUE if data received, FALSE if the timeout occurred.
*/
int rtp_recv(struct rtp *session, struct timeval *timeout, uint32_t curr_rtp_ts)
{
check_database(session);
udp_fd_zero();
udp_fd_set(session->rtp_socket);
udp_fd_set(session->rtcp_socket);
if (udp_select(timeout) > 0) {
if (udp_fd_isset(session->rtp_socket)) {
rtp_recv_data(session, curr_rtp_ts);
}
if (udp_fd_isset(session->rtcp_socket)) {
uint8_t buffer[RTP_MAX_PACKET_LEN];
int buflen;
buflen = udp_recv(session->rtcp_socket, buffer, RTP_MAX_PACKET_LEN);
rtp_process_ctrl(session, buffer, buflen);
}
check_database(session);
return TRUE;
}
check_database(session);
return FALSE;
}
/**
* rtp_add_csrc:
* @session: the session pointer (returned by rtp_init())
* @csrc: Const
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -