aboutsummaryrefslogtreecommitdiffstats
path: root/res/res_rtp_asterisk.c
diff options
context:
space:
mode:
authormmichelson <mmichelson@f38db490-d61c-443f-a65b-d21fe96a405b>2010-03-25 16:04:48 +0000
committermmichelson <mmichelson@f38db490-d61c-443f-a65b-d21fe96a405b>2010-03-25 16:04:48 +0000
commitaca5c91a7c62e4b4ea26d7f75108b086dbae17dd (patch)
tree4b118908bf3396709e838a6c22da43c422399e0e /res/res_rtp_asterisk.c
parent6a78f491d97aaf0f8b6d83e4a4629a0169b8a864 (diff)
Recorded merge of revisions 254452 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4 ........ r254452 | mmichelson | 2010-03-25 10:59:56 -0500 (Thu, 25 Mar 2010) | 44 lines Several fixes regarding RFC2833 DTMF detection. Here is a copy and paste of the details from my request on reviewboard that dealt with these changes: Fix 1. The first change in place is to fix Mantis issue 15811, which deals with a situation where Asterisk will incorrectly interpret out of order RFC2833 frames as duplicate DTMF digits. For instance, we would receive a sequence like: seqno 1: DTMF 1 seqno 2: DTMF 1 seqno 3: DTMF 1 seqno 4: DTMF 1 seqno 6: DTMF 1 (end) seqno 5: DTMF 1 seqno 7: DTMF 1 (end) seqno 8: DTMF 1 (end) Prior to this patch when we received the frame with seqno 5, we would interpret this as a new DTMF 1. With this patch, we will check the seqno of the incoming digit and not process the frame if the seqno is lower than the last recorded seqno. Note that we do not record the seqno of the dropped DTMF frame for future processing. While the above situation is what was designed to be fixed, the patch is written in such a way that the following would also be fixed too: seqno 9: DTMF 1 seqno 10: DTMF 1 (end) seqno 11: DTMF 1 (end) seqno 13: DTMF 2 seqno 12: DTMF 1 (end) seqno 14: DTMF 2 seqno 15: DTMF 2 (end) seqno 16: DTMF 2 (end) seqno 17: DTMF 2 (end) In this second situation, the beginning of the DTMF 2 arrives before the final end frame of the DTMF 1. With the patch, seqno 12 is no processed and thus we properly interpret the DTMF. Fix 2. The second change in place is to fix an issue like the following: seqno 1: DTMF 1 seqno 2: DTMF 1 seqno 3: DTMF 1 (end) *packet lost* seqno 4: DTMF 1 (end) *packet lost* seqno 5: DTMF 1 (end) *packet lost* seqno 6: DTMF 2 When we receive seqno 6, we had code in place that was supposed to properly end the previously unended DTMF 1. The problem was that the code was essentially a no-op. The code would set up an end frame for the DTMF 1 but would immediately overwrite the frame with the begin for DTMF 2. I changed process_dtmf_rfc2833() so that instead of returning a single frame, it is given as an output parameter a list of frames. Each frame that needs to be returned is appended to this list. Fix 3. The final change is a minor one where an AST_CONTROL_SRCCHANGE frame could get lost. If we process a cisco DTMF or an RFC 3389 frame and no frame was returned, then we would return &ast_null_frame. The problem is that earlier in the function, we may have generated an AST_CONTROL_SRCCHANGE frame and put it in the list of frames we wish to return. This frame would be lost in such a case. The patch fixes this problem ........ git-svn-id: http://svn.digium.com/svn/asterisk/trunk@254454 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'res/res_rtp_asterisk.c')
-rw-r--r--res/res_rtp_asterisk.c50
1 files changed, 37 insertions, 13 deletions
diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c
index fb060c75f..af1f1ebca 100644
--- a/res/res_rtp_asterisk.c
+++ b/res/res_rtp_asterisk.c
@@ -249,6 +249,8 @@ struct rtp_red {
long int prev_ts;
};
+AST_LIST_HEAD_NOLOCK(frame_list, ast_frame);
+
/* Forward Declarations */
static int ast_rtp_new(struct ast_rtp_instance *instance, struct sched_context *sched, struct sockaddr_in *sin, void *data);
static int ast_rtp_destroy(struct ast_rtp_instance *instance);
@@ -1281,7 +1283,7 @@ static void calc_rxstamp(struct timeval *tv, struct ast_rtp *rtp, unsigned int t
}
}
-static struct ast_frame *send_dtmf(struct ast_rtp_instance *instance, enum ast_frame_type type, int compensate)
+static struct ast_frame *create_dtmf_frame(struct ast_rtp_instance *instance, enum ast_frame_type type, int compensate)
{
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
struct sockaddr_in remote_address = { 0, };
@@ -1306,11 +1308,12 @@ static struct ast_frame *send_dtmf(struct ast_rtp_instance *instance, enum ast_f
rtp->f.samples = 0;
rtp->f.mallocd = 0;
rtp->f.src = "RTP";
+ AST_LIST_NEXT(&rtp->f, frame_list) = NULL;
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)
+static void 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 frame_list *frames)
{
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
struct sockaddr_in remote_address = { 0, };
@@ -1352,16 +1355,17 @@ static struct ast_frame *process_dtmf_rfc2833(struct ast_rtp_instance *instance,
} else {
/* Not a supported event */
ast_log(LOG_DEBUG, "Ignoring RTP 2833 Event: %08x. Not a DTMF Digit.\n", event);
- return &ast_null_frame;
+ return;
}
if (ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_DTMF_COMPENSATE)) {
if ((rtp->lastevent != timestamp) || (rtp->resp && rtp->resp != resp)) {
rtp->resp = resp;
rtp->dtmf_timeout = 0;
- f = send_dtmf(instance, AST_FRAME_DTMF_END, ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_DTMF_COMPENSATE));
+ f = ast_frdup(create_dtmf_frame(instance, AST_FRAME_DTMF_END, ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_DTMF_COMPENSATE)));
f->len = 0;
rtp->lastevent = timestamp;
+ AST_LIST_INSERT_TAIL(frames, f, frame_list);
}
} else {
/* The duration parameter measures the complete
@@ -1377,24 +1381,34 @@ static struct ast_frame *process_dtmf_rfc2833(struct ast_rtp_instance *instance,
}
new_duration = (new_duration & ~0xFFFF) | samples;
+ if (rtp->lastevent > seqno) {
+ /* Out of order frame. Processing this can cause us to
+ * improperly duplicate incoming DTMF, so just drop
+ * this.
+ */
+ return;
+ }
+
if (event_end & 0x80) {
/* End event */
if ((rtp->lastevent != seqno) && rtp->resp) {
rtp->dtmf_duration = new_duration;
- f = send_dtmf(instance, AST_FRAME_DTMF_END, 0);
+ f = ast_frdup(create_dtmf_frame(instance, AST_FRAME_DTMF_END, 0));
f->len = ast_tvdiff_ms(ast_samp2tv(rtp->dtmf_duration, rtp_get_rate(f->subclass.codec)), ast_tv(0, 0));
rtp->resp = 0;
rtp->dtmf_duration = rtp->dtmf_timeout = 0;
+ AST_LIST_INSERT_TAIL(frames, f, frame_list);
}
} else {
/* Begin/continuation */
if (rtp->resp && rtp->resp != resp) {
/* Another digit already began. End it */
- f = send_dtmf(instance, AST_FRAME_DTMF_END, 0);
+ f = ast_frdup(create_dtmf_frame(instance, AST_FRAME_DTMF_END, 0));
f->len = ast_tvdiff_ms(ast_samp2tv(rtp->dtmf_duration, rtp_get_rate(f->subclass.codec)), ast_tv(0, 0));
rtp->resp = 0;
rtp->dtmf_duration = rtp->dtmf_timeout = 0;
+ AST_LIST_INSERT_TAIL(frames, f, frame_list);
}
if (rtp->resp) {
@@ -1403,8 +1417,9 @@ static struct ast_frame *process_dtmf_rfc2833(struct ast_rtp_instance *instance,
} else {
/* New digit began */
rtp->resp = resp;
- f = send_dtmf(instance, AST_FRAME_DTMF_BEGIN, 0);
+ f = ast_frdup(create_dtmf_frame(instance, AST_FRAME_DTMF_BEGIN, 0));
rtp->dtmf_duration = samples;
+ AST_LIST_INSERT_TAIL(frames, f, frame_list);
}
rtp->dtmf_timeout = timestamp + rtp->dtmf_duration + dtmftimeout;
@@ -1415,7 +1430,7 @@ static struct ast_frame *process_dtmf_rfc2833(struct ast_rtp_instance *instance,
rtp->dtmfsamples = samples;
- return f;
+ return;
}
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)
@@ -1482,11 +1497,11 @@ static struct ast_frame *process_dtmf_cisco(struct ast_rtp_instance *instance, u
rtp->resp = resp;
/* Why we should care on DTMF compensation at reception? */
if (ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_DTMF_COMPENSATE)) {
- f = send_dtmf(instance, AST_FRAME_DTMF_BEGIN, 0);
+ f = create_dtmf_frame(instance, AST_FRAME_DTMF_BEGIN, 0);
rtp->dtmfsamples = 0;
}
} else if ((rtp->resp == resp) && !power) {
- f = send_dtmf(instance, AST_FRAME_DTMF_END, ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_DTMF_COMPENSATE));
+ f = create_dtmf_frame(instance, AST_FRAME_DTMF_END, ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_DTMF_COMPENSATE));
f->samples = rtp->dtmfsamples * (rtp_get_rate(f->subclass.codec) / 1000);
rtp->resp = 0;
} else if (rtp->resp == resp)
@@ -1867,7 +1882,7 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
unsigned int *rtpheader = (unsigned int*)(rtp->rawdata + AST_FRIENDLY_OFFSET), seqno, ssrc, timestamp;
struct ast_rtp_payload_type payload;
struct sockaddr_in remote_address = { 0, };
- AST_LIST_HEAD_NOLOCK(, ast_frame) frames;
+ struct frame_list frames;
/* If this is actually RTCP let's hop on over and handle it */
if (rtcp) {
@@ -2047,7 +2062,11 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
if (!payload.asterisk_format) {
struct ast_frame *f = NULL;
if (payload.code == AST_RTP_DTMF) {
- f = process_dtmf_rfc2833(instance, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen, seqno, timestamp, &sin, payloadtype, mark);
+ /* process_dtmf_rfc2833 may need to return multiple frames. We do this
+ * by passing the pointer to the frame list to it so that the method
+ * can append frames to the list as needed.
+ */
+ process_dtmf_rfc2833(instance, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen, seqno, timestamp, &sin, payloadtype, mark, &frames);
} 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) {
@@ -2058,6 +2077,11 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
if (f) {
AST_LIST_INSERT_TAIL(&frames, f, frame_list);
+ }
+ /* Even if no frame was returned by one of the above methods,
+ * we may have a frame to return in our frame list
+ */
+ if (!AST_LIST_EMPTY(&frames)) {
return AST_LIST_FIRST(&frames);
}
return &ast_null_frame;
@@ -2073,7 +2097,7 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
if (rtp->resp) {
struct ast_frame *f;
- f = send_dtmf(instance, AST_FRAME_DTMF_END, 0);
+ f = create_dtmf_frame(instance, AST_FRAME_DTMF_END, 0);
f->len = ast_tvdiff_ms(ast_samp2tv(rtp->dtmf_duration, rtp_get_rate(f->subclass.codec)), ast_tv(0, 0));
rtp->resp = 0;
rtp->dtmf_timeout = rtp->dtmf_duration = 0;