[Asterisk-Users] [PATCH] To fix dynamic RTP payload type handling (for SIP)
Ross Finlayson
finlayson at live.com
Wed Feb 26 04:45:47 MST 2003
-------------- next part --------------
Index: rtp.c
===================================================================
RCS file: /usr/cvsroot/asterisk/rtp.c,v
retrieving revision 1.26
diff -u -r1.26 rtp.c
--- rtp.c 24 Feb 2003 14:39:44 -0000 1.26
+++ rtp.c 26 Feb 2003 11:25:08 -0000
@@ -283,28 +283,24 @@
#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;
+ // Check for special in-band data (DTMF or Comfort Noise):
+ if (rtp->f.subclass == AST_FORMAT_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 (rtp->f.subclass == AST_FORMAT_DTMF_CISCO) {
+ /* CISCO proprietary DTMF bridge */
+ f = process_type121(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen);
+ if (f) return f; else return &null_frame;
+ } else if (rtp->f.subclass == AST_FORMAT_CN) {
+ /* Comfort Noise */
+ f = process_rfc3389(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen);
+ if (f) return f; else return &null_frame;
+ } else if (rtp->f.subclass < 0) {
+ ast_log(LOG_NOTICE, "Unknown RTP codec %d received\n", payloadtype);
+ return &null_frame;
+ }
+ rtp->lastrxformat = rtp->f.subclass;
if (!rtp->lastrxts)
rtp->lastrxts = timestamp;
@@ -360,48 +356,122 @@
return &rtp->f;
}
+// The following array defines the MIME type (and subtype) for each
+// defined "AST_FORMAT_..." value.
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" },
+ int ast;
+ char* type;
+ char* subtype;
+} mimeTypes[] = {
+ {AST_FORMAT_G723_1, "audio", "G723"},
+ {AST_FORMAT_GSM, "audio", "GSM"},
+ {AST_FORMAT_ULAW, "audio", "PCMU"},
+ {AST_FORMAT_ALAW, "audio", "PCMA"},
+ {AST_FORMAT_MP3, "audio", "MPA"},
+ {AST_FORMAT_ADPCM, "audio", "DVI4"},
+ {AST_FORMAT_SLINEAR, "audio", "L16"},
+ {AST_FORMAT_LPC10, "audio", "LPC"},
+ {AST_FORMAT_G729A, "audio", "G729"},
+ {AST_FORMAT_SPEEX, "audio", "SPEEX"},
+ {AST_FORMAT_DTMF, "audio", "TELEPHONE-EVENT"},
+ {AST_FORMAT_DTMF_CISCO, "audio", "TELEPHONE-EVENT-CISCO"/*Fix this!*/},
+ {AST_FORMAT_CN, "audio", "CN"},
+ {AST_FORMAT_JPEG, "video", "JPEG"},
+ {AST_FORMAT_PNG, "video", "PNG"},
+ {AST_FORMAT_H261, "video", "H261"},
+ {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;
+#define MAX_RTP_PT 256
+
+// Static (i.e., well-known) RTP payload types for our "AST_FORMAT..."s:
+static int static_RTP_PT[MAX_RTP_PT] = {
+ [0] = AST_FORMAT_ULAW,
+ [3] = AST_FORMAT_GSM,
+ [4] = AST_FORMAT_G723_1,
+ [5] = AST_FORMAT_ADPCM, // 8 kHz
+ [6] = AST_FORMAT_ADPCM, // 16 kHz
+ [7] = AST_FORMAT_LPC10,
+ [8] = AST_FORMAT_ALAW,
+ [10] = AST_FORMAT_SLINEAR, // 2 channels
+ [11] = AST_FORMAT_SLINEAR, // 1 channel
+ [13] = AST_FORMAT_CN,
+ [14] = AST_FORMAT_MP3,
+ [16] = AST_FORMAT_ADPCM, // 11.025 kHz
+ [17] = AST_FORMAT_ADPCM, // 22.050 kHz
+ [18] = AST_FORMAT_G729A,
+ [26] = AST_FORMAT_JPEG,
+ [31] = AST_FORMAT_H261,
+ [34] = AST_FORMAT_H263,
+};
+
+// The set of RTP payload types that the current caller has requested:
+static int current_RTP_PT[MAX_RTP_PT];
+
+void rtp_pt_init() {
+ int i;
+ for (i = 0; i < MAX_RTP_PT; ++i) {
+ current_RTP_PT[i] = 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(int pt) {
+ if (pt < 0 || pt > MAX_RTP_PT) return; // bogus payload type
+
+ if (static_RTP_PT[pt] != 0) {
+ 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(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) {
+ current_RTP_PT[pt] = mimeTypes[i].ast;
+ return;
+ }
+ }
+}
+
+// Return the union of all of the codecs that were set by rtp_set...() calls
+int rtp_get_current_codecs() {
+ int result = 0, pt;
+ for (pt = 0; pt < MAX_RTP_PT; ++pt) result |= current_RTP_PT[pt];
+
+ return result;
}
-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 "";
+int rtp2ast(int pt) {
+ if (pt < 0 || pt > MAX_RTP_PT) return -1; // bogus payload type
+ return current_RTP_PT[pt];
+}
+
+int ast2rtp(int id) {
+ int pt;
+ for (pt = 0; pt < MAX_RTP_PT; ++pt) {
+ if (current_RTP_PT[pt] == id) return pt;
+ }
+ return -1;
}
+
+char* ast2rtpn(int id) {
+ int i;
+
+ for (i = 0; i < sizeof mimeTypes/sizeof mimeTypes[0]; ++i) {
+ if (mimeTypes[i].ast == id) return mimeTypes[i].subtype;
+ }
+ return "";
+}
+
struct ast_rtp *ast_rtp_new(struct sched_context *sched, struct io_context *io)
{
struct ast_rtp *rtp;
Index: channels/chan_sip.c
===================================================================
RCS file: /usr/cvsroot/asterisk/channels/chan_sip.c,v
retrieving revision 1.129
diff -u -r1.129 chan_sip.c
--- channels/chan_sip.c 24 Feb 2003 15:20:42 -0000 1.129
+++ channels/chan_sip.c 26 Feb 2003 11:25:10 -0000
@@ -974,21 +974,41 @@
{ "Via", "v" },
};
-static char *get_sdp(struct sip_request *req, char *name)
-{
- int x;
- int len = strlen(name);
- char *r;
- for (x=0;x<req->lines;x++) {
- if (!strncasecmp(req->line[x], name, len) &&
- (req->line[x][len] == '=')) {
- r = req->line[x] + len + 1;
- while(*r && (*r < 33))
- r++;
- return r;
- }
- }
- return "";
+static char* get_sdp_by_line(char* line, char *name, int nameLen) {
+ if (strncasecmp(line, name, nameLen) == 0 && line[nameLen] == '=') {
+ char* r = line + nameLen + 1;
+ while (*r && (*r < 33)) ++r;
+ return r;
+ }
+
+ return "";
+}
+
+static char *get_sdp(struct sip_request *req, char *name) {
+ int x;
+ int len = strlen(name);
+ char *r;
+
+ for (x=0; x<req->lines; x++) {
+ r = get_sdp_by_line(req->line[x], name, len);
+ if (r[0] != '\0') return r;
+ }
+ return "";
+}
+
+static int sdpLineNum_iterator;
+void sdpLineNum_iterator_init() {
+ sdpLineNum_iterator = 0;
+}
+
+static char* get_sdp_iterate(struct sip_request *req, char *name) {
+ int len = strlen(name);
+ char *r;
+ while (sdpLineNum_iterator < req->lines) {
+ r = get_sdp_by_line(req->line[sdpLineNum_iterator++], name, len);
+ if (r[0] != '\0') return r;
+ }
+ return "";
}
static char *__get_header(struct sip_request *req, char *name, int *start)
@@ -1288,6 +1308,7 @@
{
char *m;
char *c;
+ char *a;
char host[258];
int len = -1;
int portno;
@@ -1329,21 +1350,38 @@
#if 0
printf("Peer RTP is at port %s:%d\n", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
#endif
- peercapability = 0;
+ // Scan through the RTP payload types specified in a "m=" line:
+ rtp_pt_init();
codecs = m + len;
while(strlen(codecs)) {
if (sscanf(codecs, "%d %n", &codec, &len) != 1) {
ast_log(LOG_WARNING, "Error in codec string '%s'\n", codecs);
return -1;
}
-#if 0
- printf("Codec: %d\n", codec);
-#endif
- codec = rtp2ast(codec);
- if (codec > -1)
- peercapability |= codec;
+ rtp_set_m_type(codec);
codecs += len;
}
+
+ // Next, scan through each "a=rtpmap:" line, noting each
+ // specified RTP payload type (with corresponding MIME subtype):
+ sdpLineNum_iterator_init();
+ while ((a = get_sdp_iterate(req, "a"))[0] != '\0') {
+ char mimeSubtype[100];
+ int subtypeLen, i;
+ if (sscanf(a, "rtpmap: %u %[^/]/", &codec, mimeSubtype) != 2) continue;
+ // Note: should really look at the 'freq' and '#chans' params too
+ mimeSubtype[sizeof mimeSubtype - 1] = '\0'; // in case...
+ subtypeLen = strlen(mimeSubtype);
+ // Convert the MIME subtype to upper case, for ease of searching:
+ for (i = 0; i < subtypeLen; ++i) {
+ mimeSubtype[i] = toupper(mimeSubtype[i]);
+ }
+ rtp_set_rtpmap_type(codec, "audio", mimeSubtype);
+ }
+
+ // Now gather all of the codecs that were asked for:
+ peercapability = rtp_get_current_codecs();
+ capability |= AST_FORMAT_DTMF|AST_FORMAT_DTMF_CISCO; // include DTMF
p->capability = capability & peercapability;
if (sipdebug)
ast_verbose("Capabilities: us - %d, them - %d, combined - %d\n",
@@ -1722,13 +1760,17 @@
strcat(m, costr);
snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, ast2rtpn(x));
strcat(a, costr);
+ if (x == AST_FORMAT_DTMF ||
+ x == AST_FORMAT_DTMF_CISCO) {
+ /* Indicate we support DTMF only... Not sure about 16, but MSN supports it so dang it, we will too... */
+ snprintf(costr, sizeof costr, "a=fmtp:%d 0-16\r\n",
+ codec);
+ strcat(a, costr);
+ }
}
}
}
- strcat(m, " 101\r\n");
- strcat(a, "a=rtpmap:101 telephone-event/8000\r\n");
- /* Indicate we support DTMF only... Not sure about 16, but MSN supports it so dang it, we will too... */
- strcat(a, "a=fmtp:101 0-16\r\n");
+ strcat(m, "\r\n");
len = strlen(v) + strlen(s) + strlen(o) + strlen(c) + strlen(t) + strlen(m) + strlen(a);
snprintf(costr, sizeof(costr), "%d", len);
add_header(resp, "Content-Type", "application/sdp");
Index: include/asterisk/frame.h
===================================================================
RCS file: /usr/cvsroot/asterisk/include/asterisk/frame.h,v
retrieving revision 1.41
diff -u -r1.41 frame.h
--- include/asterisk/frame.h 5 Feb 2003 19:26:49 -0000 1.41
+++ include/asterisk/frame.h 26 Feb 2003 11:25:11 -0000
@@ -131,6 +131,12 @@
#define AST_FORMAT_G729A (1 << 8)
/*! SpeeX Free Compression */
#define AST_FORMAT_SPEEX (1 << 9)
+/*! DTMF (in RTP) */
+#define AST_FORMAT_DTMF (1 << 10)
+/*! Cisco's proprietary DTMF variant (in RTP) */
+#define AST_FORMAT_DTMF_CISCO (1 << 11)
+/*! Comfort Noise (RFC 3389) (in RTP) */
+#define AST_FORMAT_CN (1 << 12)
/*! Maximum audio format */
#define AST_FORMAT_MAX_AUDIO (1 << 15)
/*! JPEG Images */
Index: include/asterisk/rtp.h
===================================================================
RCS file: /usr/cvsroot/asterisk/include/asterisk/rtp.h,v
retrieving revision 1.7
diff -u -r1.7 rtp.h
--- include/asterisk/rtp.h 15 Feb 2003 23:41:23 -0000 1.7
+++ include/asterisk/rtp.h 26 Feb 2003 11:25:11 -0000
@@ -61,6 +61,14 @@
int ast_rtp_settos(struct ast_rtp *rtp, int tos);
+void rtp_pt_init(void);
+
+void rtp_set_m_type(int pt);
+
+void rtp_set_rtpmap_type(int pt, char* mimeType, char* mimeSubtype);
+
+int rtp_get_current_codecs(void);
+
int ast2rtp(int id);
int rtp2ast(int id);
More information about the asterisk-users
mailing list