rtp_engine: add support for multirate RFC2833 digits

Add RFC2833 DTMF support for 16K, 24K, and 32K bitrate codecs.

Asterisk currently treats RFC2833 Digits as a single rtp payload type
with a fixed bitrate of 8K.  This change would expand that to 8, 16,
24 and 32K.

This requires checking the offered rtp types for any of these bitrates
and then adding an offer for each (if configured for RFC2833.)  DTMF
generation must also be changed in order to look at the current outbound
codec in order to generate appropriately timed rtp.

For cases where no outgoing audio has yet been sent prior to digit
generation, Asterisk now has a concept of a 'preferred' codec based on
offer order.

On inbound calls Asterisk will mimic the payload types of the RFC2833
digits.

On outbound calls Asterisk will choose the next free payload types starting
with 101.

UserNote: No change in configuration is required in order to enable this
feature. Endpoints configured to use RFC2833 will automatically have this
enabled. If the endpoint does not support this, it should not include it in
the SDP offer/response.

Resolves: #699
(cherry picked from commit 182ea91fc5)
This commit is contained in:
Mike Bradeen
2024-04-08 11:00:14 -06:00
committed by Asterisk Development Team
parent 14367caaf7
commit 728dbdccd1
4 changed files with 361 additions and 36 deletions

View File

@@ -138,7 +138,6 @@
#define RTCP_PT_PSFB AST_RTP_RTCP_PSFB
#define RTP_MTU 1200
#define DTMF_SAMPLE_RATE_MS 8 /*!< DTMF samples per millisecond */
#define DEFAULT_DTMF_TIMEOUT (150 * (8000 / 1000)) /*!< samples */
@@ -434,6 +433,7 @@ struct ast_rtp {
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 */
unsigned int dtmf_samplerate_ms; /*!< The sample rate of the current RTP stream in ms (sample rate / 1000) */
/* DTMF Transmission Variables */
unsigned int lastdigitts;
char sending_digit; /*!< boolean - are we sending digits */
@@ -4284,8 +4284,10 @@ static int ast_rtp_dtmf_begin(struct ast_rtp_instance *instance, char digit)
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
struct ast_sockaddr remote_address = { {0,} };
int hdrlen = 12, res = 0, i = 0, payload = 101;
unsigned int sample_rate = 8000;
char data[256];
unsigned int *rtpheader = (unsigned int*)data;
RAII_VAR(struct ast_format *, payload_format, NULL, ao2_cleanup);
ast_rtp_instance_get_remote_address(instance, &remote_address);
@@ -4310,12 +4312,32 @@ static int ast_rtp_dtmf_begin(struct ast_rtp_instance *instance, char digit)
return -1;
}
/* Grab the payload that they expect the RFC2833 packet to be received in */
payload = ast_rtp_codecs_payload_code_tx(ast_rtp_instance_get_codecs(instance), 0, NULL, AST_RTP_DTMF);
if (rtp->lasttxformat == ast_format_none) {
/* No audio frames have been written yet so we have to lookup both the preferred payload type and bitrate. */
payload_format = ast_rtp_codecs_get_preferred_format(ast_rtp_instance_get_codecs(instance));
if (payload_format) {
/* If we have a preferred type, use that. Otherwise default to 8K. */
sample_rate = ast_format_get_sample_rate(payload_format);
}
} else {
sample_rate = ast_format_get_sample_rate(rtp->lasttxformat);
}
/* 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 (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);
rtp->dtmfmute = ast_tvadd(ast_tvnow(), ast_tv(0, 500000));
rtp->send_duration = 160;
rtp->lastts += calc_txstamp(rtp, NULL) * DTMF_SAMPLE_RATE_MS;
rtp->dtmf_samplerate_ms = (sample_rate / 1000);
rtp->lastts += calc_txstamp(rtp, NULL) * rtp->dtmf_samplerate_ms;
rtp->lastdigitts = rtp->lastts + rtp->send_duration;
/* Create the actual packet that we will be sending */
@@ -4394,7 +4416,7 @@ static int ast_rtp_dtmf_continuation(struct ast_rtp_instance *instance)
/* And now we increment some values for the next time we swing by */
rtp->seqno++;
rtp->send_duration += 160;
rtp->lastts += calc_txstamp(rtp, NULL) * DTMF_SAMPLE_RATE_MS;
rtp->lastts += calc_txstamp(rtp, NULL) * rtp->dtmf_samplerate_ms;
return 0;
}
@@ -4472,7 +4494,7 @@ static int ast_rtp_dtmf_end_with_duration(struct ast_rtp_instance *instance, cha
res = 0;
/* Oh and we can't forget to turn off the stuff that says we are sending DTMF */
rtp->lastts += calc_txstamp(rtp, NULL) * DTMF_SAMPLE_RATE_MS;
rtp->lastts += calc_txstamp(rtp, NULL) * rtp->dtmf_samplerate_ms;
/* Reset the smoother as the delivery time stored in it is now out of date */
if (rtp->smoother) {