res_pjsip_sdp_rtp: Use negotiated DTMF Payload types on bitrate mismatch

When Asterisk sends an offer to Bob that includes 48K and 8K codecs with
matching 4733 offers, Bob may want to use the 48K audio codec but can not
accept 48K digits and so negotiates for a mixed set.

Asterisk will now check Bob's offer to make sure Bob has indicated this is
acceptible and if not, will use Bob's preference.

Fixes: #847
(cherry picked from commit ac673dd14e)
releases/21
Mike Bradeen 8 months ago committed by Asterisk Development Team
parent 57242cbe31
commit 8ad9f7d320

@ -764,10 +764,15 @@ struct ast_rtp_codecs {
unsigned int framing;
/*! The preferred format, as the mappings are numerically sorted */
struct ast_format *preferred_format;
/*! The preferred dtmf sample rate */
int preferred_dtmf_rate;
/*! The preferred dtmf payload type */
int preferred_dtmf_pt;
};
#define AST_RTP_CODECS_NULL_INIT \
{ .codecs_lock = AST_RWLOCK_INIT_VALUE, .payload_mapping_rx = { 0, }, .payload_mapping_tx = { 0, }, .framing = 0, .preferred_format = NULL }
{ .codecs_lock = AST_RWLOCK_INIT_VALUE, .payload_mapping_rx = { 0, }, .payload_mapping_tx = { 0, }, .framing = 0, .preferred_format = NULL, \
.preferred_dtmf_rate = -1, .preferred_dtmf_pt = -1}
/*! Structure that represents the glue that binds an RTP instance to a channel */
struct ast_rtp_glue {
@ -1710,6 +1715,69 @@ struct ast_format *ast_rtp_codecs_get_preferred_format(struct ast_rtp_codecs *co
*/
int ast_rtp_codecs_set_preferred_format(struct ast_rtp_codecs *codecs, struct ast_format *format);
/*!
* \brief Retrieve rx preferred dtmf format payload type
*
* \param codecs Codecs structure to look in
*
* \return Payload type of preferred dtmf format.
* \retval -1 if not set.
*
* Example usage:
*
* \code
* int payload;
* payload = ast_rtp_codecs_get_preferred_dtmf_format_pt(codec);
* \endcode
*
* This looks up the preferred dtmf format pt on the codec
*/
int ast_rtp_codecs_get_preferred_dtmf_format_pt(struct ast_rtp_codecs *codecs);
/*!
* \brief Retrieve rx preferred dtmf format sample rate
*
* \param codecs Codecs structure to look in
*
* \return Sample rate of preferred dtmf format.
* \retval -1 if not set.
*
* Example usage:
*
* \code
* int sample_rate;
* sample_rate = ast_rtp_codecs_get_preferred_dtmf_format_rate(codec);
* \endcode
*
* This looks up the preferred dtmf format sample rate on the codec
*/
int ast_rtp_codecs_get_preferred_dtmf_format_rate(struct ast_rtp_codecs *codecs);
/*!
* \brief Set the preferred dtmf format pt and sample rate
*
* \param codecs Codecs structure to set the preferred format in
* \param pt Preferred dtmf payload type to set.
* \param rate Preferred dtmf payload rate to set.
*
* \return 0
*
* \note The format passed this function has its reference count increased. If an existing
* format is set, that format is replaced.
*
* Example usage:
*
* \code
* int dtmf_code = atoi(dtmf_pt);
* int dtmf_rate = clock_rate;
* ast_rtp_codecs_set_preferred_dtmf_format(codecs, dtmf_code, dtmf_rate);
* \endcode
*
* This sets the preferred dtmf_code and dtmf_rate on the codec.
*/
int ast_rtp_codecs_set_preferred_dtmf_format(struct ast_rtp_codecs *codecs, int pt, int rate);
/*!
* \brief Update the format associated with a tx payload type in a codecs structure
*
@ -2977,6 +3045,20 @@ int ast_rtp_get_rate(const struct ast_format *format);
*/
struct stasis_topic *ast_rtp_topic(void);
/*!
* \brief Determine if a type of payload is already present in mappings.
* \since 18
*
* \param codecs Codecs to be checked for mappings.
* \param to_match Payload type object to compare against.
*
* \note It is assumed that codecs is not locked before calling.
*
* \retval 0 not found
* \retval 1 found
*/
int ast_rtp_payload_mapping_tx_is_present(struct ast_rtp_codecs *codecs, const struct ast_rtp_payload_type *to_match);
/* RTP debug logging category name */
#define AST_LOG_CATEGORY_RTP "rtp"
/* RTP packet debug logging category name */

@ -1217,6 +1217,16 @@ static int payload_mapping_tx_is_present(const struct ast_rtp_codecs *codecs, co
return 0;
}
int ast_rtp_payload_mapping_tx_is_present(struct ast_rtp_codecs *codecs, const struct ast_rtp_payload_type *to_match) {
int ret = 0;
if (codecs && to_match) {
ast_rwlock_rdlock(&codecs->codecs_lock);
ret = payload_mapping_tx_is_present(codecs, to_match);
ast_rwlock_unlock(&codecs->codecs_lock);
}
return ret;
}
/*!
* \internal
* \brief Copy the tx payload type mapping to the destination.
@ -1289,6 +1299,8 @@ void ast_rtp_codecs_payloads_copy(struct ast_rtp_codecs *src, struct ast_rtp_cod
rtp_codecs_payloads_copy_tx(src, dest, instance);
dest->framing = src->framing;
ao2_replace(dest->preferred_format, src->preferred_format);
dest->preferred_dtmf_rate = src->preferred_dtmf_rate;
dest->preferred_dtmf_pt = src->preferred_dtmf_pt;
ast_rwlock_unlock(&src->codecs_lock);
ast_rwlock_unlock(&dest->codecs_lock);
@ -1332,6 +1344,8 @@ void ast_rtp_codecs_payloads_xover(struct ast_rtp_codecs *src, struct ast_rtp_co
dest->framing = src->framing;
ao2_replace(dest->preferred_format, src->preferred_format);
dest->preferred_dtmf_rate = src->preferred_dtmf_rate;
dest->preferred_dtmf_pt = src->preferred_dtmf_pt;
if (src != dest) {
ast_rwlock_unlock(&src->codecs_lock);
@ -1572,6 +1586,33 @@ int ast_rtp_codecs_set_preferred_format(struct ast_rtp_codecs *codecs, struct as
return 0;
}
int ast_rtp_codecs_get_preferred_dtmf_format_pt(struct ast_rtp_codecs *codecs)
{
int pt = -1;
ast_rwlock_rdlock(&codecs->codecs_lock);
pt = codecs->preferred_dtmf_pt;
ast_rwlock_unlock(&codecs->codecs_lock);
return pt;
}
int ast_rtp_codecs_get_preferred_dtmf_format_rate(struct ast_rtp_codecs *codecs)
{
int rate = -1;
ast_rwlock_rdlock(&codecs->codecs_lock);
rate = codecs->preferred_dtmf_rate;
ast_rwlock_unlock(&codecs->codecs_lock);
return rate;
}
int ast_rtp_codecs_set_preferred_dtmf_format(struct ast_rtp_codecs *codecs, int pt, int rate)
{
ast_rwlock_wrlock(&codecs->codecs_lock);
codecs->preferred_dtmf_pt = pt;
codecs->preferred_dtmf_rate = rate;
ast_rwlock_unlock(&codecs->codecs_lock);
return 0;
}
int ast_rtp_codecs_payload_replace_format(struct ast_rtp_codecs *codecs, int payload, struct ast_format *format)
{
struct ast_rtp_payload_type *type;
@ -2087,6 +2128,16 @@ int ast_rtp_codecs_payload_code_tx_sample_rate(struct ast_rtp_codecs *codecs, in
ast_rwlock_rdlock(&static_RTP_PT_lock);
payload = find_static_payload_type(asterisk_format, format, code);
ast_rwlock_unlock(&static_RTP_PT_lock);
ast_rwlock_rdlock(&codecs->codecs_lock);
if (payload >= 0 && payload < AST_VECTOR_SIZE(&codecs->payload_mapping_tx)){
type = AST_VECTOR_GET(&codecs->payload_mapping_tx, payload);
if (!type || (sample_rate != 0 && type->sample_rate != sample_rate)) {
/* Don't use the type if we can't find it or it doesn't match the supplied sample_rate */
payload = -1;
}
}
ast_rwlock_unlock(&codecs->codecs_lock);
}
return payload;

@ -344,6 +344,14 @@ static void get_codecs(struct ast_sip_session *session, const struct pjmedia_sdp
ast_copy_pj_str(name, &rtpmap->enc_name, sizeof(name));
if (strcmp(name, "telephone-event") == 0) {
if (tel_event == 0) {
int dtmf_rate = 0, dtmf_code = 0;
char dtmf_pt[8];
ast_copy_pj_str(dtmf_pt, &rtpmap->pt, sizeof(dtmf_pt));
dtmf_code = atoi(dtmf_pt);
dtmf_rate = rtpmap->clock_rate;
ast_rtp_codecs_set_preferred_dtmf_format(codecs, dtmf_code, dtmf_rate);
}
tel_event++;
}

@ -4283,8 +4283,7 @@ 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;
int hdrlen = 12, res = 0, i = 0, payload = -1, sample_rate = -1;
char data[256];
unsigned int *rtpheader = (unsigned int*)data;
RAII_VAR(struct ast_format *, payload_format, NULL, ao2_cleanup);
@ -4323,16 +4322,26 @@ static int ast_rtp_dtmf_begin(struct ast_rtp_instance *instance, char digit)
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 (sample_rate != -1) {
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 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) {
if (payload == -1 ||
!ast_rtp_payload_mapping_tx_is_present(
ast_rtp_instance_get_codecs(instance), ast_rtp_codecs_get_payload(ast_rtp_instance_get_codecs(instance), payload))) {
/* Fall back to the preferred DTMF payload type and sample rate as either we couldn't find an audio codec to try and match
sample rates with or we could, but a telephone-event matching that audio codec's sample rate was not included in the
sdp negotiated by the far end. */
payload = ast_rtp_codecs_get_preferred_dtmf_format_pt(ast_rtp_instance_get_codecs(instance));
sample_rate = ast_rtp_codecs_get_preferred_dtmf_format_rate(ast_rtp_instance_get_codecs(instance));
}
/* The sdp negotiation has not yeilded a usable RFC 2833/4733 format. Try a default-rate one as a last resort. */
if (payload == -1 || sample_rate == -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. */
/* Even trying a default payload has failed. We are trying to send a digit outside of what was negotiated for. */
if (payload == -1) {
return -1;
}

Loading…
Cancel
Save