[asterisk-commits] file: branch file/rtp_engine r129498 - in /team/file/rtp_engine: main/ res/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Jul 9 17:36:40 CDT 2008


Author: file
Date: Wed Jul  9 17:36:39 2008
New Revision: 129498

URL: http://svn.digium.com/view/asterisk?view=rev&rev=129498
Log:
Fix a codec issue I found and bring DTMF back in.

Modified:
    team/file/rtp_engine/main/rtp_engine.c
    team/file/rtp_engine/res/res_rtp_asterisk.c

Modified: team/file/rtp_engine/main/rtp_engine.c
URL: http://svn.digium.com/view/asterisk/team/file/rtp_engine/main/rtp_engine.c?view=diff&rev=129498&r1=129497&r2=129498
==============================================================================
--- team/file/rtp_engine/main/rtp_engine.c (original)
+++ team/file/rtp_engine/main/rtp_engine.c Wed Jul  9 17:36:39 2008
@@ -266,7 +266,7 @@
 {
 	memcpy(&instance->remote_address, address, sizeof(instance->remote_address));
 
-	return -1;
+	return 0;
 }
 
 void ast_rtp_instance_set_prop(struct ast_rtp_instance *instance, enum ast_rtp_property property, int value)
@@ -285,6 +285,7 @@
 	int i;
 
 	for (i = 0; i < AST_RTP_MAX_PT; i++) {
+		ast_debug(1, "Clearing payload %d on %p\n", i, codecs);
 		codecs->payloads[i].isAstFormat = 0;
 		codecs->payloads[i].code = 0;
 		if (instance && instance->engine && instance->engine->payload_set) {
@@ -300,60 +301,71 @@
 	int i;
 
 	for (i = 0; i < AST_RTP_MAX_PT; i++) {
-		codecs->payloads[i].isAstFormat = static_RTP_PT[i].isAstFormat;
-		codecs->payloads[i].code = static_RTP_PT[i].code;
-		if (instance && instance->engine && instance->engine->payload_set) {
-			instance->engine->payload_set(instance, i, codecs->payloads[i].isAstFormat, codecs->payloads[i].code);
-		}
-	}
-
-	return;
-}
-
-void ast_rtp_codecs_payloads_copy(struct ast_rtp_codecs *src, struct ast_rtp_codecs *dest, struct ast_rtp_instance *instance)
-{
-	int i;
-
-	for (i = 0; i < AST_RTP_MAX_PT; i++) {
-		dest->payloads[i].isAstFormat = src->payloads[i].isAstFormat;
-		dest->payloads[i].code = src->payloads[i].code;
-		if (instance && instance->engine && instance->engine->payload_set) {
-			instance->engine->payload_set(instance, i, dest->payloads[i].isAstFormat, dest->payloads[i].code);
-		}
-	}
-
-	return;
-}
-
-void ast_rtp_codecs_payloads_set_m_type(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, int payload)
-{
-	if (payload < 0 || payload > AST_RTP_MAX_PT || !static_RTP_PT[payload].code) {
-		return;
-	}
-
-	codecs->payloads[payload] = static_RTP_PT[payload];
-
-	if (instance && instance->engine && instance->engine->payload_set) {
-		instance->engine->payload_set(instance, payload, codecs->payloads[payload].isAstFormat, codecs->payloads[payload].code);
-	}
-
-	return;
-}
-
-int ast_rtp_codecs_payloads_set_rtpmap_type(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, int payload, const char *mimeType, const char *mimeSubtype, enum ast_rtp_options options)
-{
-	int i;
-
-	if (payload < 0 || payload > AST_RTP_MAX_PT) {
-		return -1;
-	}
-
-	for (i = 0; i < AST_RTP_MAX_PT; i++) {
-		if (!strcasecmp(mimeTypes[i].subtype, mimeSubtype) && !strcasecmp(mimeTypes[i].type, mimeType)) {
-			codecs->payloads[i] = mimeTypes[i].payloadType;
+		if (static_RTP_PT[i].code) {
+			ast_debug(1, "Set default payload %d on %p\n", i, codecs);
+			codecs->payloads[i].isAstFormat = static_RTP_PT[i].isAstFormat;
+			codecs->payloads[i].code = static_RTP_PT[i].code;
 			if (instance && instance->engine && instance->engine->payload_set) {
 				instance->engine->payload_set(instance, i, codecs->payloads[i].isAstFormat, codecs->payloads[i].code);
 			}
+		}
+	}
+
+	return;
+}
+
+void ast_rtp_codecs_payloads_copy(struct ast_rtp_codecs *src, struct ast_rtp_codecs *dest, struct ast_rtp_instance *instance)
+{
+	int i;
+
+	for (i = 0; i < AST_RTP_MAX_PT; i++) {
+		if (src->payloads[i].code) { 
+			ast_debug(1, "Copying payload %d from %p to %p\n", i, src, dest);
+			dest->payloads[i].isAstFormat = src->payloads[i].isAstFormat;
+			dest->payloads[i].code = src->payloads[i].code;
+			if (instance && instance->engine && instance->engine->payload_set) {
+				instance->engine->payload_set(instance, i, dest->payloads[i].isAstFormat, dest->payloads[i].code);
+			}
+		}
+	}
+
+	return;
+}
+
+void ast_rtp_codecs_payloads_set_m_type(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, int payload)
+{
+	if (payload < 0 || payload > AST_RTP_MAX_PT || !static_RTP_PT[payload].code) {
+		return;
+	}
+
+	codecs->payloads[payload].isAstFormat = static_RTP_PT[payload].isAstFormat;
+	codecs->payloads[payload].code = static_RTP_PT[payload].code;
+
+	ast_debug(1, "Setting payload %d based on m type on %p\n", payload, codecs);
+
+	if (instance && instance->engine && instance->engine->payload_set) {
+		instance->engine->payload_set(instance, payload, codecs->payloads[payload].isAstFormat, codecs->payloads[payload].code);
+	}
+
+	return;
+}
+
+int ast_rtp_codecs_payloads_set_rtpmap_type(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, int payload, const char *mimeType, const char *mimeSubtype, enum ast_rtp_options options)
+{
+	int i;
+
+	if (payload < 0 || payload > AST_RTP_MAX_PT) {
+		return -1;
+	}
+
+	for (i = 0; i < AST_RTP_MAX_PT; i++) {
+		if (!strcasecmp(mimeTypes[i].subtype, mimeSubtype) && !strcasecmp(mimeTypes[i].type, mimeType)) {
+			ast_debug(1, "Setting payload %d based on rtpmap on %p\n", payload, codecs);
+			codecs->payloads[payload].isAstFormat = mimeTypes[i].payloadType.isAstFormat;
+			codecs->payloads[payload].code = mimeTypes[i].payloadType.code;
+			if (instance && instance->engine && instance->engine->payload_set) {
+				instance->engine->payload_set(instance, payload, codecs->payloads[i].isAstFormat, codecs->payloads[i].code);
+			}
 			return 0;
 		}
 	}
@@ -367,6 +379,7 @@
 		return;
 	}
 
+	ast_debug(1, "Unsetting payload %d on %p\n", payload, codecs);
 	codecs->payloads[payload].isAstFormat = 0;
 	codecs->payloads[payload].code = 0;
 
@@ -385,7 +398,8 @@
 		return result;
 	}
 
-	result = codecs->payloads[payload];
+	result.isAstFormat = codecs->payloads[payload].isAstFormat;
+	result.code = codecs->payloads[payload].code;
 
 	if (!result.code) {
 		result = static_RTP_PT[payload];
@@ -401,6 +415,9 @@
 	*AstFormats = *nonAstFormats = 0;
 
 	for (i = 0; i < AST_RTP_MAX_PT; i++) {
+		if (codecs->payloads[i].code) {
+			ast_debug(1, "Incorporating payload %d on %p\n", i, codecs);
+		}
 		if (codecs->payloads[i].isAstFormat) {
 			*AstFormats |= codecs->payloads[i].code;
 		} else {
@@ -417,6 +434,7 @@
 
 	for (i = 0; i < AST_RTP_MAX_PT; i++) {
 		if (codecs->payloads[i].isAstFormat == isAstFormat && codecs->payloads[i].code == code) {
+			ast_debug(1, "Found code %d at payload %d on %p\n", code, i, codecs);
 			return i;
 		}
 	}

Modified: team/file/rtp_engine/res/res_rtp_asterisk.c
URL: http://svn.digium.com/view/asterisk/team/file/rtp_engine/res/res_rtp_asterisk.c?view=diff&rev=129498&r1=129497&r2=129498
==============================================================================
--- team/file/rtp_engine/res/res_rtp_asterisk.c (original)
+++ team/file/rtp_engine/res/res_rtp_asterisk.c Wed Jul  9 17:36:39 2008
@@ -154,6 +154,8 @@
 	struct sockaddr_in strict_rtp_address;  /*!< Remote address information for strict RTP purposes */
 
 	unsigned int set_marker_bit:1;           /*!< Whether to set the marker bit or not */
+	unsigned int dtmf_compensate:1;
+	unsigned int cn_warning:1;
 };
 
 /*!
@@ -851,6 +853,212 @@
 	}
 }
 
+static struct ast_frame *send_dtmf(struct ast_rtp_instance *instance, enum ast_frame_type type, int compensate)
+{
+	struct ast_rtp *rtp = instance->data;
+
+        if (((compensate && type == AST_FRAME_DTMF_END) || (type == AST_FRAME_DTMF_BEGIN)) && ast_tvcmp(ast_tvnow(), rtp->dtmfmute) < 0) {
+                ast_debug(1, "Ignore potential DTMF echo from '%s'\n", ast_inet_ntoa(instance->remote_address.sin_addr));
+                rtp->resp = 0;
+                rtp->dtmfsamples = 0;
+                return &ast_null_frame;
+        }
+        ast_debug(1, "Sending dtmf: %d (%c), at %s\n", rtp->resp, rtp->resp, ast_inet_ntoa(instance->remote_address.sin_addr));
+        if (rtp->resp == 'X') {
+                rtp->f.frametype = AST_FRAME_CONTROL;
+                rtp->f.subclass = AST_CONTROL_FLASH;
+        } else {
+                rtp->f.frametype = type;
+                rtp->f.subclass = rtp->resp;
+        }
+        rtp->f.datalen = 0;
+        rtp->f.samples = 0;
+        rtp->f.mallocd = 0;
+        rtp->f.src = "RTP";
+
+        return &rtp->f;
+}
+
+static struct ast_frame *process_dtmf_rfc2833(struct ast_rtp_instance *instance, unsigned char *data, int len, unsigned int seqno, unsigned int timestamp, struct sockaddr_in *sin, int payloadtype, int mark)
+{
+	struct ast_rtp *rtp = instance->data;
+	unsigned int event, event_end, samples;
+	char resp;
+	struct ast_frame *f = NULL;
+
+        /* Figure out event, event end, and samples */
+        event = ntohl(*((unsigned int *)(data)));
+        event >>= 24;
+        event_end = ntohl(*((unsigned int *)(data)));
+        event_end <<= 8;
+        event_end >>= 24;
+        samples = ntohl(*((unsigned int *)(data)));
+        samples &= 0xFFFF;
+
+	ast_verbose("Got  RTP RFC2833 from   %s:%u (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u, mark %d, event %08x, end %d, duration %-5.5d) \n", ast_inet_ntoa(instance->remote_address.sin_addr), ntohs(instance->remote_address.sin_port), payloadtype, seqno, timestamp, len, (mark?1:0), event, ((event_end & 0x80)?1:0), samples);
+
+        /* Print out debug if turned on */
+        if (rtpdebug || option_debug > 2)
+                ast_debug(0, "- RTP 2833 Event: %08x (len = %d)\n", event, len);
+
+        /* Figure out what digit was pressed */
+        if (event < 10) {
+                resp = '0' + event;
+        } else if (event < 11) {
+                resp = '*';
+        } else if (event < 12) {
+                resp = '#';
+        } else if (event < 16) {
+                resp = 'A' + (event - 12);
+        } else if (event < 17) {        /* Event 16: Hook flash */
+                resp = 'X';
+        } else {
+                /* Not a supported event */
+                ast_log(LOG_DEBUG, "Ignoring RTP 2833 Event: %08x. Not a DTMF Digit.\n", event);
+                return &ast_null_frame;
+        }
+
+	if (instance->properties[AST_RTP_PROPERTY_DTMF_COMPENSATE]) {
+                if ((rtp->lastevent != timestamp) || (rtp->resp && rtp->resp != resp)) {
+                        rtp->resp = resp;
+                        f = send_dtmf(instance, AST_FRAME_DTMF_END, instance->properties[AST_RTP_PROPERTY_DTMF_COMPENSATE]);
+                        f->len = 0;
+                        rtp->lastevent = timestamp;
+                }
+        } else {
+                if ((!(rtp->resp) && (!(event_end & 0x80))) || (rtp->resp && rtp->resp != resp)) {
+                        rtp->resp = resp;
+                        f = send_dtmf(instance, AST_FRAME_DTMF_BEGIN, 0);
+                } else if ((event_end & 0x80) && (rtp->lastevent != seqno) && rtp->resp) {
+                        f = send_dtmf(instance, AST_FRAME_DTMF_END, 0);
+                        f->len = ast_tvdiff_ms(ast_samp2tv(samples, 8000), ast_tv(0, 0)); /* XXX hard coded 8kHz */
+                        rtp->resp = 0;
+                        rtp->lastevent = seqno;
+                }
+        }
+
+        rtp->dtmfcount = dtmftimeout;
+        rtp->dtmfsamples = samples;
+
+        return f;
+}
+
+static struct ast_frame *process_dtmf_cisco(struct ast_rtp_instance *instance, unsigned char *data, int len, unsigned int seqno, unsigned int timestamp, struct sockaddr_in *sin, int payloadtype, int mark)
+{
+	struct ast_rtp *rtp = instance->data;
+	unsigned int event, flags, power;
+	char resp;
+	unsigned char seq;
+	struct ast_frame *f = NULL;
+
+	if (len < 4) {
+		return NULL;
+	}
+
+        /*      The format of Cisco RTP DTMF packet looks like next:
+                +0                              - sequence number of DTMF RTP packet (begins from 1,
+                                                  wrapped to 0)
+                +1                              - set of flags
+                +1 (bit 0)              - flaps by different DTMF digits delimited by audio
+                                                  or repeated digit without audio???
+                +2 (+4,+6,...)  - power level? (rises from 0 to 32 at begin of tone
+                                                  then falls to 0 at its end)
+                +3 (+5,+7,...)  - detected DTMF digit (0..9,*,#,A-D,...)
+                Repeated DTMF information (bytes 4/5, 6/7) is history shifted right
+                by each new packet and thus provides some redudancy.
+
+                Sample of Cisco RTP DTMF packet is (all data in hex):
+                        19 07 00 02 12 02 20 02
+                showing end of DTMF digit '2'.
+
+                The packets
+                        27 07 00 02 0A 02 20 02
+                        28 06 20 02 00 02 0A 02
+                shows begin of new digit '2' with very short pause (20 ms) after
+                previous digit '2'. Bit +1.0 flips at begin of new digit.
+
+                Cisco RTP DTMF packets comes as replacement of audio RTP packets
+                so its uses the same sequencing and timestamping rules as replaced
+                audio packets. Repeat interval of DTMF packets is 20 ms and not rely
+                on audio framing parameters. Marker bit isn't used within stream of
+                DTMFs nor audio stream coming immediately after DTMF stream. Timestamps
+                are not sequential at borders between DTMF and audio streams,
+	*/
+
+        seq = data[0];
+        flags = data[1];
+        power = data[2];
+        event = data[3] & 0x1f;
+
+        if (option_debug > 2 || rtpdebug)
+                ast_debug(0, "Cisco DTMF Digit: %02x (len=%d, seq=%d, flags=%02x, power=%d, history count=%d)\n", event, len, seq, flags, power, (len - 4) / 2);
+        if (event < 10) {
+                resp = '0' + event;
+        } else if (event < 11) {
+                resp = '*';
+        } else if (event < 12) {
+                resp = '#';
+        } else if (event < 16) {
+                resp = 'A' + (event - 12);
+        } else if (event < 17) {
+                resp = 'X';
+        }
+        if ((!rtp->resp && power) || (rtp->resp && (rtp->resp != resp))) {
+                rtp->resp = resp;
+                /* Why we should care on DTMF compensation at reception? */
+                if (!instance->properties[AST_RTP_PROPERTY_DTMF_COMPENSATE]) {
+                        f = send_dtmf(instance, AST_FRAME_DTMF_BEGIN, 0);
+                        rtp->dtmfsamples = 0;
+                }
+        } else if ((rtp->resp == resp) && !power) {
+                f = send_dtmf(instance, AST_FRAME_DTMF_END, instance->properties[AST_RTP_PROPERTY_DTMF_COMPENSATE] ? 1 : 0);
+                f->samples = rtp->dtmfsamples * 8;
+                rtp->resp = 0;
+        } else if (rtp->resp == resp)
+                rtp->dtmfsamples += 20 * 8;
+        rtp->dtmfcount = dtmftimeout;
+
+	return f;
+}
+
+static struct ast_frame *process_cn_rfc3389(struct ast_rtp_instance *instance, unsigned char *data, int len, unsigned int seqno, unsigned int timestamp, struct sockaddr_in *sin, int payloadtype, int mark)
+{
+	struct ast_rtp *rtp = instance->data;
+
+        /* Convert comfort noise into audio with various codecs.  Unfortunately this doesn't
+           totally help us out becuase we don't have an engine to keep it going and we are not
+           guaranteed to have it every 20ms or anything */
+        if (rtpdebug)
+                ast_debug(0, "- RTP 3389 Comfort noise event: Level %d (len = %d)\n", rtp->lastrxformat, len);
+
+	if (!rtp->cn_warning) {
+                ast_log(LOG_NOTICE, "Comfort noise support incomplete in Asterisk (RFC 3389). Please turn off on client if possible. Client IP: %s\n",
+                        ast_inet_ntoa(instance->remote_address.sin_addr));
+		rtp->cn_warning = 1;
+        }
+
+        /* Must have at least one byte */
+        if (!len)
+                return NULL;
+        if (len < 24) {
+                rtp->f.data.ptr = rtp->rawdata + AST_FRIENDLY_OFFSET;
+                rtp->f.datalen = len - 1;
+                rtp->f.offset = AST_FRIENDLY_OFFSET;
+                memcpy(rtp->f.data.ptr, data + 1, len - 1);
+        } else {
+                rtp->f.data.ptr = NULL;
+                rtp->f.offset = 0;
+                rtp->f.datalen = 0;
+        }
+        rtp->f.frametype = AST_FRAME_CNG;
+        rtp->f.subclass = data[0] & 0x7f;
+        rtp->f.datalen = len - 1;
+        rtp->f.samples = 0;
+        rtp->f.delivery.tv_usec = rtp->f.delivery.tv_sec = 0;
+
+	return &rtp->f;
+}
+
 static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtcp)
 {
 	struct ast_rtp *rtp = instance->data;
@@ -974,9 +1182,14 @@
 	if (!payload.isAstFormat) {
 		struct ast_frame *f = NULL;
 
+		ast_log(LOG_NOTICE, "uh hi\n");
+
 		if (payload.code == AST_RTP_DTMF) {
+			f = process_dtmf_rfc2833(instance, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen, seqno, timestamp, &sin, payloadtype, mark);
 		} else if (payload.code == AST_RTP_CISCO_DTMF) {
+			f = process_dtmf_cisco(instance, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen, seqno, timestamp, &sin, payloadtype, mark);
 		} else if (payload.code == AST_RTP_CN) {
+			f = process_cn_rfc3389(instance, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen, seqno, timestamp, &sin, payloadtype, mark);
 		} else {
 			ast_log(LOG_NOTICE, "Unknown RTP codec %d received from '%s'\n", payloadtype, ast_inet_ntoa(instance->remote_address.sin_addr));
 		}




More information about the asterisk-commits mailing list