mirror of
https://github.com/asterisk/asterisk.git
synced 2025-11-08 10:58:15 +00:00
Wed Mar 12 07:00:01 CET 2003
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@641 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
274
rtp.c
274
rtp.c
@@ -39,6 +39,14 @@
|
||||
|
||||
static int dtmftimeout = 300; /* 300 samples */
|
||||
|
||||
// The value of each RTP payload format mapping:
|
||||
struct rtpPayloadType {
|
||||
int isAstFormat; // whether the following code is an AST_FORMAT
|
||||
int code;
|
||||
};
|
||||
|
||||
#define MAX_RTP_PT 256
|
||||
|
||||
struct ast_rtp {
|
||||
int s;
|
||||
char resp;
|
||||
@@ -62,6 +70,11 @@ struct ast_rtp {
|
||||
struct io_context *io;
|
||||
void *data;
|
||||
ast_rtp_callback callback;
|
||||
struct rtpPayloadType current_RTP_PT[MAX_RTP_PT];
|
||||
// a cache for the result of rtp_lookup_code():
|
||||
int rtp_lookup_code_cache_isAstFormat;
|
||||
int rtp_lookup_code_cache_code;
|
||||
int rtp_lookup_code_cache_result;
|
||||
};
|
||||
|
||||
static struct ast_rtp_protocol *protos = NULL;
|
||||
@@ -204,41 +217,6 @@ static struct ast_frame *process_rfc3389(struct ast_rtp *rtp, unsigned char *dat
|
||||
return f;
|
||||
}
|
||||
|
||||
static struct ast_frame *process_type121(struct ast_rtp *rtp, unsigned char *data, int len)
|
||||
{
|
||||
char resp = 0;
|
||||
struct ast_frame *f = NULL;
|
||||
unsigned char b0,b1,b2,b3,b4,b5,b6,b7;
|
||||
|
||||
b0=*(data+0);b1=*(data+1);b2=*(data+2);b3=*(data+3);
|
||||
b4=*(data+4);b5=*(data+5);b6=*(data+6);b7=*(data+7);
|
||||
// printf("%u %u %u %u %u %u %u %u\n",b0,b1,b2,b3,b4,b5,b6,b7);
|
||||
if (b2==32) {
|
||||
// printf("Start %d\n",b3);
|
||||
if (b4==0) {
|
||||
// printf("Detection point for DTMF %d\n",b3);
|
||||
if (b3<10) {
|
||||
resp='0'+b3;
|
||||
} else if (b3<11) {
|
||||
resp='*';
|
||||
} else if (b3<12) {
|
||||
resp='#';
|
||||
} else if (b3<16) {
|
||||
resp='A'+(b3-12);
|
||||
}
|
||||
rtp->resp=resp;
|
||||
f = send_dtmf(rtp);
|
||||
}
|
||||
}
|
||||
if (b2==3) {
|
||||
// printf("Stop(3) %d\n",b3);
|
||||
}
|
||||
if (b2==0) {
|
||||
// printf("Stop(0) %d\n",b3);
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
static int rtpread(int *id, int fd, short events, void *cbdata)
|
||||
{
|
||||
struct ast_rtp *rtp = cbdata;
|
||||
@@ -262,6 +240,7 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
|
||||
unsigned int timestamp;
|
||||
unsigned int *rtpheader;
|
||||
static struct ast_frame *f, null_frame = { AST_FRAME_NULL, };
|
||||
struct rtpPayloadType rtpPT;
|
||||
|
||||
len = sizeof(sin);
|
||||
|
||||
@@ -297,29 +276,24 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
|
||||
printf("Got RTP packet from %s:%d (type %d, seq %d, ts %d, len = %d)\n", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), payloadtype, seqno, timestamp,res - hdrlen);
|
||||
#endif
|
||||
rtp->f.frametype = AST_FRAME_VOICE;
|
||||
rtp->f.subclass = rtp2ast(payloadtype);
|
||||
if (rtp->f.subclass < 0) {
|
||||
f = NULL;
|
||||
if (payloadtype == 101) {
|
||||
/* It's special -- rfc2833 process it */
|
||||
f = process_rfc2833(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen);
|
||||
} else if (payloadtype == 121) {
|
||||
/* CISCO proprietary DTMF bridge */
|
||||
f = process_type121(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen);
|
||||
} else if (payloadtype == 100) {
|
||||
/* CISCO's notso proprietary DTMF bridge */
|
||||
f = process_rfc2833(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen);
|
||||
} else if (payloadtype == 13) {
|
||||
f = process_rfc3389(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen);
|
||||
} else {
|
||||
ast_log(LOG_NOTICE, "Unknown RTP codec %d received\n", payloadtype);
|
||||
}
|
||||
if (f)
|
||||
return f;
|
||||
else
|
||||
return &null_frame;
|
||||
} else
|
||||
rtp->lastrxformat = rtp->f.subclass;
|
||||
rtpPT = rtp_lookup_pt(rtp, payloadtype);
|
||||
if (!rtpPT.isAstFormat) {
|
||||
// This is special in-band data that's not one of our codecs
|
||||
if (rtpPT.code == AST_RTP_DTMF) {
|
||||
/* It's special -- rfc2833 process it */
|
||||
f = process_rfc2833(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen);
|
||||
if (f) return f; else return &null_frame;
|
||||
} else if (rtpPT.code == AST_RTP_CN) {
|
||||
/* Comfort Noise */
|
||||
f = process_rfc3389(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen);
|
||||
if (f) return f; else return &null_frame;
|
||||
} else {
|
||||
ast_log(LOG_NOTICE, "Unknown RTP codec %d received\n", payloadtype);
|
||||
return &null_frame;
|
||||
}
|
||||
}
|
||||
rtp->f.subclass = rtpPT.code;
|
||||
rtp->lastrxformat = rtp->f.subclass;
|
||||
|
||||
if (!rtp->lastrxts)
|
||||
rtp->lastrxts = timestamp;
|
||||
@@ -367,6 +341,10 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
|
||||
case AST_FORMAT_G723_1:
|
||||
rtp->f.samples = g723_samples(rtp->f.data, rtp->f.datalen);
|
||||
break;
|
||||
case AST_FORMAT_SPEEX:
|
||||
rtp->f.samples = 160;
|
||||
// assumes that the RTP packet contained one Speex frame
|
||||
break;
|
||||
default:
|
||||
ast_log(LOG_NOTICE, "Unable to calculate samples for format %d\n", rtp->f.subclass);
|
||||
break;
|
||||
@@ -375,48 +353,151 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
|
||||
return &rtp->f;
|
||||
}
|
||||
|
||||
// The following array defines the MIME type (and subtype) for each
|
||||
// of our codecs, or RTP-specific data type.
|
||||
static struct {
|
||||
int rtp;
|
||||
int ast;
|
||||
char *label;
|
||||
} cmap[] = {
|
||||
{ 0, AST_FORMAT_ULAW, "PCMU" },
|
||||
{ 3, AST_FORMAT_GSM, "GSM" },
|
||||
{ 4, AST_FORMAT_G723_1, "G723" },
|
||||
{ 5, AST_FORMAT_ADPCM, "ADPCM" },
|
||||
{ 8, AST_FORMAT_ALAW, "PCMA" },
|
||||
{ 18, AST_FORMAT_G729A, "G729" },
|
||||
struct rtpPayloadType payloadType;
|
||||
char* type;
|
||||
char* subtype;
|
||||
} mimeTypes[] = {
|
||||
{{1, AST_FORMAT_G723_1}, "audio", "G723"},
|
||||
{{1, AST_FORMAT_GSM}, "audio", "GSM"},
|
||||
{{1, AST_FORMAT_ULAW}, "audio", "PCMU"},
|
||||
{{1, AST_FORMAT_ALAW}, "audio", "PCMA"},
|
||||
{{1, AST_FORMAT_MP3}, "audio", "MPA"},
|
||||
{{1, AST_FORMAT_ADPCM}, "audio", "DVI4"},
|
||||
{{1, AST_FORMAT_SLINEAR}, "audio", "L16"},
|
||||
{{1, AST_FORMAT_LPC10}, "audio", "LPC"},
|
||||
{{1, AST_FORMAT_G729A}, "audio", "G729"},
|
||||
{{1, AST_FORMAT_SPEEX}, "audio", "SPEEX"},
|
||||
{{0, AST_RTP_DTMF}, "audio", "TELEPHONE-EVENT"},
|
||||
{{0, AST_RTP_CN}, "audio", "CN"},
|
||||
{{1, AST_FORMAT_JPEG}, "video", "JPEG"},
|
||||
{{1, AST_FORMAT_PNG}, "video", "PNG"},
|
||||
{{1, AST_FORMAT_H261}, "video", "H261"},
|
||||
{{1, AST_FORMAT_H263}, "video", "H263"},
|
||||
};
|
||||
|
||||
int rtp2ast(int id)
|
||||
{
|
||||
int x;
|
||||
for (x=0;x<sizeof(cmap) / sizeof(cmap[0]); x++) {
|
||||
if (cmap[x].rtp == id)
|
||||
return cmap[x].ast;
|
||||
}
|
||||
return -1;
|
||||
// Static (i.e., well-known) RTP payload types for our "AST_FORMAT..."s:
|
||||
static struct rtpPayloadType static_RTP_PT[MAX_RTP_PT] = {
|
||||
[0] = {1, AST_FORMAT_ULAW},
|
||||
[3] = {1, AST_FORMAT_GSM},
|
||||
[4] = {1, AST_FORMAT_G723_1},
|
||||
[5] = {1, AST_FORMAT_ADPCM}, // 8 kHz
|
||||
[6] = {1, AST_FORMAT_ADPCM}, // 16 kHz
|
||||
[7] = {1, AST_FORMAT_LPC10},
|
||||
[8] = {1, AST_FORMAT_ALAW},
|
||||
[10] = {1, AST_FORMAT_SLINEAR}, // 2 channels
|
||||
[11] = {1, AST_FORMAT_SLINEAR}, // 1 channel
|
||||
[13] = {0, AST_RTP_CN},
|
||||
[14] = {1, AST_FORMAT_MP3},
|
||||
[16] = {1, AST_FORMAT_ADPCM}, // 11.025 kHz
|
||||
[17] = {1, AST_FORMAT_ADPCM}, // 22.050 kHz
|
||||
[18] = {1, AST_FORMAT_G729A},
|
||||
[26] = {1, AST_FORMAT_JPEG},
|
||||
[31] = {1, AST_FORMAT_H261},
|
||||
[34] = {1, AST_FORMAT_H263},
|
||||
};
|
||||
|
||||
void rtp_pt_init(struct ast_rtp* rtp) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_RTP_PT; ++i) {
|
||||
rtp->current_RTP_PT[i].isAstFormat = 0;
|
||||
rtp->current_RTP_PT[i].code = 0;
|
||||
}
|
||||
|
||||
rtp->rtp_lookup_code_cache_isAstFormat = 0;
|
||||
rtp->rtp_lookup_code_cache_code = 0;
|
||||
rtp->rtp_lookup_code_cache_result = 0;
|
||||
}
|
||||
|
||||
int ast2rtp(int id)
|
||||
{
|
||||
int x;
|
||||
for (x=0;x<sizeof(cmap) / sizeof(cmap[0]); x++) {
|
||||
if (cmap[x].ast == id)
|
||||
return cmap[x].rtp;
|
||||
}
|
||||
return -1;
|
||||
// Make a note of a RTP payload type that was seen in a SDP "m=" line.
|
||||
// By default, use the well-known value for this type (although it may
|
||||
// still be set to a different value by a subsequent "a=rtpmap:" line):
|
||||
void rtp_set_m_type(struct ast_rtp* rtp, int pt) {
|
||||
if (pt < 0 || pt > MAX_RTP_PT) return; // bogus payload type
|
||||
|
||||
if (static_RTP_PT[pt].code != 0) {
|
||||
rtp->current_RTP_PT[pt] = static_RTP_PT[pt];
|
||||
}
|
||||
}
|
||||
|
||||
// Make a note of a RTP payload type (with MIME type) that was seen in
|
||||
// a SDP "a=rtpmap:" line.
|
||||
void rtp_set_rtpmap_type(struct ast_rtp* rtp, int pt,
|
||||
char* mimeType, char* mimeSubtype) {
|
||||
int i;
|
||||
|
||||
if (pt < 0 || pt > MAX_RTP_PT) return; // bogus payload type
|
||||
|
||||
for (i = 0; i < sizeof mimeTypes/sizeof mimeTypes[0]; ++i) {
|
||||
if (strcmp(mimeSubtype, mimeTypes[i].subtype) == 0 &&
|
||||
strcmp(mimeType, mimeTypes[i].type) == 0) {
|
||||
rtp->current_RTP_PT[pt] = mimeTypes[i].payloadType;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return the union of all of the codecs that were set by rtp_set...() calls
|
||||
// They're returned as two distinct sets: AST_FORMATs, and AST_RTPs
|
||||
void rtp_get_current_formats(struct ast_rtp* rtp,
|
||||
int* astFormats, int* nonAstFormats) {
|
||||
int pt;
|
||||
|
||||
*astFormats = *nonAstFormats = 0;
|
||||
for (pt = 0; pt < MAX_RTP_PT; ++pt) {
|
||||
if (rtp->current_RTP_PT[pt].isAstFormat) {
|
||||
*astFormats |= rtp->current_RTP_PT[pt].code;
|
||||
} else {
|
||||
*nonAstFormats |= rtp->current_RTP_PT[pt].code;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char *ast2rtpn(int id)
|
||||
{
|
||||
int x;
|
||||
for (x=0;x<sizeof(cmap) / sizeof(cmap[0]); x++) {
|
||||
if (cmap[x].ast == id)
|
||||
return cmap[x].label;
|
||||
}
|
||||
return "";
|
||||
struct rtpPayloadType rtp_lookup_pt(struct ast_rtp* rtp, int pt) {
|
||||
if (pt < 0 || pt > MAX_RTP_PT) {
|
||||
struct rtpPayloadType result;
|
||||
result.isAstFormat = result.code = 0;
|
||||
return result; // bogus payload type
|
||||
}
|
||||
return rtp->current_RTP_PT[pt];
|
||||
}
|
||||
|
||||
int rtp_lookup_code(struct ast_rtp* rtp, int isAstFormat, int code) {
|
||||
int pt;
|
||||
|
||||
if (isAstFormat == rtp->rtp_lookup_code_cache_isAstFormat &&
|
||||
code == rtp->rtp_lookup_code_cache_code) {
|
||||
// Use our cached mapping, to avoid the overhead of the loop below
|
||||
return rtp->rtp_lookup_code_cache_result;
|
||||
}
|
||||
|
||||
for (pt = 0; pt < MAX_RTP_PT; ++pt) {
|
||||
if (rtp->current_RTP_PT[pt].code == code &&
|
||||
rtp->current_RTP_PT[pt].isAstFormat == isAstFormat) {
|
||||
rtp->rtp_lookup_code_cache_isAstFormat = isAstFormat;
|
||||
rtp->rtp_lookup_code_cache_code = code;
|
||||
rtp->rtp_lookup_code_cache_result = pt;
|
||||
return pt;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
char* rtp_lookup_mime_subtype(int isAstFormat, int code) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sizeof mimeTypes/sizeof mimeTypes[0]; ++i) {
|
||||
if (mimeTypes[i].payloadType.code == code &&
|
||||
mimeTypes[i].payloadType.isAstFormat == isAstFormat) {
|
||||
return mimeTypes[i].subtype;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
struct ast_rtp *ast_rtp_new(struct sched_context *sched, struct io_context *io)
|
||||
{
|
||||
struct ast_rtp *rtp;
|
||||
@@ -604,6 +685,10 @@ static int ast_rtp_raw_write(struct ast_rtp *rtp, struct ast_frame *f, int codec
|
||||
case AST_FORMAT_G723_1:
|
||||
pred = rtp->lastts + g723_samples(f->data, f->datalen);
|
||||
break;
|
||||
case AST_FORMAT_SPEEX:
|
||||
pred = rtp->lastts + 160;
|
||||
// assumes that the RTP packet contains one Speex frame
|
||||
break;
|
||||
default:
|
||||
ast_log(LOG_WARNING, "Not sure about timestamp format for codec format %d\n", f->subclass);
|
||||
}
|
||||
@@ -648,7 +733,7 @@ int ast_rtp_write(struct ast_rtp *rtp, struct ast_frame *_f)
|
||||
return -1;
|
||||
}
|
||||
|
||||
codec = ast2rtp(_f->subclass);
|
||||
codec = rtp_lookup_code(rtp, 1, _f->subclass);
|
||||
if (codec < 0) {
|
||||
ast_log(LOG_WARNING, "Don't know how to send format %d packets with RTP\n", _f->subclass);
|
||||
return -1;
|
||||
@@ -706,6 +791,9 @@ int ast_rtp_write(struct ast_rtp *rtp, struct ast_frame *_f)
|
||||
break;
|
||||
default:
|
||||
ast_log(LOG_WARNING, "Not sure about sending format %d packets\n", _f->subclass);
|
||||
// fall through to...
|
||||
case AST_FORMAT_SPEEX:
|
||||
// Don't buffer outgoing frames; send them one-per-packet:
|
||||
if (_f->offset < hdrlen) {
|
||||
f = ast_frdup(_f);
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user