diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 3fbf9c48a6..9a5e09db7c 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -632,9 +632,13 @@ typedef enum { This flag will never send any. Sheesh.... */ + RTP_BUG_IGNORE_DTMF_DURATION = (1 << 6) - - + /* + Guess Who? ... Yep, Sonus (and who know's who else) likes to interweave DTMF with the audio stream making it take + 2X as long as it should and sending an incorrect duration making the DTMF very delayed. + This flag will treat every dtmf as if it were 50ms and queue it on recipt of the leading packet rather than at the end. + */ } switch_rtp_bug_flag_t; diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index ffba5ff0a3..a529844059 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -6188,6 +6188,14 @@ void sofia_glue_parse_rtp_bugs(uint32_t *flag_pole, const char *str) if (switch_stristr("~NEVER_SEND_MARKER", str)) { *flag_pole &= ~RTP_BUG_NEVER_SEND_MARKER; } + + if (switch_stristr("IGNORE_DTMF_DURATION", str)) { + *flag_pole |= RTP_BUG_IGNORE_DTMF_DURATION; + } + + if (switch_stristr("~IGNORE_DTMF_DURATION", str)) { + *flag_pole &= ~RTP_BUG_IGNORE_DTMF_DURATION; + } } char *sofia_glue_gen_contact_str(sofia_profile_t *profile, sip_t const *sip, sofia_nat_parse_t *np) diff --git a/src/switch_rtp.c b/src/switch_rtp.c index 41d5fc98dd..eb8b6a19d3 100644 --- a/src/switch_rtp.c +++ b/src/switch_rtp.c @@ -133,6 +133,7 @@ struct switch_rtp_rfc2833_data { char last_digit; switch_queue_t *dtmf_inqueue; switch_mutex_t *dtmf_mutex; + uint8_t in_digit_queued; }; struct switch_rtp { @@ -2479,7 +2480,8 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ } } - if ((!(io_flags & SWITCH_IO_FLAG_NOBLOCK)) && (rtp_session->dtmf_data.out_digit_dur == 0 || switch_test_flag(rtp_session, SWITCH_RTP_FLAG_VIDEO))) { + if ((!(io_flags & SWITCH_IO_FLAG_NOBLOCK)) && + (rtp_session->dtmf_data.out_digit_dur == 0 || switch_test_flag(rtp_session, SWITCH_RTP_FLAG_VIDEO))) { return_cng_frame(); } } @@ -2819,7 +2821,7 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ } #ifdef DEBUG_2833 if (rtp_session->dtmf_data.in_digit_sanity && !(rtp_session->dtmf_data.in_digit_sanity % 100)) { - printf("sanity %d\n", rtp_session->dtmf_data.in_digit_sanity); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "sanity %d\n", rtp_session->dtmf_data.in_digit_sanity); } #endif @@ -2869,7 +2871,7 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ } } #ifdef DEBUG_2833 - printf("packet[%d]: %02x %02x %02x %02x\n", (int) len, (unsigned) packet[0], (unsigned) + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "packet[%d]: %02x %02x %02x %02x\n", (int) len, (unsigned) packet[0], (unsigned) packet[1], (unsigned) packet[2], (unsigned) packet[3]); #endif @@ -2878,16 +2880,28 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ rtp_session->dtmf_data.in_digit_seq = in_digit_seq; #ifdef DEBUG_2833 - printf("read: %c %u %u %u %u %d %d %s\n", + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "read: %c %u %u %u %u %d %d %s\n", key, in_digit_seq, rtp_session->dtmf_data.in_digit_seq, ts, duration, rtp_session->recv_msg.header.m, end, end && !rtp_session->dtmf_data.in_digit_ts ? "ignored" : ""); #endif + + if (!rtp_session->dtmf_data.in_digit_queued && (rtp_session->rtp_bugs & RTP_BUG_IGNORE_DTMF_DURATION) && + rtp_session->dtmf_data.in_digit_ts) { + switch_dtmf_t dtmf = { key, switch_core_min_dtmf_duration(0) }; +#ifdef DEBUG_2833 + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Early Queuing digit %c:%d\n", dtmf.digit, dtmf.duration / 8); +#endif + switch_rtp_queue_rfc2833_in(rtp_session, &dtmf); + rtp_session->dtmf_data.in_digit_queued = 1; + } + /* only set sanity if we do NOT ignore the packet */ if (rtp_session->dtmf_data.in_digit_ts) { rtp_session->dtmf_data.in_digit_sanity = 2000; } - if (rtp_session->dtmf_data.last_duration > duration && rtp_session->dtmf_data.last_duration > 0xFC17 && ts == rtp_session->dtmf_data.in_digit_ts) { + if (rtp_session->dtmf_data.last_duration > duration && + rtp_session->dtmf_data.last_duration > 0xFC17 && ts == rtp_session->dtmf_data.in_digit_ts) { rtp_session->dtmf_data.flip++; } @@ -2902,18 +2916,26 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ dtmf.duration += rtp_session->dtmf_data.flip * 0xFFFF; rtp_session->dtmf_data.flip = 0; #ifdef DEBUG_2833 - printf("you're welcome!\n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "you're welcome!\n"); #endif } #ifdef DEBUG_2833 - printf("done digit=%c ts=%u start_ts=%u dur=%u ddur=%u\n", + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "done digit=%c ts=%u start_ts=%u dur=%u ddur=%u\n", dtmf.digit, ts, rtp_session->dtmf_data.in_digit_ts, duration, dtmf.duration); #endif - switch_rtp_queue_rfc2833_in(rtp_session, &dtmf); + + if (!(rtp_session->rtp_bugs & RTP_BUG_IGNORE_DTMF_DURATION) && !rtp_session->dtmf_data.in_digit_queued) { +#ifdef DEBUG_2833 + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Queuing digit %c:%d\n", dtmf.digit, dtmf.duration / 8); +#endif + switch_rtp_queue_rfc2833_in(rtp_session, &dtmf); + } + rtp_session->dtmf_data.last_digit = rtp_session->dtmf_data.first_digit; rtp_session->dtmf_data.in_digit_ts = 0; rtp_session->dtmf_data.in_digit_sanity = 0; + rtp_session->dtmf_data.in_digit_queued = 0; do_cng = 1; } else { if (!switch_rtp_ready(rtp_session)) { @@ -2932,7 +2954,7 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ rtp_session->dtmf_data.last_duration = duration; } else { #ifdef DEBUG_2833 - printf("drop: %c %u %u %u %u %d %d\n", + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "drop: %c %u %u %u %u %d %d\n", key, in_digit_seq, rtp_session->dtmf_data.in_digit_seq, ts, duration, rtp_session->recv_msg.header.m, end); #endif switch_cond_next(); @@ -3540,7 +3562,7 @@ static int rtp_common_write(switch_rtp_t *rtp_session, #ifdef RTP_DEBUG_WRITE_DELTA { int delta = (int) (now - rtp_session->send_time) / 1000; - printf("WRITE %d delta %d\n", (int) bytes, delta); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "WRITE %d delta %d\n", (int) bytes, delta); } #endif rtp_session->send_time = now;