[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