From d59f1a0c44cb32dad4a22e08b832484e8d72f23c Mon Sep 17 00:00:00 2001 From: Mike Bradeen Date: Fri, 21 Jun 2024 16:56:11 -0600 Subject: [PATCH] res_pjsip_sdp_rtp: Add support for default/mismatched 8K RFC 4733/2833 digits After change made in 624f509 to add support for non 8K RFC 4733/2833 digits, Asterisk would only accept RFC 4733/2833 offers that matched the sample rate of the negotiated codec(s). This change allows Asterisk to accept 8K RFC 4733/2833 offers if the UAC offfers 8K RFC 4733/2833 but negotiates for a non 8K bitrate codec. A number of corresponding tests in tests/channels/pjsip/dtmf_sdp also needed to be re-written to allow for these scenarios. Fixes: #776 --- include/asterisk/rtp_engine.h | 3 +++ res/res_pjsip_sdp_rtp.c | 27 ++++++++++++++++++++++----- res/res_rtp_asterisk.c | 10 ++++++++-- 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/include/asterisk/rtp_engine.h b/include/asterisk/rtp_engine.h index cb555b7797..b3519f9176 100644 --- a/include/asterisk/rtp_engine.h +++ b/include/asterisk/rtp_engine.h @@ -106,6 +106,9 @@ extern "C" { */ #define MAX_CHANNEL_ID 152 +/*!< DTMF samples per second */ +#define DEFAULT_DTMF_SAMPLE_RATE_MS 8000 + struct ast_rtp_instance; struct ast_rtp_glue; diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c index 5e992350ae..c86a505914 100644 --- a/res/res_pjsip_sdp_rtp.c +++ b/res/res_pjsip_sdp_rtp.c @@ -1989,10 +1989,8 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as } if ((attr = generate_rtpmap_attr(session, media, pool, rtp_code, 1, format, 0))) { - int newrate = ast_rtp_lookup_sample_rate2(1, format, 0); int i, added = 0; - media->attr[media->attr_count++] = attr; - + int newrate = ast_rtp_lookup_sample_rate2(1, format, 0); if (build_dtmf_sample_rates) { for (i = 0; i < AST_VECTOR_SIZE(&sample_rates); i++) { /* Only add if we haven't already processed this sample rate. For instance @@ -2007,6 +2005,7 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as AST_VECTOR_APPEND(&sample_rates, newrate); } } + media->attr[media->attr_count++] = attr; } if ((attr = generate_fmtp_attr(pool, format, rtp_code))) { @@ -2032,7 +2031,6 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as continue; } - if (index != AST_RTP_DTMF) { rtp_code = ast_rtp_codecs_payload_code( ast_rtp_instance_get_codecs(session_media->rtp), 0, NULL, index); @@ -2046,7 +2044,7 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as * Walk through the possible bitrates for the RFC 2833/4733 digits and generate the rtpmap * attributes. */ - int i; + int i, found_default_offer = 0; for (i = 0; i < AST_VECTOR_SIZE(&sample_rates); i++) { rtp_code = ast_rtp_codecs_payload_code_sample_rate( ast_rtp_instance_get_codecs(session_media->rtp), 0, NULL, index, AST_VECTOR_GET(&sample_rates, i)); @@ -2055,12 +2053,31 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as continue; } + if (AST_VECTOR_GET(&sample_rates, i) == DEFAULT_DTMF_SAMPLE_RATE_MS) { + /* we found and added a default offer, so no need to include a default one.*/ + found_default_offer = 1; + } + if ((attr = generate_rtpmap_attr2(session, media, pool, rtp_code, 0, NULL, index, AST_VECTOR_GET(&sample_rates, i)))) { media->attr[media->attr_count++] = attr; snprintf(tmp, sizeof(tmp), "%d 0-16", (rtp_code)); attr = pjmedia_sdp_attr_create(pool, "fmtp", pj_cstr(&stmp, tmp)); media->attr[media->attr_count++] = attr; + } + } + + /* If we weren't able to add any matching RFC 2833/4733, assume this endpoint is using a + * mismatched 8K offer and try to add one as a fall-back/default. + */ + if (!found_default_offer) { + rtp_code = ast_rtp_codecs_payload_code_sample_rate( + ast_rtp_instance_get_codecs(session_media->rtp), 0, NULL, index, DEFAULT_DTMF_SAMPLE_RATE_MS); + if (rtp_code != -1 && (attr = generate_rtpmap_attr2(session, media, pool, rtp_code, 0, NULL, index, DEFAULT_DTMF_SAMPLE_RATE_MS))) { + media->attr[media->attr_count++] = attr; + snprintf(tmp, sizeof(tmp), "%d 0-16", (rtp_code)); + attr = pjmedia_sdp_attr_create(pool, "fmtp", pj_cstr(&stmp, tmp)); + media->attr[media->attr_count++] = attr; } } } diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index db763e3ed0..c3314612eb 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -4326,11 +4326,17 @@ static int ast_rtp_dtmf_begin(struct ast_rtp_instance *instance, char digit) /* Grab the matching DTMF type payload */ payload = ast_rtp_codecs_payload_code_tx_sample_rate(ast_rtp_instance_get_codecs(instance), 0, NULL, AST_RTP_DTMF, sample_rate); - /* If this returns -1, we are being asked to send digits for a sample rate that is outside - what was negotiated for. Fall back if possible. */ + /* If this returns -1, we are using a codec with a sample rate that does not have a matching RFC 2833/4733 + offer. The offer may have included a default-rate one that doesn't match the codec rate, so try to use that. */ + if (payload == -1) { + sample_rate = DEFAULT_DTMF_SAMPLE_RATE_MS; + payload = ast_rtp_codecs_payload_code_tx(ast_rtp_instance_get_codecs(instance), 0, NULL, AST_RTP_DTMF); + } + /* No default-rate offer either, trying to send a digit outside of what was negotiated for. */ if (payload == -1) { return -1; } + ast_test_suite_event_notify("DTMF_BEGIN", "Digit: %d\r\nPayload: %d\r\nRate: %d\r\n", digit, payload, sample_rate); ast_debug(1, "Sending digit '%d' at rate %d with payload %d\n", digit, sample_rate, payload);