[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