aboutsummaryrefslogtreecommitdiffstats
path: root/rtp.c
diff options
context:
space:
mode:
authormatteo <matteo@f38db490-d61c-443f-a65b-d21fe96a405b>2003-03-12 06:00:18 +0000
committermatteo <matteo@f38db490-d61c-443f-a65b-d21fe96a405b>2003-03-12 06:00:18 +0000
commitf61680257a63d31f0abcf41b5c29f4670552af2f (patch)
tree37350d3bd0d6df02129f16dc35b893e9a674e627 /rtp.c
parent9cfcee51633cfff22801dd82843f5b7c7f4fdd82 (diff)
Wed Mar 12 07:00:01 CET 2003
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@641 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'rtp.c')
-rwxr-xr-xrtp.c274
1 files changed, 181 insertions, 93 deletions
diff --git a/rtp.c b/rtp.c
index fb3ea671f..b7078a5bd 100755
--- a/rtp.c
+++ b/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 {