CHANNEL(callid): Give dialplan access to the callid.
[asterisk/asterisk.git] / main / rtp_engine.c
index 229af8f..931f89d 100644 (file)
                                        and sending this report.</para>
                                </parameter>
                        </syntax>
+                       <see-also>
+                               <ref type="managerEvent">RTCPReceived</ref>
+                       </see-also>
                </managerEventInstance>
        </managerEvent>
        <managerEvent language="en_US" name="RTCPReceived">
                                <xi:include xpointer="xpointer(/docs/managerEvent[@name='RTCPSent']/managerEventInstance/syntax/parameter[@name='SentOctets'])" />
                                <xi:include xpointer="xpointer(/docs/managerEvent[@name='RTCPSent']/managerEventInstance/syntax/parameter[contains(@name, 'ReportX')])" />
                        </syntax>
+                       <see-also>
+                               <ref type="managerEvent">RTCPSent</ref>
+                       </see-also>
                </managerEventInstance>
        </managerEvent>
  ***/
 
 #include "asterisk.h"
 
-ASTERISK_REGISTER_FILE()
-
-#include <math.h>
-
-#include "asterisk/channel.h"
-#include "asterisk/frame.h"
-#include "asterisk/module.h"
-#include "asterisk/rtp_engine.h"
+#include <math.h>                       /* for sqrt, MAX */
+#include <sched.h>                      /* for sched_yield */
+#include <sys/time.h>                   /* for timeval */
+#include <time.h>                       /* for time_t */
+
+#include "asterisk/_private.h"          /* for ast_rtp_engine_init prototype */
+#include "asterisk/astobj2.h"           /* for ao2_cleanup, ao2_ref, etc */
+#include "asterisk/channel.h"           /* for ast_channel_name, etc */
+#include "asterisk/codec.h"             /* for ast_codec_media_type2str, etc */
+#include "asterisk/format.h"            /* for ast_format_cmp, etc */
+#include "asterisk/format_cache.h"      /* for ast_format_adpcm, etc */
+#include "asterisk/format_cap.h"        /* for ast_format_cap_alloc, etc */
+#include "asterisk/json.h"              /* for ast_json_ref, etc */
+#include "asterisk/linkedlists.h"       /* for ast_rtp_engine::<anonymous>, etc */
+#include "asterisk/lock.h"              /* for ast_rwlock_unlock, etc */
+#include "asterisk/logger.h"            /* for ast_log, ast_debug, etc */
 #include "asterisk/manager.h"
-#include "asterisk/options.h"
-#include "asterisk/astobj2.h"
-#include "asterisk/pbx.h"
-#include "asterisk/translate.h"
-#include "asterisk/netsock2.h"
-#include "asterisk/_private.h"
-#include "asterisk/framehook.h"
-#include "asterisk/stasis.h"
-#include "asterisk/json.h"
-#include "asterisk/stasis_channels.h"
+#include "asterisk/module.h"            /* for ast_module_unref, etc */
+#include "asterisk/netsock2.h"          /* for ast_sockaddr_copy, etc */
+#include "asterisk/options.h"           /* for ast_option_rtpptdynamic */
+#include "asterisk/pbx.h"               /* for pbx_builtin_setvar_helper */
+#include "asterisk/res_srtp.h"          /* for ast_srtp_res */
+#include "asterisk/rtp_engine.h"        /* for ast_rtp_codecs, etc */
+#include "asterisk/stasis.h"            /* for stasis_message_data, etc */
+#include "asterisk/stasis_channels.h"   /* for ast_channel_stage_snapshot, etc */
+#include "asterisk/strings.h"           /* for ast_str_append, etc */
+#include "asterisk/time.h"              /* for ast_tvdiff_ms, ast_tvnow */
+#include "asterisk/translate.h"         /* for ast_translate_available_formats */
+#include "asterisk/utils.h"             /* for ast_free, ast_strdup, etc */
+#include "asterisk/vector.h"            /* for AST_VECTOR_GET, etc */
 
 struct ast_srtp_res *res_srtp = NULL;
 struct ast_srtp_policy_res *res_srtp_policy = NULL;
@@ -188,6 +205,8 @@ struct ast_rtp_instance {
        struct ast_rtp_glue *glue;
        /*! SRTP info associated with the instance */
        struct ast_srtp *srtp;
+       /*! SRTP info dedicated for RTCP associated with the instance */
+       struct ast_srtp *rtcp_srtp;
        /*! Channel unique ID */
        char channel_uniqueid[AST_MAX_UNIQUEID];
        /*! Time of last packet sent */
@@ -364,6 +383,10 @@ static void instance_destructor(void *obj)
                res_srtp->destroy(instance->srtp);
        }
 
+       if (instance->rtcp_srtp) {
+               res_srtp->destroy(instance->rtcp_srtp);
+       }
+
        ast_rtp_codecs_payloads_destroy(&instance->codecs);
 
        /* Drop our engine reference */
@@ -640,11 +663,13 @@ static void payload_mapping_rx_clear_primary(struct ast_rtp_codecs *codecs, stru
        int idx;
        struct ast_rtp_payload_type *current;
        struct ast_rtp_payload_type *new_type;
+       struct timeval now;
 
        if (!to_match->primary_mapping) {
                return;
        }
 
+       now = ast_tvnow();
        for (idx = 0; idx < AST_VECTOR_SIZE(&codecs->payload_mapping_rx); ++idx) {
                current = AST_VECTOR_GET(&codecs->payload_mapping_rx, idx);
 
@@ -670,6 +695,7 @@ static void payload_mapping_rx_clear_primary(struct ast_rtp_codecs *codecs, stru
                }
                *new_type = *current;
                new_type->primary_mapping = 0;
+               new_type->when_retired = now;
                ao2_bump(new_type->format);
                AST_VECTOR_REPLACE(&codecs->payload_mapping_rx, idx, new_type);
                ao2_ref(current, -1);
@@ -678,6 +704,31 @@ static void payload_mapping_rx_clear_primary(struct ast_rtp_codecs *codecs, stru
 
 /*!
  * \internal
+ * \brief Put the new_type into the rx payload type mapping.
+ * \since 14.0.0
+ *
+ * \param codecs Codecs structure to put new_type into
+ * \param payload type position to replace.
+ * \param new_type RTP payload mapping object to store.
+ *
+ * \note It is assumed that codecs is write locked before calling.
+ *
+ * \return Nothing
+ */
+static void rtp_codecs_payload_replace_rx(struct ast_rtp_codecs *codecs, int payload, struct ast_rtp_payload_type *new_type)
+{
+       ao2_ref(new_type, +1);
+       if (payload < AST_VECTOR_SIZE(&codecs->payload_mapping_rx)) {
+               ao2_t_cleanup(AST_VECTOR_GET(&codecs->payload_mapping_rx, payload),
+                       "cleaning up rx mapping vector element about to be replaced");
+       }
+       AST_VECTOR_REPLACE(&codecs->payload_mapping_rx, payload, new_type);
+
+       payload_mapping_rx_clear_primary(codecs, new_type);
+}
+
+/*!
+ * \internal
  * \brief Copy the rx payload type mapping to the destination.
  * \since 14.0.0
  *
@@ -703,14 +754,7 @@ static void rtp_codecs_payloads_copy_rx(struct ast_rtp_codecs *src, struct ast_r
 
                ast_debug(2, "Copying rx payload mapping %d (%p) from %p to %p\n",
                        idx, type, src, dest);
-               ao2_ref(type, +1);
-               if (idx < AST_VECTOR_SIZE(&dest->payload_mapping_rx)) {
-                       ao2_t_cleanup(AST_VECTOR_GET(&dest->payload_mapping_rx, idx),
-                               "cleaning up rx mapping vector element about to be replaced");
-               }
-               AST_VECTOR_REPLACE(&dest->payload_mapping_rx, idx, type);
-
-               payload_mapping_rx_clear_primary(dest, type);
+               rtp_codecs_payload_replace_rx(dest, idx, type);
 
                if (instance && instance->engine && instance->engine->payload_set) {
                        instance->engine->payload_set(instance, idx, type->asterisk_format, type->format, type->rtp_code);
@@ -720,18 +764,18 @@ static void rtp_codecs_payloads_copy_rx(struct ast_rtp_codecs *src, struct ast_r
 
 /*!
  * \internal
- * \brief Remove other matching payload mappings.
+ * \brief Determine if a type of payload is already present in mappings.
  * \since 14.0.0
  *
- * \param codecs Codecs that need tx mappings removed.
- * \param instance RTP instance to notify of any payloads removed.
+ * \param codecs Codecs to be checked for mappings.
  * \param to_match Payload type object to compare against.
  *
  * \note It is assumed that codecs is write locked before calling.
  *
- * \return Nothing
+ * \retval 0 not found
+ * \retval 1 found
  */
-static void payload_mapping_tx_remove_other_mappings(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, struct ast_rtp_payload_type *to_match)
+static int payload_mapping_tx_is_present(const struct ast_rtp_codecs *codecs, const struct ast_rtp_payload_type *to_match)
 {
        int idx;
        struct ast_rtp_payload_type *current;
@@ -739,12 +783,18 @@ static void payload_mapping_tx_remove_other_mappings(struct ast_rtp_codecs *code
        for (idx = 0; idx < AST_VECTOR_SIZE(&codecs->payload_mapping_tx); ++idx) {
                current = AST_VECTOR_GET(&codecs->payload_mapping_tx, idx);
 
-               if (!current || current == to_match) {
+               if (!current) {
                        continue;
                }
+               if (current == to_match) {
+                       /* The exact object is already in the mapping. */
+                       return 1;
+               }
                if (current->asterisk_format && to_match->asterisk_format) {
-                       if (ast_format_cmp(current->format, to_match->format) == AST_FORMAT_CMP_NOT_EQUAL) {
+                       if (ast_format_get_codec_id(current->format) != ast_format_get_codec_id(to_match->format)) {
                                continue;
+                       } else if (current->payload == to_match->payload) {
+                               return 0;
                        }
                } else if (!current->asterisk_format && !to_match->asterisk_format) {
                        if (current->rtp_code != to_match->rtp_code) {
@@ -754,13 +804,10 @@ static void payload_mapping_tx_remove_other_mappings(struct ast_rtp_codecs *code
                        continue;
                }
 
-               /* Remove other mapping */
-               AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, idx, NULL);
-               ao2_ref(current, -1);
-               if (instance && instance->engine && instance->engine->payload_set) {
-                       instance->engine->payload_set(instance, idx, 0, NULL, 0);
-               }
+               return 1;
        }
+
+       return 0;
 }
 
 /*!
@@ -800,13 +847,14 @@ static void rtp_codecs_payloads_copy_tx(struct ast_rtp_codecs *src, struct ast_r
                if (instance && instance->engine && instance->engine->payload_set) {
                        instance->engine->payload_set(instance, idx, type->asterisk_format, type->format, type->rtp_code);
                }
-
-               payload_mapping_tx_remove_other_mappings(dest, instance, type);
        }
 }
 
 void ast_rtp_codecs_payloads_copy(struct ast_rtp_codecs *src, struct ast_rtp_codecs *dest, struct ast_rtp_instance *instance)
 {
+       int idx;
+       struct ast_rtp_payload_type *type;
+
        ast_rwlock_wrlock(&dest->codecs_lock);
 
        /* Deadlock avoidance because of held write lock. */
@@ -816,6 +864,17 @@ void ast_rtp_codecs_payloads_copy(struct ast_rtp_codecs *src, struct ast_rtp_cod
                ast_rwlock_wrlock(&dest->codecs_lock);
        }
 
+       /*
+        * This represents a completely new mapping of what the remote party is
+        * expecting for payloads, so we clear out the entire tx payload mapping
+        * vector and replace it.
+        */
+       for (idx = 0; idx < AST_VECTOR_SIZE(&dest->payload_mapping_tx); ++idx) {
+               type = AST_VECTOR_GET(&dest->payload_mapping_tx, idx);
+               ao2_t_cleanup(type, "destroying ast_rtp_codec tx mapping");
+               AST_VECTOR_REPLACE(&dest->payload_mapping_tx, idx, NULL);
+       }
+
        rtp_codecs_payloads_copy_rx(src, dest, instance);
        rtp_codecs_payloads_copy_tx(src, dest, instance);
        dest->framing = src->framing;
@@ -851,14 +910,7 @@ void ast_rtp_codecs_payloads_xover(struct ast_rtp_codecs *src, struct ast_rtp_co
 
                ast_debug(2, "Crossover copying tx to rx payload mapping %d (%p) from %p to %p\n",
                        idx, type, src, dest);
-               ao2_ref(type, +1);
-               if (idx < AST_VECTOR_SIZE(&dest->payload_mapping_rx)) {
-                       ao2_t_cleanup(AST_VECTOR_GET(&dest->payload_mapping_rx, idx),
-                               "cleaning up rx mapping vector element about to be replaced");
-               }
-               AST_VECTOR_REPLACE(&dest->payload_mapping_rx, idx, type);
-
-               payload_mapping_rx_clear_primary(dest, type);
+               rtp_codecs_payload_replace_rx(dest, idx, type);
 
                if (instance && instance->engine && instance->engine->payload_set) {
                        instance->engine->payload_set(instance, idx, type->asterisk_format, type->format, type->rtp_code);
@@ -895,18 +947,20 @@ void ast_rtp_codecs_payloads_set_m_type(struct ast_rtp_codecs *codecs, struct as
 
        ast_rwlock_wrlock(&codecs->codecs_lock);
 
-       if (payload < AST_VECTOR_SIZE(&codecs->payload_mapping_tx)) {
-               ao2_t_cleanup(AST_VECTOR_GET(&codecs->payload_mapping_tx, payload),
-                       "cleaning up replaced tx payload type");
-       }
-       AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, payload, new_type);
+       if (!payload_mapping_tx_is_present(codecs, new_type)) {
+               if (payload < AST_VECTOR_SIZE(&codecs->payload_mapping_tx)) {
+                       ao2_t_cleanup(AST_VECTOR_GET(&codecs->payload_mapping_tx, payload),
+                               "cleaning up replaced tx payload type");
+               }
+               AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, payload, new_type);
 
-       if (instance && instance->engine && instance->engine->payload_set) {
-               instance->engine->payload_set(instance, payload, new_type->asterisk_format, new_type->format, new_type->rtp_code);
+               if (instance && instance->engine && instance->engine->payload_set) {
+                       instance->engine->payload_set(instance, payload, new_type->asterisk_format, new_type->format, new_type->rtp_code);
+               }
+       } else {
+               ao2_ref(new_type, -1);
        }
 
-       payload_mapping_tx_remove_other_mappings(codecs, instance, new_type);
-
        ast_rwlock_unlock(&codecs->codecs_lock);
 }
 
@@ -959,22 +1013,30 @@ int ast_rtp_codecs_payloads_set_rtpmap_type_rate(struct ast_rtp_codecs *codecs,
                if (t->payload_type.asterisk_format
                        && ast_format_cmp(t->payload_type.format, ast_format_g726) == AST_FORMAT_CMP_EQUAL
                        && (options & AST_RTP_OPT_G726_NONSTANDARD)) {
-                       new_type->format = ao2_bump(ast_format_g726_aal2);
+                       new_type->format = ast_format_g726_aal2;
                } else {
-                       new_type->format = ao2_bump(t->payload_type.format);
+                       new_type->format = t->payload_type.format;
                }
 
-               if (pt < AST_VECTOR_SIZE(&codecs->payload_mapping_tx)) {
-                       ao2_t_cleanup(AST_VECTOR_GET(&codecs->payload_mapping_tx, pt),
-                               "cleaning up replaced tx payload type");
+               if (new_type->format) {
+                       /* SDP parsing automatically increases the reference count */
+                       new_type->format = ast_format_parse_sdp_fmtp(new_type->format, "");
                }
-               AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, pt, new_type);
 
-               if (instance && instance->engine && instance->engine->payload_set) {
-                       instance->engine->payload_set(instance, pt, new_type->asterisk_format, new_type->format, new_type->rtp_code);
+               if (!payload_mapping_tx_is_present(codecs, new_type)) {
+                       if (pt < AST_VECTOR_SIZE(&codecs->payload_mapping_tx)) {
+                               ao2_t_cleanup(AST_VECTOR_GET(&codecs->payload_mapping_tx, pt),
+                                       "cleaning up replaced tx payload type");
+                       }
+                       AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, pt, new_type);
+
+                       if (instance && instance->engine && instance->engine->payload_set) {
+                               instance->engine->payload_set(instance, pt, new_type->asterisk_format, new_type->format, new_type->rtp_code);
+                       }
+               } else {
+                       ao2_ref(new_type, -1);
                }
 
-               payload_mapping_tx_remove_other_mappings(codecs, instance, new_type);
                break;
        }
 
@@ -1057,11 +1119,14 @@ int ast_rtp_codecs_payload_replace_format(struct ast_rtp_codecs *codecs, int pay
        type->primary_mapping = 1;
 
        ast_rwlock_wrlock(&codecs->codecs_lock);
-       if (payload < AST_VECTOR_SIZE(&codecs->payload_mapping_tx)) {
-               ao2_cleanup(AST_VECTOR_GET(&codecs->payload_mapping_tx, payload));
+       if (!payload_mapping_tx_is_present(codecs, type)) {
+               if (payload < AST_VECTOR_SIZE(&codecs->payload_mapping_tx)) {
+                       ao2_cleanup(AST_VECTOR_GET(&codecs->payload_mapping_tx, payload));
+               }
+               AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, payload, type);
+       } else {
+               ao2_ref(type, -1);
        }
-       AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, payload, type);
-       payload_mapping_tx_remove_other_mappings(codecs, NULL, type);
        ast_rwlock_unlock(&codecs->codecs_lock);
 
        return 0;
@@ -1149,6 +1214,8 @@ void ast_rtp_codecs_payload_formats(struct ast_rtp_codecs *codecs, struct ast_fo
  * \param format Asterisk format to look for
  * \param code The non-Asterisk format code to look for
  *
+ * \note It is assumed that static_RTP_PT_lock is at least read locked before calling.
+ *
  * \retval Numerical payload type
  * \retval -1 if not found.
  */
@@ -1158,7 +1225,6 @@ static int find_static_payload_type(int asterisk_format, const struct ast_format
        int payload = -1;
 
        if (!asterisk_format) {
-               ast_rwlock_rdlock(&static_RTP_PT_lock);
                for (idx = 0; idx < AST_RTP_MAX_PT; ++idx) {
                        if (static_RTP_PT[idx]
                                && !static_RTP_PT[idx]->asterisk_format
@@ -1167,9 +1233,7 @@ static int find_static_payload_type(int asterisk_format, const struct ast_format
                                break;
                        }
                }
-               ast_rwlock_unlock(&static_RTP_PT_lock);
        } else if (format) {
-               ast_rwlock_rdlock(&static_RTP_PT_lock);
                for (idx = 0; idx < AST_RTP_MAX_PT; ++idx) {
                        if (static_RTP_PT[idx]
                                && static_RTP_PT[idx]->asterisk_format
@@ -1179,18 +1243,149 @@ static int find_static_payload_type(int asterisk_format, const struct ast_format
                                break;
                        }
                }
-               ast_rwlock_unlock(&static_RTP_PT_lock);
        }
 
        return payload;
 }
 
-int ast_rtp_codecs_payload_code(struct ast_rtp_codecs *codecs, int asterisk_format, const struct ast_format *format, int code)
+/*!
+ * \internal
+ * \brief Find the first unused dynamic rx payload type.
+ * \since 14.0.0
+ *
+ * \param codecs Codecs structure to look in
+ *
+ * \note It is assumed that codecs is at least read locked before calling.
+ *
+ * \retval Numerical payload type
+ * \retval -1 if not found.
+ */
+static int rtp_codecs_find_empty_dynamic_rx(struct ast_rtp_codecs *codecs)
+{
+       struct ast_rtp_payload_type *type;
+       int idx;
+       int payload = -1;
+
+       idx = AST_RTP_PT_FIRST_DYNAMIC;
+       for (; idx < AST_VECTOR_SIZE(&codecs->payload_mapping_rx); ++idx) {
+               type = AST_VECTOR_GET(&codecs->payload_mapping_rx, idx);
+               if (!type) {
+                       payload = idx;
+                       break;
+               }
+       }
+       return payload;
+}
+
+/*!
+ * \internal
+ * \brief Find the oldest non-primary dynamic rx payload type.
+ * \since 14.0.0
+ *
+ * \param codecs Codecs structure to look in
+ *
+ * \note It is assumed that codecs is at least read locked before calling.
+ *
+ * \retval Numerical payload type
+ * \retval -1 if not found.
+ */
+static int rtp_codecs_find_non_primary_dynamic_rx(struct ast_rtp_codecs *codecs)
+{
+       struct ast_rtp_payload_type *type;
+       struct timeval oldest;
+       int idx;
+       int payload = -1;
+
+       idx = AST_RTP_PT_FIRST_DYNAMIC;
+       for (; idx < AST_VECTOR_SIZE(&codecs->payload_mapping_rx); ++idx) {
+               type = AST_VECTOR_GET(&codecs->payload_mapping_rx, idx);
+               if (type
+                       && !type->primary_mapping
+                       && (payload == -1
+                               || ast_tvdiff_ms(type->when_retired, oldest) < 0)) {
+                       oldest = type->when_retired;
+                       payload = idx;
+               }
+       }
+       return payload;
+}
+
+/*!
+ * \internal
+ * \brief Assign a payload type for the rx mapping.
+ * \since 14.0.0
+ *
+ * \param codecs Codecs structure to look in
+ * \param asterisk_format Non-zero if the given Asterisk format is present
+ * \param format Asterisk format to look for
+ * \param code The format to look for
+ *
+ * \note It is assumed that static_RTP_PT_lock is at least read locked before calling.
+ *
+ * \retval Numerical payload type
+ * \retval -1 if could not assign.
+ */
+static int rtp_codecs_assign_payload_code_rx(struct ast_rtp_codecs *codecs, int asterisk_format, struct ast_format *format, int code)
+{
+       int payload;
+       struct ast_rtp_payload_type *new_type;
+
+       payload = find_static_payload_type(asterisk_format, format, code);
+       if (payload < 0) {
+               return payload;
+       }
+
+       new_type = ast_rtp_engine_alloc_payload_type();
+       if (!new_type) {
+               return -1;
+       }
+       new_type->format = ao2_bump(format);
+       new_type->asterisk_format = asterisk_format;
+       new_type->rtp_code = code;
+       new_type->payload = payload;
+       new_type->primary_mapping = 1;
+
+       ast_rwlock_wrlock(&codecs->codecs_lock);
+       if (payload < AST_RTP_PT_FIRST_DYNAMIC
+               || AST_VECTOR_SIZE(&codecs->payload_mapping_rx) <= payload
+               || !AST_VECTOR_GET(&codecs->payload_mapping_rx, payload)) {
+               /*
+                * The payload type is a static assignment
+                * or our default dynamic position is available.
+                */
+               rtp_codecs_payload_replace_rx(codecs, payload, new_type);
+       } else if (-1 < (payload = rtp_codecs_find_empty_dynamic_rx(codecs))
+               || -1 < (payload = rtp_codecs_find_non_primary_dynamic_rx(codecs))) {
+               /*
+                * We found the first available empty dynamic position
+                * or we found a mapping that should no longer be
+                * actively used.
+                */
+               new_type->payload = payload;
+               rtp_codecs_payload_replace_rx(codecs, payload, new_type);
+       } else {
+               /*
+                * There are no empty or non-primary dynamic positions
+                * left.  Sadness.
+                *
+                * I don't think this is really possible.
+                */
+               ast_log(LOG_WARNING, "No dynamic RTP payload type values available!\n");
+       }
+       ast_rwlock_unlock(&codecs->codecs_lock);
+
+       ao2_ref(new_type, -1);
+
+       return payload;
+}
+
+int ast_rtp_codecs_payload_code(struct ast_rtp_codecs *codecs, int asterisk_format, struct ast_format *format, int code)
 {
        struct ast_rtp_payload_type *type;
        int idx;
        int payload = -1;
 
+       ast_rwlock_rdlock(&static_RTP_PT_lock);
        if (!asterisk_format) {
                ast_rwlock_rdlock(&codecs->codecs_lock);
                for (idx = 0; idx < AST_VECTOR_SIZE(&codecs->payload_mapping_rx); ++idx) {
@@ -1200,14 +1395,10 @@ int ast_rtp_codecs_payload_code(struct ast_rtp_codecs *codecs, int asterisk_form
                        }
 
                        if (!type->asterisk_format
+                               && type->primary_mapping
                                && type->rtp_code == code) {
-                               if (type->primary_mapping) {
-                                       payload = idx;
-                                       break;
-                               }
-                               if (payload == -1) {
-                                       payload = idx;
-                               }
+                               payload = idx;
+                               break;
                        }
                }
                ast_rwlock_unlock(&codecs->codecs_lock);
@@ -1220,22 +1411,20 @@ int ast_rtp_codecs_payload_code(struct ast_rtp_codecs *codecs, int asterisk_form
                        }
 
                        if (type->asterisk_format
+                               && type->primary_mapping
                                && ast_format_cmp(format, type->format) == AST_FORMAT_CMP_EQUAL) {
-                               if (type->primary_mapping) {
-                                       payload = idx;
-                                       break;
-                               }
-                               if (payload == -1) {
-                                       payload = idx;
-                               }
+                               payload = idx;
+                               break;
                        }
                }
                ast_rwlock_unlock(&codecs->codecs_lock);
        }
 
        if (payload < 0) {
-               payload = find_static_payload_type(asterisk_format, format, code);
+               payload = rtp_codecs_assign_payload_code_rx(codecs, asterisk_format, format,
+                       code);
        }
+       ast_rwlock_unlock(&static_RTP_PT_lock);
 
        return payload;
 }
@@ -1279,7 +1468,9 @@ int ast_rtp_codecs_payload_code_tx(struct ast_rtp_codecs *codecs, int asterisk_f
        }
 
        if (payload < 0) {
+               ast_rwlock_rdlock(&static_RTP_PT_lock);
                payload = find_static_payload_type(asterisk_format, format, code);
+               ast_rwlock_unlock(&static_RTP_PT_lock);
        }
 
        return payload;
@@ -1302,7 +1493,8 @@ int ast_rtp_codecs_find_payload_code(struct ast_rtp_codecs *codecs, int payload)
        return res;
 }
 
-const char *ast_rtp_lookup_mime_subtype2(const int asterisk_format, struct ast_format *format, int code, enum ast_rtp_options options)
+const char *ast_rtp_lookup_mime_subtype2(const int asterisk_format,
+       const struct ast_format *format, int code, enum ast_rtp_options options)
 {
        int i;
        const char *res = "";
@@ -1331,7 +1523,8 @@ const char *ast_rtp_lookup_mime_subtype2(const int asterisk_format, struct ast_f
        return res;
 }
 
-unsigned int ast_rtp_lookup_sample_rate2(int asterisk_format, struct ast_format *format, int code)
+unsigned int ast_rtp_lookup_sample_rate2(int asterisk_format,
+       const struct ast_format *format, int code)
 {
        unsigned int i;
        unsigned int res = 0;
@@ -1708,16 +1901,16 @@ void ast_rtp_instance_set_stats_vars(struct ast_channel *chan, struct ast_rtp_in
 {
        char quality_buf[AST_MAX_USER_FIELD];
        char *quality;
-       struct ast_channel *bridge = ast_channel_bridge_peer(chan);
+       struct ast_channel *bridge;
 
-       ast_channel_lock(chan);
-       ast_channel_stage_snapshot(chan);
-       ast_channel_unlock(chan);
+       bridge = ast_channel_bridge_peer(chan);
        if (bridge) {
-               ast_channel_lock(bridge);
+               ast_channel_lock_both(chan, bridge);
                ast_channel_stage_snapshot(bridge);
-               ast_channel_unlock(bridge);
+       } else {
+               ast_channel_lock(chan);
        }
+       ast_channel_stage_snapshot(chan);
 
        quality = ast_rtp_instance_get_quality(instance, AST_RTP_INSTANCE_STAT_FIELD_QUALITY,
                quality_buf, sizeof(quality_buf));
@@ -1755,11 +1948,9 @@ void ast_rtp_instance_set_stats_vars(struct ast_channel *chan, struct ast_rtp_in
                }
        }
 
-       ast_channel_lock(chan);
        ast_channel_stage_snapshot_done(chan);
        ast_channel_unlock(chan);
        if (bridge) {
-               ast_channel_lock(bridge);
                ast_channel_stage_snapshot_done(bridge);
                ast_channel_unlock(bridge);
                ast_channel_unref(bridge);
@@ -1908,29 +2099,38 @@ int ast_rtp_engine_srtp_is_registered(void)
        return res_srtp && res_srtp_policy;
 }
 
-int ast_rtp_instance_add_srtp_policy(struct ast_rtp_instance *instance, struct ast_srtp_policy *remote_policy, struct ast_srtp_policy *local_policy)
+int ast_rtp_instance_add_srtp_policy(struct ast_rtp_instance *instance, struct ast_srtp_policy *remote_policy, struct ast_srtp_policy *local_policy, int rtcp)
 {
        int res = 0;
+       struct ast_srtp **srtp;
 
        if (!res_srtp) {
                return -1;
        }
 
-       if (!instance->srtp) {
-               res = res_srtp->create(&instance->srtp, instance, remote_policy);
+
+       srtp = rtcp ? &instance->rtcp_srtp : &instance->srtp;
+
+       if (!*srtp) {
+               res = res_srtp->create(srtp, instance, remote_policy);
        } else {
-               res = res_srtp->replace(&instance->srtp, instance, remote_policy);
+               res = res_srtp->replace(srtp, instance, remote_policy);
        }
        if (!res) {
-               res = res_srtp->add_stream(instance->srtp, local_policy);
+               res = res_srtp->add_stream(*srtp, local_policy);
        }
 
        return res;
 }
 
-struct ast_srtp *ast_rtp_instance_get_srtp(struct ast_rtp_instance *instance)
+struct ast_srtp *ast_rtp_instance_get_srtp(struct ast_rtp_instance *instance, int rtcp)
 {
-       return instance->srtp;
+       if (rtcp && instance->rtcp_srtp) {
+               return instance->rtcp_srtp;
+       }
+       else {
+               return instance->srtp;
+       }
 }
 
 int ast_rtp_instance_sendcng(struct ast_rtp_instance *instance, int level)
@@ -1974,18 +2174,34 @@ int ast_rtp_dtls_cfg_parse(struct ast_rtp_dtls_cfg *dtls_cfg, const char *name,
                }
        } else if (!strcasecmp(name, "dtlscertfile")) {
                ast_free(dtls_cfg->certfile);
+               if (!ast_strlen_zero(value) && !ast_file_is_readable(value)) {
+                       ast_log(LOG_ERROR, "%s file %s does not exist or is not readable\n", name, value);
+                       return -1;
+               }
                dtls_cfg->certfile = ast_strdup(value);
        } else if (!strcasecmp(name, "dtlsprivatekey")) {
                ast_free(dtls_cfg->pvtfile);
+               if (!ast_strlen_zero(value) && !ast_file_is_readable(value)) {
+                       ast_log(LOG_ERROR, "%s file %s does not exist or is not readable\n", name, value);
+                       return -1;
+               }
                dtls_cfg->pvtfile = ast_strdup(value);
        } else if (!strcasecmp(name, "dtlscipher")) {
                ast_free(dtls_cfg->cipher);
                dtls_cfg->cipher = ast_strdup(value);
        } else if (!strcasecmp(name, "dtlscafile")) {
                ast_free(dtls_cfg->cafile);
+               if (!ast_strlen_zero(value) && !ast_file_is_readable(value)) {
+                       ast_log(LOG_ERROR, "%s file %s does not exist or is not readable\n", name, value);
+                       return -1;
+               }
                dtls_cfg->cafile = ast_strdup(value);
        } else if (!strcasecmp(name, "dtlscapath") || !strcasecmp(name, "dtlscadir")) {
                ast_free(dtls_cfg->capath);
+               if (!ast_strlen_zero(value) && !ast_file_is_readable(value)) {
+                       ast_log(LOG_ERROR, "%s file %s does not exist or is not readable\n", name, value);
+                       return -1;
+               }
                dtls_cfg->capath = ast_strdup(value);
        } else if (!strcasecmp(name, "dtlssetup")) {
                if (!strcasecmp(value, "active")) {
@@ -2082,7 +2298,11 @@ static void add_static_payload(int map, struct ast_format *format, int rtp_code)
        int x;
        struct ast_rtp_payload_type *type;
 
-       ast_assert(map < ARRAY_LEN(static_RTP_PT));
+       /*
+        * ARRAY_LEN's result is cast to an int so 'map' is not autocast to a size_t,
+        * which if negative would cause an assertion.
+        */
+       ast_assert(map < (int)ARRAY_LEN(static_RTP_PT));
 
        ast_rwlock_wrlock(&static_RTP_PT_lock);
        if (map < 0) {
@@ -2093,6 +2313,49 @@ static void add_static_payload(int map, struct ast_format *format, int rtp_code)
                                break;
                        }
                }
+
+               /* http://www.iana.org/assignments/rtp-parameters
+                * RFC 3551, Section 3: "[...] applications which need to define more
+                * than 32 dynamic payload types MAY bind codes below 96, in which case
+                * it is RECOMMENDED that unassigned payload type numbers be used
+                * first". Updated by RFC 5761, Section 4: "[...] values in the range
+                * 64-95 MUST NOT be used [to avoid conflicts with RTCP]". Summaries:
+                * https://tools.ietf.org/html/draft-roach-mmusic-unified-plan#section-3.2.1.2
+                * https://tools.ietf.org/html/draft-wu-avtcore-dynamic-pt-usage#section-3
+                */
+               if (map < 0) {
+                       for (x = MAX(ast_option_rtpptdynamic, 35); x <= AST_RTP_PT_LAST_REASSIGN; ++x) {
+                               if (!static_RTP_PT[x]) {
+                                       map = x;
+                                       break;
+                               }
+                       }
+               }
+               /* Yet, reusing mappings below 35 is not supported in Asterisk because
+                * when Compact Headers are activated, no rtpmap is send for those below
+                * 35. If you want to use 35 and below
+                * A) do not use Compact Headers,
+                * B) remove that code in chan_sip/res_pjsip, or
+                * C) add a flag that this RTP Payload Type got reassigned dynamically
+                *    and requires a rtpmap even with Compact Headers enabled.
+                */
+               if (map < 0) {
+                       for (x = MAX(ast_option_rtpptdynamic, 20); x < 35; ++x) {
+                               if (!static_RTP_PT[x]) {
+                                       map = x;
+                                       break;
+                               }
+                       }
+               }
+               if (map < 0) {
+                       for (x = MAX(ast_option_rtpptdynamic, 0); x < 20; ++x) {
+                               if (!static_RTP_PT[x]) {
+                                       map = x;
+                                       break;
+                               }
+                       }
+               }
+
                if (map < 0) {
                        if (format) {
                                ast_log(LOG_WARNING, "No Dynamic RTP mapping available for format %s\n",
@@ -2125,14 +2388,10 @@ static void add_static_payload(int map, struct ast_format *format, int rtp_code)
 
 int ast_rtp_engine_load_format(struct ast_format *format)
 {
-       char *codec_name = ast_strdupa(ast_format_get_name(format));
-
-       codec_name = ast_str_to_upper(codec_name);
-
        set_next_mime_type(format,
                0,
                ast_codec_media_type2str(ast_format_get_type(format)),
-               codec_name,
+               ast_format_get_codec_name(format),
                ast_format_get_sample_rate(format));
        add_static_payload(-1, format, 0);
 
@@ -2234,7 +2493,7 @@ static struct ast_manager_event_blob *rtcp_report_to_ami(struct stasis_message *
        if (type == AST_RTP_RTCP_SR) {
                ast_str_append(&packet_string, 0, "SentNTP: %lu.%06lu\r\n",
                        (unsigned long)payload->report->sender_information.ntp_timestamp.tv_sec,
-                       (unsigned long)payload->report->sender_information.ntp_timestamp.tv_usec * 4096);
+                       (unsigned long)payload->report->sender_information.ntp_timestamp.tv_usec);
                ast_str_append(&packet_string, 0, "SentRTP: %u\r\n",
                                payload->report->sender_information.rtp_timestamp);
                ast_str_append(&packet_string, 0, "SentPackets: %u\r\n",
@@ -2333,12 +2592,12 @@ static struct ast_json *rtcp_report_to_json(struct stasis_message *msg,
                }
        }
 
-       json_rtcp_report = ast_json_pack("{s: i, s: i, s: i, s: O, s: O}",
+       json_rtcp_report = ast_json_pack("{s: i, s: i, s: i, s: o, s: o}",
                        "ssrc", payload->report->ssrc,
                        "type", payload->report->type,
                        "report_count", payload->report->reception_report_count,
-                       "sender_information", json_rtcp_sender_info ? json_rtcp_sender_info : ast_json_null(),
-                       "report_blocks", json_rtcp_report_blocks);
+                       "sender_information", json_rtcp_sender_info ? ast_json_ref(json_rtcp_sender_info) : ast_json_ref(ast_json_null()),
+                       "report_blocks", ast_json_ref(json_rtcp_report_blocks));
        if (!json_rtcp_report) {
                return NULL;
        }
@@ -2350,10 +2609,10 @@ static struct ast_json *rtcp_report_to_json(struct stasis_message *msg,
                }
        }
 
-       return ast_json_pack("{s: O, s: O, s: O}",
-               "channel", payload->snapshot ? json_channel : ast_json_null(),
-               "rtcp_report", json_rtcp_report,
-               "blob", payload->blob);
+       return ast_json_pack("{s: o, s: o, s: o}",
+               "channel", payload->snapshot ? ast_json_ref(json_channel) : ast_json_ref(ast_json_null()),
+               "rtcp_report", ast_json_ref(json_rtcp_report),
+               "blob", ast_json_deep_copy(payload->blob));
 }
 
 static void rtp_rtcp_report_dtor(void *obj)