diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 6c6aa1578af8833e43f7cf78c4e2945ec75ccb8d..d18729ddfbe52c03846916c4cc22c79d467ddec5 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -191,12 +191,13 @@ struct ast_rtp { int rtpkeepalive; /*!< Send RTP comfort noice packets for keepalive */ /* DTMF Reception Variables */ - char resp; - unsigned int lastevent; - unsigned int dtmf_duration; /*!< Total duration in samples since the digit start event */ - unsigned int dtmf_timeout; /*!< When this timestamp is reached we consider END frame lost and forcibly abort digit */ + char resp; /*!< The current digit being processed */ + unsigned int last_seqno; /*!< The last known sequence number for any DTMF packet */ + unsigned int last_end_timestamp; /*!< The last known timestamp received from an END packet */ + unsigned int dtmf_duration; /*!< Total duration in samples since the digit start event */ + unsigned int dtmf_timeout; /*!< When this timestamp is reached we consider END frame lost and forcibly abort digit */ unsigned int dtmfsamples; - enum ast_rtp_dtmf_mode dtmfmode;/*!< The current DTMF mode of the RTP stream */ + enum ast_rtp_dtmf_mode dtmfmode; /*!< The current DTMF mode of the RTP stream */ /* DTMF Transmission Variables */ unsigned int lastdigitts; char sending_digit; /*!< boolean - are we sending digits */ @@ -2155,8 +2156,10 @@ static struct ast_frame *create_dtmf_frame(struct ast_rtp_instance *instance, en rtp->dtmfsamples = 0; return &ast_null_frame; } - ast_debug(1, "Sending dtmf: %d (%c), at %s\n", rtp->resp, rtp->resp, - ast_sockaddr_stringify(&remote_address)); + ast_debug(1, "Creating %s DTMF Frame: %d (%c), at %s\n", + type == AST_FRAME_DTMF_END ? "END" : "BEGIN", + rtp->resp, rtp->resp, + ast_sockaddr_stringify(&remote_address)); if (rtp->resp == 'X') { rtp->f.frametype = AST_FRAME_CONTROL; rtp->f.subclass.integer = AST_CONTROL_FLASH; @@ -2220,12 +2223,12 @@ static void process_dtmf_rfc2833(struct ast_rtp_instance *instance, unsigned cha } if (ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_DTMF_COMPENSATE)) { - if ((rtp->lastevent != timestamp) || (rtp->resp && rtp->resp != resp)) { + if ((rtp->last_end_timestamp != timestamp) || (rtp->resp && rtp->resp != resp)) { rtp->resp = resp; rtp->dtmf_timeout = 0; 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; + rtp->last_end_timestamp = timestamp; AST_LIST_INSERT_TAIL(frames, f, frame_list); } } else { @@ -2242,31 +2245,41 @@ static void process_dtmf_rfc2833(struct ast_rtp_instance *instance, unsigned cha } new_duration = (new_duration & ~0xFFFF) | samples; - /* The second portion of this check is to not mistakenly - * stop accepting DTMF if the seqno rolls over beyond - * 65535. - */ - if (rtp->lastevent > seqno && rtp->lastevent - seqno < 50) { - /* 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) { + if ((rtp->last_seqno != seqno) && (timestamp > rtp->last_end_timestamp)) { + rtp->last_end_timestamp = timestamp; rtp->dtmf_duration = new_duration; + rtp->resp = resp; 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.format)), ast_tv(0, 0)); rtp->resp = 0; rtp->dtmf_duration = rtp->dtmf_timeout = 0; AST_LIST_INSERT_TAIL(frames, f, frame_list); + } else if (rtpdebug) { + ast_debug(1, "Dropping duplicate or out of order DTMF END frame (seqno: %d, ts %d, digit %c)\n", + seqno, timestamp, resp); } } else { /* Begin/continuation */ + /* The second portion of the seqno check is to not mistakenly + * stop accepting DTMF if the seqno rolls over beyond + * 65535. + */ + if ((rtp->last_seqno > seqno && rtp->last_seqno - seqno < 50) + || timestamp <= rtp->last_end_timestamp) { + /* Out of order frame. Processing this can cause us to + * improperly duplicate incoming DTMF, so just drop + * this. + */ + if (rtpdebug) { + ast_debug(1, "Dropping out of order DTMF frame (seqno %d, ts %d, digit %c)\n", + seqno, timestamp, resp); + } + return; + } + if (rtp->resp && rtp->resp != resp) { /* Another digit already began. End it */ f = ast_frdup(create_dtmf_frame(instance, AST_FRAME_DTMF_END, 0)); @@ -2290,7 +2303,7 @@ static void process_dtmf_rfc2833(struct ast_rtp_instance *instance, unsigned cha rtp->dtmf_timeout = timestamp + rtp->dtmf_duration + dtmftimeout; } - rtp->lastevent = seqno; + rtp->last_seqno = seqno; } rtp->dtmfsamples = samples;