]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
res_pjsip_sdp_rtp: Use negotiated DTMF Payload types on bitrate mismatch
authorMike Bradeen <mbradeen@sangoma.com>
Wed, 21 Aug 2024 16:11:31 +0000 (10:11 -0600)
committerAsterisk Development Team <asteriskteam@digium.com>
Thu, 12 Sep 2024 18:46:27 +0000 (18:46 +0000)
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 ac673dd14e2aadb933e76017249cb18a76c556bd)

include/asterisk/rtp_engine.h
main/rtp_engine.c
res/res_pjsip_sdp_rtp.c
res/res_rtp_asterisk.c

index b3519f9176c17949a6495556acd9349328ff0220..0a38e43cd579f5109ddcd1d15c42288d6e2b3554 100644 (file)
@@ -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 */
index 621f12ca008f34b6e1fefa2df30ffc1f4eaeb986..6b2d67bd31e72aeb20b87f87ec834f5822e2a5dd 100644 (file)
@@ -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;
index 98df545397bd5172dc718711e26524f01e1ed209..4423dfda5ccae1746ad00fb78199f7ff5a14676a 100644 (file)
@@ -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++;
                }
 
index c3314612eb78ded9efe542d30d353fcd7865a6a0..495e3de93fd90615ac3dc3ad6d3103ae356849f2 100644 (file)
@@ -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;
        }