📄 rtpacket.c
字号:
/*
RTP input packet construction and parsing
*/
#include "netfone.h"
static audio_descr_t adt[] = {
/* enc sample ch */
{AE_PCMU, 8000, 1}, /* 0 PCMU */
{AE_MAX, 8000, 1}, /* 1 1016 */
{AE_G721, 8000, 1}, /* 2 G721 */
{AE_GSM, 8000, 1}, /* 3 GSM */
{AE_G723, 8000, 1}, /* 4 Unassigned */
{AE_IDVI, 8000, 1}, /* 5 DVI4 */
{AE_IDVI, 16000, 1}, /* 6 DVI4 */
{AE_LPC, 8000, 1}, /* 7 LPC */
{AE_PCMA, 8000, 1}, /* 8 PCMA */
{AE_MAX, 0, 1}, /* 9 G722 */
{AE_L16, 44100, 2}, /* 10 L16 */
{AE_L16, 44100, 1}, /* 11 L16 */
{AE_MAX, 0, 1}, /* 12 */
};
#define bcopy(s, d, l) memcpy(d, s, l)
#define bzero(d, l) memset(d, 0, l)
#define MAX_MISORDER 100
#define MAX_DROPOUT 3000
/* ISRTP -- Determine if a packet is RTP or not. If so, convert
in place into a sound buffer. */
int isrtp(unsigned char *pkt, int len)
{
#ifdef RationalWorld
rtp_hdr_t *rh = (rtp_hdr_t *) pkt;
#endif
unsigned int r_version, r_p, r_x, r_cc, r_m, r_pt,
r_seq;
long r_ts;
/* Tear apart the header in a byte- and bit field-order
independent fashion. */
r_version = (pkt[0] >> 6) & 3;
r_p = !!(pkt[0] & 0x20);
r_x = !!(pkt[0] & 0x10);
r_cc = pkt[0] & 0xF;
r_m = !!(pkt[1] & 0x80);
r_pt = pkt[1] & 0x1F;
r_seq = ntohs(*((short *) (pkt + 2)));
r_ts = ntohl(*((long *) (pkt + 4)));
if (
#ifdef RationalWorld
rh->version == RTP_VERSION && /* Version ID correct */
rh->pt < ELEMENTS(adt) && /* Payload type credible */
adt[rh->pt].sample_rate != 0 && /* Defined payload type */
/* Padding, if present, is plausible */
(!rh->p || (pkt[len - 1] < (len - (12 + 4 * rh->cc))))
#else
r_version == RTP_VERSION && /* Version ID correct */
r_pt < ELEMENTS(adt) && /* Payload type credible */
adt[r_pt].sample_rate != 0 && /* Defined payload type */
/* Padding, if present, is plausible */
(!r_p || (pkt[len - 1] < (len - (12 + 4 * r_cc))))
#endif
) {
struct soundbuf sb;
unsigned char *payload;
int lex, paylen;
/* Length of fixed header extension, if any */
lex = r_x ? (ntohs(*((short *) (pkt + 2 + 12 + 4 * r_cc))) + 1) * 4 : 0;
payload = pkt + (12 + 4 * r_cc) + lex; /* Start of payload */
paylen = len - ((12 + 4 * r_cc) + /* Length of payload */
lex + (r_p ? pkt[len - 1] : 0));
sb.compression = fProtocol;
sb.buffer.buffer_len = 0;
#ifdef NEEDED
/* Fake an RTP unique host name from the SSRC identifier. */
sprintf(sb.sendinghost, ".RTP:%02X%02X%02X%02X",
pkt[8], pkt[9], pkt[10], pkt[11]);
#else
strcpy(sb.sendinghost, ".RTP");
#endif
#ifdef RTP_PACKET_DUMP
xd(pkt, len, TRUE);
#endif
switch (adt[r_pt].encoding) {
case AE_PCMU:
sb.buffer.buffer_len = paylen;
bcopy(payload, sb.buffer.buffer_val, paylen);
break;
case AE_PCMA:
/* Untested: I haven't found a program which sends in this
format. */
{
int i;
unsigned char *op = (unsigned char *) sb.buffer.buffer_val;
sb.buffer.buffer_len = paylen;
for (i = 0; i < paylen; i++) {
*op++ = alaw2ulaw(*payload++);
}
}
break;
case AE_GSM:
sb.buffer.buffer_len = paylen + sizeof(short);
bcopy(payload, sb.buffer.buffer_val + 2, paylen);
*((short *) sb.buffer.buffer_val) =
htons((short) ((((long) paylen) * 160) / 33));
sb.compression |= fCompGSM;
break;
case AE_IDVI:
bcopy(payload + 4, sb.buffer.buffer_val, paylen - 4);
bcopy(payload, sb.buffer.buffer_val + (paylen - 4), 3);
sb.buffer.buffer_len = paylen - 1;
if (adt[r_pt].sample_rate == 8000) {
sb.compression |= fCompADPCM;
} else {
/* Bogus attempt to convert sampling rate. We
really need to do this in linear mode, which isn't
supported on all SPARCs. This is better than
nothing, though. */
int inc = adt[r_pt].sample_rate / 8000, i;
unsigned char *in = (unsigned char *) sb.buffer.buffer_val,
*out = (unsigned char *) sb.buffer.buffer_val;
adpcmdecomp(&sb);
for (i = 0; i < (paylen - 4) / inc; i++) {
*out++ = *in;
in += inc;
}
sb.buffer.buffer_len /= inc;
}
break;
case AE_LPC:
{
int i, n = paylen / 14;
char *ip = (char *) payload,
*op = (char *) sb.buffer.buffer_val + 2;
*((short *) sb.buffer.buffer_val) = htons((short) (160 * n));
for (i = 0; i < n; i++) {
bcopy(ip, op, 3);
op[3] = 0;
bcopy(ip + 3, op + 4, 10);
ip += 14;
op += 14;
}
sb.buffer.buffer_len = paylen + 2;
sb.compression |= fCompLPC;
}
break;
case AE_L16:
if (adt[r_pt].channels == 1) {
int i, j, k;
for (i = j = k = 0; i < (paylen / 8); i++) {
if ((k & 3) != 2 && ((i % 580) != 579)) {
sb.buffer.buffer_val[j++] =
audio_s2u((((unsigned short *) payload)[i * 4]));
}
k = (k + 1) % 11;
}
sb.buffer.buffer_len = j;
} else if (adt[r_pt].channels == 2) {
int i, j, k;
for (i = j = k = 0; i < (paylen / 16); i++) {
if ((k & 3) != 2 && ((i % 580) != 579)) {
sb.buffer.buffer_val[j++] =
audio_s2u(((((unsigned short *) payload)[i * 8]) +
(((unsigned short *) payload)[i * 8 + 1])) / 2);
}
k = (k + 1) % 11;
}
sb.buffer.buffer_len = j;
}
break;
default:
/* Unknown compression type. */
break;
}
if (sb.buffer.buffer_len > 0) {
bcopy(&sb, pkt, (int) (((sizeof sb - BUFL)) + sb.buffer.buffer_len));
#ifdef RTP_PACKET_DUMP
xd(&sb, (int) ((sizeof sb - BUFL) + sb.buffer.buffer_len), TRUE);
#endif
}
return TRUE;
}
return FALSE;
}
/* ISVALIDRTCPPACKET -- Consistency check a packet to see if
is a compliant RTCP packet. */
int isValidRTCPpacket(unsigned char *p, int len)
{
unsigned char *end;
if (((((p[0] >> 6) & 3) != RTP_VERSION) && /* Version incorrect ? */
((((p[0] >> 6) & 3) != 1))) || /* Allow Speak Freely too */
((p[0] & 0x20) != 0) || /* Padding in first packet ? */
((p[1] != RTCP_SR) && (p[1] != RTCP_RR))) { /* First item not SR or RR ? */
return FALSE;
}
end = p + len;
do {
/* Advance to next subpacket */
p += (ntohs(*((short *) (p + 2))) + 1) * 4;
} while (p < end && (((p[0] >> 6) & 3) == RTP_VERSION));
return p == end;
}
/* ISRTCPBYEPACKET -- Test if this RTCP packet contains a BYE. */
int isRTCPByepacket(unsigned char *p, int len)
{
unsigned char *end;
int sawbye = FALSE;
/* Version incorrect ? */
if ((((p[0] >> 6) & 3) != RTP_VERSION && ((p[0] >> 6) & 3) != 1) ||
((p[0] & 0x20) != 0) || /* Padding in first packet ? */
((p[1] != RTCP_SR) && (p[1] != RTCP_RR))) { /* First item not SR or RR ? */
return FALSE;
}
end = p + len;
do {
if (p[1] == RTCP_BYE) {
sawbye = TRUE;
}
/* Advance to next subpacket */
p += (ntohs(*((short *) (p + 2))) + 1) * 4;
} while (p < end && (((p[0] >> 6) & 3) == RTP_VERSION));
return (p == end) && sawbye;
}
/* ISRTCPAPPPACKET -- Test if this RTCP packet contains a APP item
with a given name. If so, returns a pointer
to the APP sub-packet in app_ptr. */
int isRTCPAPPpacket(unsigned char *p, int len, char *name, unsigned char **app_ptr)
{
unsigned char *end;
*app_ptr = NULL;
/* Version incorrect ? */
if ((((p[0] >> 6) & 3) != RTP_VERSION && ((p[0] >> 6) & 3) != 1) ||
((p[0] & 0x20) != 0) || /* Padding in first packet ? */
((p[1] != RTCP_SR) && (p[1] != RTCP_RR))) { /* First item not SR or RR ? */
return FALSE;
}
end = p + len;
do {
if ((p[1] == RTCP_APP) && (memcmp(p + 8, name, 4) == 0)) {
*app_ptr = p;
return TRUE;
}
/* Advance to next subpacket */
p += (ntohs(*((short *) (p + 2))) + 1) * 4;
} while (p < end && (((p[0] >> 6) & 3) == RTP_VERSION));
return FALSE;
}
/* RTP_MAKE_SDES -- Generate a source description for this
user, based either on information obtained
from the password file or supplied by
environment variables. Strict construction
of the RTP specification requires every
SDES packet to be a composite which begins
with a sender or receiver report. If the
"strict" argument is true, we'll comply with
this. Unfortunately, Look Who's Listening
Server code was not aware of this little
twist when originally implemented, so it will
take some time to transition all the running
servers to composite packet aware code. */
int rtp_make_sdes(char **pkt, unsigned long ssrc_i, int port,
int exact, int strict)
{
unsigned char zp[512];
unsigned char *p = zp;
// rtcp_t *rp;
unsigned char *ap;
int l, hl;
char s[256];
#define addSDES(item, text) *ap++ = item; *ap++ = l = strlen(text); \
bcopy(text, ap, l); ap += l
hl = 0;
if (strict) {
*p++ = RTP_VERSION << 6;
*p++ = RTCP_RR;
*p++ = 0;
*p++ = 1;
*((long *) p) = htonl(ssrc_i);
p += 4;
hl = 8;
}
#ifdef RationalWorld
rp = (rtcp_t *) p;
rp->common.version = RTP_VERSION;
rp->common.p = 0;
rp->common.count = 1;
rp->common.pt = RTCP_SDES;
rp->r.sdes.src = htonl(ssrc_i);
#else
*((short *) p) = htons((u_short) ((RTP_VERSION << 14) | RTCP_SDES | (1 << 8)));
*((long *) (p + 4)) = htonl(ssrc_i);
#endif
ap = p + 8;
/* Build canonical name for this user. This is generally
a name which can be used for "talk" and "finger", and
is not necessarily the user's E-mail address. If the
exact flag is set, we precede the name with an asterisk
to inform the LWL server this name cannot be matched by
a wild card. */
if (exact) {
s[0] = '*';
strcpy(s + 1, lwl_s_email);
addSDES(RTCP_SDES_CNAME, s);
} else {
addSDES(RTCP_SDES_CNAME, lwl_s_email);
}
if (lwl_s_fullname[0]) {
addSDES(RTCP_SDES_NAME, lwl_s_fullname);
}
addSDES(RTCP_SDES_EMAIL, lwl_s_email);
if (lwl_s_phone[0]) {
addSDES(RTCP_SDES_PHONE, lwl_s_phone);
}
if (lwl_s_location[0]) {
addSDES(RTCP_SDES_LOC, lwl_s_location);
}
addSDES(RTCP_SDES_TOOL, rstring(IDS_T_RTP_TOOL));
/* If not strict, add a PRIV item indicating the port
we're communicating on. */
if (!strict) {
sprintf(s, Format(59), port);
addSDES(RTCP_SDES_PRIV, s);
}
*ap++ = RTCP_SDES_END;
*ap++ = 0;
l = ap - p;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -