res/res_rtp_asterisk: smoother can cause wrong timestamps if dtmf happen
[asterisk/asterisk.git] / res / res_rtp_asterisk.c
index f6a0ec0..84b2088 100644 (file)
@@ -29,6 +29,7 @@
  */
 
 /*** MODULEINFO
+       <use type="external">openssl</use>
        <use type="external">pjproject</use>
        <support_level>core</support_level>
  ***/
 #include <signal.h>
 #include <fcntl.h>
 
-#ifdef HAVE_OPENSSL_SRTP
+#ifdef HAVE_OPENSSL
+#include <openssl/opensslconf.h>
+#include <openssl/opensslv.h>
+#if !defined(OPENSSL_NO_SRTP) && (OPENSSL_VERSION_NUMBER >= 0x10001000L)
 #include <openssl/ssl.h>
 #include <openssl/err.h>
 #include <openssl/bio.h>
+#if !defined(OPENSSL_NO_ECDH) && (OPENSSL_VERSION_NUMBER >= 0x10000000L)
+#include <openssl/bn.h>
+#endif
+#ifndef OPENSSL_NO_DH
+#include <openssl/dh.h>
+#endif
+#endif
 #endif
 
 #ifdef HAVE_PJPROJECT
 #include "asterisk/smoother.h"
 #include "asterisk/uuid.h"
 #include "asterisk/test.h"
+#include "asterisk/data_buffer.h"
+#ifdef HAVE_PJPROJECT
+#include "asterisk/res_pjproject.h"
+#endif
 
 #define MAX_TIMESTAMP_SKEW     640
 
 
 #define TURN_STATE_WAIT_TIME 2000
 
+#define DEFAULT_RTP_SEND_BUFFER_SIZE   250
+#define DEFAULT_RTP_RECV_BUFFER_SIZE   20
+
 /*! Full INTRA-frame Request / Fast Update Request (From RFC2032) */
 #define RTCP_PT_FUR     192
 /*! Sender Report (From RFC3550) */
 #define RTCP_PT_APP     204
 /* VP8: RTCP Feedback */
 /*! Payload Specific Feed Back (From RFC4585 also RFC5104) */
-#define RTCP_PT_PSFB    206
+#define RTCP_PT_PSFB    AST_RTP_RTCP_PSFB
 
 #define RTP_MTU                1200
 #define DTMF_SAMPLE_RATE_MS    8 /*!< DTMF samples per millisecond */
 #define ZFONE_PROFILE_ID 0x505a
 
 #define DEFAULT_LEARNING_MIN_SEQUENTIAL 4
+/*!
+ * \brief Calculate the min learning duration in ms.
+ *
+ * \details
+ * The min supported packet size represents 10 ms and we need to account
+ * for some jitter and fast clocks while learning.  Some messed up devices
+ * have very bad jitter for a small packet sample size.  Jitter can also
+ * be introduced by the network itself.
+ *
+ * So we'll allow packets to come in every 9ms on average for fast clocking
+ * with the last one coming in 5ms early for jitter.
+ */
+#define CALC_LEARNING_MIN_DURATION(count) (((count) - 1) * 9 - 5)
+#define DEFAULT_LEARNING_MIN_DURATION CALC_LEARNING_MIN_DURATION(DEFAULT_LEARNING_MIN_SEQUENTIAL)
 
 #define SRTP_MASTER_KEY_LEN 16
 #define SRTP_MASTER_SALT_LEN 14
@@ -125,7 +157,22 @@ enum strict_rtp_state {
        STRICT_RTP_CLOSED,   /*! Drop all RTP packets not coming from source that was learned */
 };
 
-#define DEFAULT_STRICT_RTP STRICT_RTP_CLOSED
+enum strict_rtp_mode {
+       STRICT_RTP_NO = 0,      /*! Don't adhere to any strict RTP rules */
+       STRICT_RTP_YES,         /*! Strict RTP that restricts packets based on time and sequence number */
+       STRICT_RTP_SEQNO,       /*! Strict RTP that restricts packets based on sequence number */
+};
+
+/*!
+ * \brief Strict RTP learning timeout time in milliseconds
+ *
+ * \note Set to 5 seconds to allow reinvite chains for direct media
+ * to settle before media actually starts to arrive.  There may be a
+ * reinvite collision involved on the other leg.
+ */
+#define STRICT_RTP_LEARN_TIMEOUT       5000
+
+#define DEFAULT_STRICT_RTP STRICT_RTP_YES      /*!< Enabled by default */
 #define DEFAULT_ICESUPPORT 1
 
 extern struct ast_srtp_res *res_srtp;
@@ -148,6 +195,7 @@ static int nochecksums;
 #endif
 static int strictrtp = DEFAULT_STRICT_RTP; /*!< Only accept RTP frames from a defined source. If we receive an indication of a changing source, enter learning mode. */
 static int learning_min_sequential = DEFAULT_LEARNING_MIN_SEQUENTIAL; /*!< Number of sequential RTP frames needed from a single source during learning mode to accept new source. */
+static int learning_min_duration = DEFAULT_LEARNING_MIN_DURATION; /*!< Lowest acceptable timeout between the first and the last sequential RTP frame. */
 #ifdef HAVE_PJPROJECT
 static int icesupport = DEFAULT_ICESUPPORT;
 static struct sockaddr_in stunaddr;
@@ -218,6 +266,7 @@ static AST_RWLIST_HEAD_STATIC(host_candidates, ast_ice_host_candidate);
 #define FLAG_NAT_INACTIVE_NOWARN        (1 << 1)
 #define FLAG_NEED_MARKER_BIT            (1 << 3)
 #define FLAG_DTMF_COMPENSATE            (1 << 4)
+#define FLAG_REQ_LOCAL_BRIDGE_BIT       (1 << 5)
 
 #define TRANSPORT_SOCKET_RTP 0
 #define TRANSPORT_SOCKET_RTCP 1
@@ -226,12 +275,16 @@ static AST_RWLIST_HEAD_STATIC(host_candidates, ast_ice_host_candidate);
 
 /*! \brief RTP learning mode tracking information */
 struct rtp_learning_info {
-       int max_seq;     /*!< The highest sequence number received */
-       int packets;     /*!< The number of remaining packets before the source is accepted */
-       struct timeval received; /*!< The time of the last received packet */
+       struct ast_sockaddr proposed_address;   /*!< Proposed remote address for strict RTP */
+       struct timeval start;   /*!< The time learning mode was started */
+       struct timeval received; /*!< The time of the first received packet */
+       int max_seq;    /*!< The highest sequence number received */
+       int packets;    /*!< The number of remaining packets before the source is accepted */
+       /*! Type of media stream carried by the RTP instance */
+       enum ast_media_type stream_type;
 };
 
-#ifdef HAVE_OPENSSL_SRTP
+#if defined(HAVE_OPENSSL) && (OPENSSL_VERSION_NUMBER >= 0x10001000L) && !defined(OPENSSL_NO_SRTP)
 struct dtls_details {
        SSL *ssl;         /*!< SSL session */
        BIO *read_bio;    /*!< Memory buffer for reading */
@@ -253,6 +306,8 @@ struct ice_wrap {
 struct rtp_ssrc_mapping {
        /*! \brief The received SSRC */
        unsigned int ssrc;
+       /*! True if the SSRC is available.  Otherwise, this is a placeholder mapping until the SSRC is set. */
+       unsigned int ssrc_valid;
        /*! \brief The RTP instance this SSRC belongs to*/
        struct ast_rtp_instance *instance;
 };
@@ -266,15 +321,15 @@ struct ast_rtp {
        unsigned int ssrc;              /*!< Synchronization source, RFC 3550, page 10. */
        char cname[AST_UUID_STR_LEN]; /*!< Our local CNAME */
        unsigned int themssrc;          /*!< Their SSRC */
-       unsigned int rxssrc;
+       unsigned int themssrc_valid;    /*!< True if their SSRC is available. */
        unsigned int lastts;
-       unsigned int lastrxts;
        unsigned int lastividtimestamp;
        unsigned int lastovidtimestamp;
        unsigned int lastitexttimestamp;
        unsigned int lastotexttimestamp;
-       unsigned int lasteventseqn;
        int lastrxseqno;                /*!< Last received sequence number, from the network */
+       int expectedrxseqno;            /*!< Next expected sequence number, from the network */
+       AST_VECTOR(, int) missing_seqno; /*!< A vector of sequence numbers we never received */
        int expectedseqno;              /*!< Next expected sequence number, from the core */
        unsigned short seedrxseqno;     /*!< What sequence number did they start with?*/
        unsigned int seedrxts;          /*!< What RTP timestamp did they start with? */
@@ -288,10 +343,6 @@ struct ast_rtp {
        struct ast_format *lasttxformat;
        struct ast_format *lastrxformat;
 
-       int rtptimeout;                 /*!< RTP timeout time (negative or zero means disabled, negative value means temporarily disabled) */
-       int rtpholdtimeout;             /*!< RTP timeout when on hold (negative or zero means disabled, negative value means temporarily disabled). */
-       int rtpkeepalive;               /*!< Send RTP comfort noice packets for keepalive */
-
        /* DTMF Reception Variables */
        char resp;                        /*!< The current digit being processed */
        unsigned int last_seqno;          /*!< The last known sequence number for any DTMF packet */
@@ -310,17 +361,11 @@ struct ast_rtp {
        struct timeval rxcore;
        struct timeval txcore;
        double drxcore;                 /*!< The double representation of the first received packet */
-       struct timeval lastrx;          /*!< timeval when we last received a packet */
        struct timeval dtmfmute;
        struct ast_smoother *smoother;
-       int *ioid;
        unsigned short seqno;           /*!< Sequence number, RFC 3550, page 13. */
-       unsigned short rxseqno;
        struct ast_sched_context *sched;
-       struct io_context *io;
-       void *data;
        struct ast_rtcp *rtcp;
-       struct ast_rtp *bridged;        /*!< Who we are Packet bridged to */
        unsigned int asymmetric_codec;  /*!< Indicate if asymmetric send/receive codecs are allowed */
 
        struct ast_rtp_instance *bundled; /*!< The RTP instance we are bundled to */
@@ -339,6 +384,9 @@ struct ast_rtp {
 
        struct rtp_red *red;
 
+       struct ast_data_buffer *send_buffer;            /*!< Buffer for storing sent packets for retransmission */
+       struct ast_data_buffer *recv_buffer;            /*!< Buffer for storing received packets for retransmission */
+
 #ifdef HAVE_PJPROJECT
        ast_cond_t cond;            /*!< ICE/TURN condition for signaling */
 
@@ -369,7 +417,7 @@ struct ast_rtp {
        unsigned int ice_num_components; /*!< The number of ICE components */
 #endif
 
-#ifdef HAVE_OPENSSL_SRTP
+#if defined(HAVE_OPENSSL) && (OPENSSL_VERSION_NUMBER >= 0x10001000L) && !defined(OPENSSL_NO_SRTP)
        SSL_CTX *ssl_ctx; /*!< SSL context */
        enum ast_rtp_dtls_verify dtls_verify; /*!< What to verify */
        enum ast_srtp_suite suite;   /*!< SRTP crypto suite */
@@ -446,7 +494,7 @@ struct ast_rtcp {
        /* VP8: sequence number for the RTCP FIR FCI */
        int firseq;
 
-#ifdef HAVE_OPENSSL_SRTP
+#if defined(HAVE_OPENSSL) && (OPENSSL_VERSION_NUMBER >= 0x10001000L) && !defined(OPENSSL_NO_SRTP)
        struct dtls_details dtls; /*!< DTLS state information */
 #endif
 
@@ -475,6 +523,12 @@ struct rtp_red {
        long int prev_ts;
 };
 
+/*! \brief Structure for storing RTP packets for retransmission */
+struct ast_rtp_rtcp_nack_payload {
+       size_t size;            /*!< The size of the payload */
+       unsigned char buf[0];   /*!< The payload data */
+};
+
 AST_LIST_HEAD_NOLOCK(frame_list, ast_frame);
 
 /* Forward Declarations */
@@ -505,9 +559,10 @@ static unsigned int ast_rtp_get_ssrc(struct ast_rtp_instance *instance);
 static const char *ast_rtp_get_cname(struct ast_rtp_instance *instance);
 static void ast_rtp_set_remote_ssrc(struct ast_rtp_instance *instance, unsigned int ssrc);
 static void ast_rtp_set_stream_num(struct ast_rtp_instance *instance, int stream_num);
+static int ast_rtp_extension_enable(struct ast_rtp_instance *instance, enum ast_rtp_extension extension);
 static int ast_rtp_bundle(struct ast_rtp_instance *child, struct ast_rtp_instance *parent);
 
-#ifdef HAVE_OPENSSL_SRTP
+#if defined(HAVE_OPENSSL) && (OPENSSL_VERSION_NUMBER >= 0x10001000L) && !defined(OPENSSL_NO_SRTP)
 static int ast_rtp_activate(struct ast_rtp_instance *instance);
 static void dtls_srtp_check_pending(struct ast_rtp_instance *instance, struct ast_rtp *rtp, int rtcp);
 static void dtls_srtp_start_timeout_timer(struct ast_rtp_instance *instance, struct ast_rtp *rtp, int rtcp);
@@ -619,9 +674,12 @@ static void ast_rtp_ice_add_remote_candidate(struct ast_rtp_instance *instance,
                return;
        }
 
-       if (!rtp->ice_proposed_remote_candidates &&
-                       !(rtp->ice_proposed_remote_candidates = ao2_container_alloc(1, NULL, ice_candidate_cmp))) {
-               return;
+       if (!rtp->ice_proposed_remote_candidates) {
+               rtp->ice_proposed_remote_candidates = ao2_container_alloc_list(
+                       AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL, ice_candidate_cmp);
+               if (!rtp->ice_proposed_remote_candidates) {
+                       return;
+               }
        }
 
        /* If this is going to exceed the maximum number of ICE candidates don't even add it */
@@ -1005,6 +1063,15 @@ static void ast_rtp_ice_set_role(struct ast_rtp_instance *instance, enum ast_rtp
        }
 
        rtp->role = role;
+
+       if (!rtp->ice->real_ice->is_nominating && !rtp->ice->real_ice->is_complete) {
+               pj_thread_register_check();
+
+               pj_ice_sess_change_role(rtp->ice->real_ice, role == AST_RTP_ICE_ROLE_CONTROLLED ?
+                       PJ_ICE_SESS_ROLE_CONTROLLED : PJ_ICE_SESS_ROLE_CONTROLLING);
+       } else {
+               ast_debug(3, "Not setting ICE role because state is %s\n", rtp->ice->real_ice->is_nominating ? "nominating" : "complete" );
+       }
 }
 
 /*! \pre instance is locked */
@@ -1027,8 +1094,12 @@ static void ast_rtp_ice_add_cand(struct ast_rtp_instance *instance, struct ast_r
 
        pj_ice_calc_foundation(rtp->ice->real_ice->pool, &foundation, type, addr);
 
-       if (!rtp->ice_local_candidates && !(rtp->ice_local_candidates = ao2_container_alloc(1, NULL, ice_candidate_cmp))) {
-               return;
+       if (!rtp->ice_local_candidates) {
+               rtp->ice_local_candidates = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
+                       NULL, ice_candidate_cmp);
+               if (!rtp->ice_local_candidates) {
+                       return;
+               }
        }
 
        if (!(candidate = ao2_alloc(sizeof(*candidate), ast_rtp_ice_candidate_destroy))) {
@@ -1517,7 +1588,7 @@ static struct ast_rtp_engine_ice ast_rtp_ice = {
 };
 #endif
 
-#ifdef HAVE_OPENSSL_SRTP
+#if defined(HAVE_OPENSSL) && (OPENSSL_VERSION_NUMBER >= 0x10001000L) && !defined(OPENSSL_NO_SRTP)
 static int dtls_verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
 {
        /* We don't want to actually verify the certificate so just accept what they have provided */
@@ -1586,46 +1657,32 @@ static int dtls_setup_rtcp(struct ast_rtp_instance *instance)
        return dtls_details_initialize(&rtp->rtcp->dtls, rtp->ssl_ctx, rtp->dtls.dtls_setup);
 }
 
-/*! \pre instance is locked */
-static int ast_rtp_dtls_set_configuration(struct ast_rtp_instance *instance, const struct ast_rtp_dtls_cfg *dtls_cfg)
+static const SSL_METHOD *get_dtls_method(void)
 {
-       struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
-       int res;
-#ifdef HAVE_OPENSSL_EC
-       EC_KEY *ecdh;
-#endif
-
-       if (!dtls_cfg->enabled) {
-               return 0;
-       }
-
-       if (!ast_rtp_engine_srtp_is_registered()) {
-               ast_log(LOG_ERROR, "SRTP support module is not loaded or available. Try loading res_srtp.so.\n");
-               return -1;
-       }
-
-       if (rtp->ssl_ctx) {
-               return 0;
-       }
-
 #if OPENSSL_VERSION_NUMBER < 0x10002000L || defined(LIBRESSL_VERSION_NUMBER)
-       rtp->ssl_ctx = SSL_CTX_new(DTLSv1_method());
+       return DTLSv1_method();
 #else
-       rtp->ssl_ctx = SSL_CTX_new(DTLS_method());
+       return DTLS_method();
 #endif
-       if (!rtp->ssl_ctx) {
-               return -1;
-       }
+}
 
-       SSL_CTX_set_read_ahead(rtp->ssl_ctx, 1);
+struct dtls_cert_info {
+       EVP_PKEY *private_key;
+       X509 *certificate;
+};
 
-#ifdef HAVE_OPENSSL_EC
+static void configure_dhparams(const struct ast_rtp *rtp, const struct ast_rtp_dtls_cfg *dtls_cfg)
+{
+#if !defined(OPENSSL_NO_ECDH) && (OPENSSL_VERSION_NUMBER >= 0x10000000L) && (OPENSSL_VERSION_NUMBER < 0x10100000L)
+       EC_KEY *ecdh;
+#endif
 
+#ifndef OPENSSL_NO_DH
        if (!ast_strlen_zero(dtls_cfg->pvtfile)) {
                BIO *bio = BIO_new_file(dtls_cfg->pvtfile, "r");
-               if (bio != NULL) {
+               if (bio) {
                        DH *dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
-                       if (dh != NULL) {
+                       if (dh) {
                                if (SSL_CTX_set_tmp_dh(rtp->ssl_ctx, dh)) {
                                        long options = SSL_OP_CIPHER_SERVER_PREFERENCE |
                                                SSL_OP_SINGLE_DH_USE | SSL_OP_SINGLE_ECDH_USE;
@@ -1637,9 +1694,12 @@ static int ast_rtp_dtls_set_configuration(struct ast_rtp_instance *instance, con
                        BIO_free(bio);
                }
        }
+#endif /* !OPENSSL_NO_DH */
+
+#if !defined(OPENSSL_NO_ECDH) && (OPENSSL_VERSION_NUMBER >= 0x10000000L) && (OPENSSL_VERSION_NUMBER < 0x10100000L)
        /* enables AES-128 ciphers, to get AES-256 use NID_secp384r1 */
        ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
-       if (ecdh != NULL) {
+       if (ecdh) {
                if (SSL_CTX_set_tmp_ecdh(rtp->ssl_ctx, ecdh)) {
                        #ifndef SSL_CTRL_SET_ECDH_AUTO
                                #define SSL_CTRL_SET_ECDH_AUTO 94
@@ -1653,8 +1713,257 @@ static int ast_rtp_dtls_set_configuration(struct ast_rtp_instance *instance, con
                }
                EC_KEY_free(ecdh);
        }
+#endif /* !OPENSSL_NO_ECDH */
+}
+
+#if !defined(OPENSSL_NO_ECDH) && (OPENSSL_VERSION_NUMBER >= 0x10000000L)
+
+static int create_ephemeral_ec_keypair(EVP_PKEY **keypair)
+{
+       EC_KEY *eckey = NULL;
+       EC_GROUP *group = NULL;
+
+       group = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
+       if (!group) {
+               goto error;
+       }
+
+       EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE);
+       EC_GROUP_set_point_conversion_form(group, POINT_CONVERSION_UNCOMPRESSED);
+
+       eckey = EC_KEY_new();
+       if (!eckey) {
+               goto error;
+       }
+
+       if (!EC_KEY_set_group(eckey, group)) {
+               goto error;
+       }
+
+       if (!EC_KEY_generate_key(eckey)) {
+               goto error;
+       }
+
+       *keypair = EVP_PKEY_new();
+       if (!*keypair) {
+               goto error;
+       }
+
+       EVP_PKEY_assign_EC_KEY(*keypair, eckey);
+       EC_GROUP_free(group);
+
+       return 0;
+
+error:
+       EC_KEY_free(eckey);
+       EC_GROUP_free(group);
+
+       return -1;
+}
+
+/* From OpenSSL's x509 command */
+#define SERIAL_RAND_BITS 159
+
+static int create_ephemeral_certificate(EVP_PKEY *keypair, X509 **certificate)
+{
+       X509 *cert = NULL;
+       BIGNUM *serial = NULL;
+       X509_NAME *name = NULL;
+
+       cert = X509_new();
+       if (!cert) {
+               goto error;
+       }
+
+       if (!X509_set_version(cert, 2)) {
+               goto error;
+       }
+
+       /* Set the public key */
+       X509_set_pubkey(cert, keypair);
+
+       /* Generate a random serial number */
+       if (!(serial = BN_new())
+          || !BN_rand(serial, SERIAL_RAND_BITS, -1, 0)
+          || !BN_to_ASN1_INTEGER(serial, X509_get_serialNumber(cert))) {
+               goto error;
+       }
+
+       /*
+        * Validity period - Current Chrome & Firefox make it 31 days starting
+        * with yesterday at the current time, so we will do the same.
+        */
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+       if (!X509_time_adj_ex(X509_get_notBefore(cert), -1, 0, NULL)
+          || !X509_time_adj_ex(X509_get_notAfter(cert), 30, 0, NULL)) {
+               goto error;
+       }
+#else
+       if (!X509_time_adj_ex(X509_getm_notBefore(cert), -1, 0, NULL)
+          || !X509_time_adj_ex(X509_getm_notAfter(cert), 30, 0, NULL)) {
+               goto error;
+       }
+#endif
+
+       /* Set the name and issuer */
+       if (!(name = X509_get_subject_name(cert))
+          || !X509_NAME_add_entry_by_NID(name, NID_commonName, MBSTRING_ASC,
+                                                                         (unsigned char *) "asterisk", -1, -1, 0)
+          || !X509_set_issuer_name(cert, name)) {
+               goto error;
+       }
+
+       /* Sign it */
+       if (!X509_sign(cert, keypair, EVP_sha256())) {
+               goto error;
+       }
+
+       *certificate = cert;
+
+       return 0;
+
+error:
+       BN_free(serial);
+       X509_free(cert);
+
+       return -1;
+}
+
+static int create_certificate_ephemeral(struct ast_rtp_instance *instance,
+                                                                               const struct ast_rtp_dtls_cfg *dtls_cfg,
+                                                                               struct dtls_cert_info *cert_info)
+{
+       /* Make sure these are initialized */
+       cert_info->private_key = NULL;
+       cert_info->certificate = NULL;
+
+       if (create_ephemeral_ec_keypair(&cert_info->private_key)) {
+               ast_log(LOG_ERROR, "Failed to create ephemeral ECDSA keypair\n");
+               goto error;
+       }
+
+       if (create_ephemeral_certificate(cert_info->private_key, &cert_info->certificate)) {
+               ast_log(LOG_ERROR, "Failed to create ephemeral X509 certificate\n");
+               goto error;
+       }
+
+       return 0;
+
+  error:
+       X509_free(cert_info->certificate);
+       EVP_PKEY_free(cert_info->private_key);
+
+       return -1;
+}
+
+#else
+
+static int create_certificate_ephemeral(struct ast_rtp_instance *instance,
+                                                                               const struct ast_rtp_dtls_cfg *dtls_cfg,
+                                                                               struct dtls_cert_info *cert_info)
+{
+       ast_log(LOG_ERROR, "Your version of OpenSSL does not support ECDSA keys\n");
+       return -1;
+}
+
+#endif /* !OPENSSL_NO_ECDH */
+
+static int create_certificate_from_file(struct ast_rtp_instance *instance,
+                                                                               const struct ast_rtp_dtls_cfg *dtls_cfg,
+                                                                               struct dtls_cert_info *cert_info)
+{
+       FILE *fp;
+       BIO *certbio = NULL;
+       EVP_PKEY *private_key = NULL;
+       X509 *cert = NULL;
+       char *private_key_file = ast_strlen_zero(dtls_cfg->pvtfile) ? dtls_cfg->certfile : dtls_cfg->pvtfile;
+
+       fp = fopen(private_key_file, "r");
+       if (!fp) {
+               ast_log(LOG_ERROR, "Failed to read private key from file '%s': %s\n", private_key_file, strerror(errno));
+               goto error;
+       }
+
+       if (!PEM_read_PrivateKey(fp, &private_key, NULL, NULL)) {
+               ast_log(LOG_ERROR, "Failed to read private key from PEM file '%s'\n", private_key_file);
+               fclose(fp);
+               goto error;
+       }
+
+       if (fclose(fp)) {
+               ast_log(LOG_ERROR, "Failed to close private key file '%s': %s\n", private_key_file, strerror(errno));
+               goto error;
+       }
+
+       certbio = BIO_new(BIO_s_file());
+       if (!certbio) {
+               ast_log(LOG_ERROR, "Failed to allocate memory for certificate fingerprinting on RTP instance '%p'\n",
+                               instance);
+               goto error;
+       }
+
+       if (!BIO_read_filename(certbio, dtls_cfg->certfile)
+          || !(cert = PEM_read_bio_X509(certbio, NULL, 0, NULL))) {
+               ast_log(LOG_ERROR, "Failed to read certificate from file '%s'\n", dtls_cfg->certfile);
+               goto error;
+       }
+
+       cert_info->private_key = private_key;
+       cert_info->certificate = cert;
+
+       BIO_free_all(certbio);
+
+       return 0;
+
+error:
+       X509_free(cert);
+       BIO_free_all(certbio);
+       EVP_PKEY_free(private_key);
+
+       return -1;
+}
+
+static int load_dtls_certificate(struct ast_rtp_instance *instance,
+                                                                const struct ast_rtp_dtls_cfg *dtls_cfg,
+                                                                struct dtls_cert_info *cert_info)
+{
+       if (dtls_cfg->ephemeral_cert) {
+               return create_certificate_ephemeral(instance, dtls_cfg, cert_info);
+       } else if (!ast_strlen_zero(dtls_cfg->certfile)) {
+               return create_certificate_from_file(instance, dtls_cfg, cert_info);
+       } else {
+               return -1;
+       }
+}
+
+/*! \pre instance is locked */
+static int ast_rtp_dtls_set_configuration(struct ast_rtp_instance *instance, const struct ast_rtp_dtls_cfg *dtls_cfg)
+{
+       struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
+       struct dtls_cert_info cert_info = { 0 };
+       int res;
+
+       if (!dtls_cfg->enabled) {
+               return 0;
+       }
+
+       if (!ast_rtp_engine_srtp_is_registered()) {
+               ast_log(LOG_ERROR, "SRTP support module is not loaded or available. Try loading res_srtp.so.\n");
+               return -1;
+       }
+
+       if (rtp->ssl_ctx) {
+               return 0;
+       }
+
+       rtp->ssl_ctx = SSL_CTX_new(get_dtls_method());
+       if (!rtp->ssl_ctx) {
+               return -1;
+       }
+
+       SSL_CTX_set_read_ahead(rtp->ssl_ctx, 1);
 
-#endif /* #ifdef HAVE_OPENSSL_EC */
+       configure_dhparams(rtp, dtls_cfg);
 
        rtp->dtls_verify = dtls_cfg->verify;
 
@@ -1673,25 +1982,22 @@ static int ast_rtp_dtls_set_configuration(struct ast_rtp_instance *instance, con
 
        rtp->local_hash = dtls_cfg->hash;
 
-       if (!ast_strlen_zero(dtls_cfg->certfile)) {
-               char *private = ast_strlen_zero(dtls_cfg->pvtfile) ? dtls_cfg->certfile : dtls_cfg->pvtfile;
-               BIO *certbio;
-               X509 *cert = NULL;
+       if (!load_dtls_certificate(instance, dtls_cfg, &cert_info)) {
                const EVP_MD *type;
                unsigned int size, i;
                unsigned char fingerprint[EVP_MAX_MD_SIZE];
                char *local_fingerprint = rtp->local_fingerprint;
 
-               if (!SSL_CTX_use_certificate_file(rtp->ssl_ctx, dtls_cfg->certfile, SSL_FILETYPE_PEM)) {
-                       ast_log(LOG_ERROR, "Specified certificate file '%s' for RTP instance '%p' could not be used\n",
-                               dtls_cfg->certfile, instance);
+               if (!SSL_CTX_use_certificate(rtp->ssl_ctx, cert_info.certificate)) {
+                       ast_log(LOG_ERROR, "Specified certificate for RTP instance '%p' could not be used\n",
+                                       instance);
                        return -1;
                }
 
-               if (!SSL_CTX_use_PrivateKey_file(rtp->ssl_ctx, private, SSL_FILETYPE_PEM) ||
-                   !SSL_CTX_check_private_key(rtp->ssl_ctx)) {
-                       ast_log(LOG_ERROR, "Specified private key file '%s' for RTP instance '%p' could not be used\n",
-                               private, instance);
+               if (!SSL_CTX_use_PrivateKey(rtp->ssl_ctx, cert_info.private_key)
+                   || !SSL_CTX_check_private_key(rtp->ssl_ctx)) {
+                       ast_log(LOG_ERROR, "Specified private key for RTP instance '%p' could not be used\n",
+                                       instance);
                        return -1;
                }
 
@@ -1705,22 +2011,9 @@ static int ast_rtp_dtls_set_configuration(struct ast_rtp_instance *instance, con
                        return -1;
                }
 
-               if (!(certbio = BIO_new(BIO_s_file()))) {
-                       ast_log(LOG_ERROR, "Failed to allocate memory for certificate fingerprinting on RTP instance '%p'\n",
-                               instance);
-                       return -1;
-               }
-
-               if (!BIO_read_filename(certbio, dtls_cfg->certfile) ||
-                   !(cert = PEM_read_bio_X509(certbio, NULL, 0, NULL)) ||
-                   !X509_digest(cert, type, fingerprint, &size) ||
-                   !size) {
-                       ast_log(LOG_ERROR, "Could not produce fingerprint from certificate '%s' for RTP instance '%p'\n",
-                               dtls_cfg->certfile, instance);
-                       BIO_free_all(certbio);
-                       if (cert) {
-                               X509_free(cert);
-                       }
+               if (!X509_digest(cert_info.certificate, type, fingerprint, &size) || !size) {
+                       ast_log(LOG_ERROR, "Could not produce fingerprint from certificate for RTP instance '%p'\n",
+                                       instance);
                        return -1;
                }
 
@@ -1729,10 +2022,10 @@ static int ast_rtp_dtls_set_configuration(struct ast_rtp_instance *instance, con
                        local_fingerprint += 3;
                }
 
-               *(local_fingerprint-1) = 0;
+               *(local_fingerprint - 1) = 0;
 
-               BIO_free_all(certbio);
-               X509_free(cert);
+               EVP_PKEY_free(cert_info.private_key);
+               X509_free(cert_info.certificate);
        }
 
        if (!ast_strlen_zero(dtls_cfg->cipher)) {
@@ -1973,7 +2266,7 @@ static struct ast_rtp_engine asterisk_rtp_engine = {
 #ifdef HAVE_PJPROJECT
        .ice = &ast_rtp_ice,
 #endif
-#ifdef HAVE_OPENSSL_SRTP
+#if defined(HAVE_OPENSSL) && (OPENSSL_VERSION_NUMBER >= 0x10001000L) && !defined(OPENSSL_NO_SRTP)
        .dtls = &ast_rtp_dtls,
        .activate = ast_rtp_activate,
 #endif
@@ -1981,10 +2274,11 @@ static struct ast_rtp_engine asterisk_rtp_engine = {
        .cname_get = ast_rtp_get_cname,
        .set_remote_ssrc = ast_rtp_set_remote_ssrc,
        .set_stream_num = ast_rtp_set_stream_num,
+       .extension_enable = ast_rtp_extension_enable,
        .bundle = ast_rtp_bundle,
 };
 
-#ifdef HAVE_OPENSSL_SRTP
+#if defined(HAVE_OPENSSL) && (OPENSSL_VERSION_NUMBER >= 0x10001000L) && !defined(OPENSSL_NO_SRTP)
 /*! \pre instance is locked */
 static void dtls_perform_handshake(struct ast_rtp_instance *instance, struct dtls_details *dtls, int rtcp)
 {
@@ -2018,7 +2312,7 @@ static void dtls_perform_handshake(struct ast_rtp_instance *instance, struct dtl
 }
 #endif
 
-#ifdef HAVE_OPENSSL_SRTP
+#if defined(HAVE_OPENSSL) && (OPENSSL_VERSION_NUMBER >= 0x10001000L) && !defined(OPENSSL_NO_SRTP)
 static void dtls_perform_setup(struct dtls_details *dtls)
 {
        if (!dtls->ssl || !SSL_is_init_finished(dtls->ssl)) {
@@ -2036,7 +2330,7 @@ static void dtls_perform_setup(struct dtls_details *dtls)
 #endif
 
 #ifdef HAVE_PJPROJECT
-static void rtp_learning_seq_init(struct rtp_learning_info *info, uint16_t seq);
+static void rtp_learning_start(struct ast_rtp *rtp);
 
 /* PJPROJECT ICE callback */
 static void ast_rtp_on_ice_complete(pj_ice_sess *ice, pj_status_t status)
@@ -2062,7 +2356,7 @@ static void ast_rtp_on_ice_complete(pj_ice_sess *ice, pj_status_t status)
                }
        }
 
-#ifdef HAVE_OPENSSL_SRTP
+#if defined(HAVE_OPENSSL) && (OPENSSL_VERSION_NUMBER >= 0x10001000L) && !defined(OPENSSL_NO_SRTP)
 
        dtls_perform_setup(&rtp->dtls);
        dtls_perform_handshake(instance, &rtp->dtls, 0);
@@ -2078,8 +2372,8 @@ static void ast_rtp_on_ice_complete(pj_ice_sess *ice, pj_status_t status)
                return;
        }
 
-       rtp->strict_rtp_state = STRICT_RTP_LEARN;
-       rtp_learning_seq_init(&rtp->rtp_source_learn, (uint16_t)rtp->seqno);
+       ast_verb(4, "%p -- Strict RTP learning after ICE completion\n", rtp);
+       rtp_learning_start(rtp);
        ao2_unlock(instance);
 }
 
@@ -2196,7 +2490,7 @@ static inline int rtcp_debug_test_addr(struct ast_sockaddr *addr)
        return 1;
 }
 
-#ifdef HAVE_OPENSSL_SRTP
+#if defined(HAVE_OPENSSL) && (OPENSSL_VERSION_NUMBER >= 0x10001000L) && !defined(OPENSSL_NO_SRTP)
 /*! \pre instance is locked */
 static int dtls_srtp_handle_timeout(struct ast_rtp_instance *instance, int rtcp)
 {
@@ -2336,7 +2630,7 @@ static int dtls_srtp_renegotiate(const void *data)
        return 0;
 }
 
-static int dtls_srtp_add_local_ssrc(struct ast_rtp *rtp, struct ast_srtp *srtp, struct ast_rtp_instance *instance, int rtcp, unsigned int ssrc, int set_remote_policy)
+static int dtls_srtp_add_local_ssrc(struct ast_rtp *rtp, struct ast_rtp_instance *instance, int rtcp, unsigned int ssrc, int set_remote_policy)
 {
        unsigned char material[SRTP_MASTER_LEN * 2];
        unsigned char *local_key, *local_salt, *remote_key, *remote_salt;
@@ -2416,7 +2710,7 @@ error:
        return res;
 }
 
-static int dtls_srtp_setup(struct ast_rtp *rtp, struct ast_srtp *srtp, struct ast_rtp_instance *instance, int rtcp)
+static int dtls_srtp_setup(struct ast_rtp *rtp, struct ast_rtp_instance *instance, int rtcp)
 {
        struct dtls_details *dtls = !rtcp ? &rtp->dtls : &rtp->rtcp->dtls;
        int index;
@@ -2458,14 +2752,14 @@ static int dtls_srtp_setup(struct ast_rtp *rtp, struct ast_srtp *srtp, struct as
                X509_free(certificate);
        }
 
-       if (dtls_srtp_add_local_ssrc(rtp, srtp, instance, rtcp, ast_rtp_instance_get_ssrc(instance), 1)) {
+       if (dtls_srtp_add_local_ssrc(rtp, instance, rtcp, ast_rtp_instance_get_ssrc(instance), 1)) {
                return -1;
        }
 
        for (index = 0; index < AST_VECTOR_SIZE(&rtp->ssrc_mapping); ++index) {
                struct rtp_ssrc_mapping *mapping = AST_VECTOR_GET_ADDR(&rtp->ssrc_mapping, index);
 
-               if (dtls_srtp_add_local_ssrc(rtp, srtp, instance, rtcp, ast_rtp_instance_get_ssrc(mapping->instance), 0)) {
+               if (dtls_srtp_add_local_ssrc(rtp, instance, rtcp, ast_rtp_instance_get_ssrc(mapping->instance), 0)) {
                        return -1;
                }
        }
@@ -2482,6 +2776,18 @@ static int dtls_srtp_setup(struct ast_rtp *rtp, struct ast_srtp *srtp, struct as
 }
 #endif
 
+/*! \brief Helper function to compare an elem in a vector by value */
+static int compare_by_value(int elem, int value)
+{
+       return elem - value;
+}
+
+/*! \brief Helper function to find an elem in a vector by value */
+static int find_by_value(int elem, int value)
+{
+       return elem == value;
+}
+
 static int rtcp_mux(struct ast_rtp *rtp, const unsigned char *packet)
 {
        uint8_t version;
@@ -2520,8 +2826,9 @@ static int __rtp_recvfrom(struct ast_rtp_instance *instance, void *buf, size_t s
 {
        int len;
        struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
-       struct ast_srtp *srtp = ast_rtp_instance_get_srtp(instance, rtcp);
+#if defined(HAVE_OPENSSL) && (OPENSSL_VERSION_NUMBER >= 0x10001000L) && !defined(OPENSSL_NO_SRTP)
        char *in = buf;
+#endif
 #ifdef HAVE_PJPROJECT
        struct ast_sockaddr *loop = rtcp ? &rtp->rtcp_loop : &rtp->rtp_loop;
 #endif
@@ -2530,7 +2837,7 @@ static int __rtp_recvfrom(struct ast_rtp_instance *instance, void *buf, size_t s
           return len;
        }
 
-#ifdef HAVE_OPENSSL_SRTP
+#if defined(HAVE_OPENSSL) && (OPENSSL_VERSION_NUMBER >= 0x10001000L) && !defined(OPENSSL_NO_SRTP)
        /* If this is an SSL packet pass it to OpenSSL for processing. RFC section for first byte value:
         * https://tools.ietf.org/html/rfc5764#section-5.1.2 */
        if ((*in >= 20) && (*in <= 63)) {
@@ -2582,7 +2889,7 @@ static int __rtp_recvfrom(struct ast_rtp_instance *instance, void *buf, size_t s
                        /* Any further connections will be existing since this is now established */
                        dtls->connection = AST_RTP_DTLS_CONNECTION_EXISTING;
                        /* Use the keying material to set up key/salt information */
-                       if ((res = dtls_srtp_setup(rtp, srtp, instance, rtcp))) {
+                       if ((res = dtls_srtp_setup(rtp, instance, rtcp))) {
                                return res;
                        }
                        /* Notify that dtls has been established */
@@ -2652,11 +2959,6 @@ static int __rtp_recvfrom(struct ast_rtp_instance *instance, void *buf, size_t s
        }
 #endif
 
-       if ((*in & 0xC0) && res_srtp && srtp && res_srtp->unprotect(
-                   srtp, buf, &len, rtcp || rtcp_mux(rtp, buf)) < 0) {
-          return -1;
-       }
-
        return len;
 }
 
@@ -2798,22 +3100,18 @@ static double stddev_compute(double stddev, double sample, double normdev, doubl
 
 static int create_new_socket(const char *type, int af)
 {
-       int sock = socket(af, SOCK_DGRAM, 0);
+       int sock = ast_socket_nonblock(af, SOCK_DGRAM, 0);
 
        if (sock < 0) {
-               if (!type) {
-                       type = "RTP/RTCP";
-               }
                ast_log(LOG_WARNING, "Unable to allocate %s socket: %s\n", type, strerror(errno));
-       } else {
-               long flags = fcntl(sock, F_GETFL);
-               fcntl(sock, F_SETFL, flags | O_NONBLOCK);
+               return sock;
+       }
+
 #ifdef SO_NO_CHECK
-               if (nochecksums) {
-                       setsockopt(sock, SOL_SOCKET, SO_NO_CHECK, &nochecksums, sizeof(nochecksums));
-               }
-#endif
+       if (nochecksums) {
+               setsockopt(sock, SOL_SOCKET, SO_NO_CHECK, &nochecksums, sizeof(nochecksums));
        }
+#endif
 
        return sock;
 }
@@ -2828,7 +3126,7 @@ static int create_new_socket(const char *type, int af)
  */
 static void rtp_learning_seq_init(struct rtp_learning_info *info, uint16_t seq)
 {
-       info->max_seq = seq - 1;
+       info->max_seq = seq;
        info->packets = learning_min_sequential;
        memset(&info->received, 0, sizeof(info->received));
 }
@@ -2845,24 +3143,61 @@ static void rtp_learning_seq_init(struct rtp_learning_info *info, uint16_t seq)
  */
 static int rtp_learning_rtp_seq_update(struct rtp_learning_info *info, uint16_t seq)
 {
-       if (!ast_tvzero(info->received) && ast_tvdiff_ms(ast_tvnow(), info->received) < 5) {
-               /* During the probation period the minimum amount of media we'll accept is
-                * 10ms so give a reasonable 5ms buffer just in case we get it sporadically.
-                */
-               return 1;
-       }
-
-       if (seq == info->max_seq + 1) {
+       if (seq == (uint16_t) (info->max_seq + 1)) {
                /* packet is in sequence */
                info->packets--;
        } else {
                /* Sequence discontinuity; reset */
                info->packets = learning_min_sequential - 1;
+               info->received = ast_tvnow();
+       }
+
+       /* Only check time if strictrtp is set to yes. Otherwise, we only needed to check seqno */
+       if (strictrtp == STRICT_RTP_YES) {
+               switch (info->stream_type) {
+               case AST_MEDIA_TYPE_UNKNOWN:
+               case AST_MEDIA_TYPE_AUDIO:
+                       /*
+                        * Protect against packet floods by checking that we
+                        * received the packet sequence in at least the minimum
+                        * allowed time.
+                        */
+                       if (ast_tvzero(info->received)) {
+                               info->received = ast_tvnow();
+                       } else if (!info->packets
+                               && ast_tvdiff_ms(ast_tvnow(), info->received) < learning_min_duration) {
+                               /* Packet flood; reset */
+                               info->packets = learning_min_sequential - 1;
+                               info->received = ast_tvnow();
+                       }
+                       break;
+               case AST_MEDIA_TYPE_VIDEO:
+               case AST_MEDIA_TYPE_IMAGE:
+               case AST_MEDIA_TYPE_TEXT:
+               case AST_MEDIA_TYPE_END:
+                       break;
+               }
        }
+
        info->max_seq = seq;
-       info->received = ast_tvnow();
 
-       return (info->packets == 0);
+       return info->packets;
+}
+
+/*!
+ * \brief Start the strictrtp learning mode.
+ *
+ * \param rtp RTP session description
+ *
+ * \return Nothing
+ */
+static void rtp_learning_start(struct ast_rtp *rtp)
+{
+       rtp->strict_rtp_state = STRICT_RTP_LEARN;
+       memset(&rtp->rtp_source_learn.proposed_address, 0,
+               sizeof(rtp->rtp_source_learn.proposed_address));
+       rtp->rtp_source_learn.start = ast_tvnow();
+       rtp_learning_seq_init(&rtp->rtp_source_learn, (uint16_t) rtp->lastrxseqno);
 }
 
 #ifdef HAVE_PJPROJECT
@@ -2954,8 +3289,8 @@ static void rtp_add_candidates_to_ice(struct ast_rtp_instance *instance, struct
        }
 
        /* If configured to use a STUN server to get our external mapped address do so */
-       if (stunaddr.sin_addr.s_addr && count && ast_sockaddr_is_ipv4(addr)
-               && !stun_address_is_blacklisted(addr)) {
+       if (count && stunaddr.sin_addr.s_addr && !stun_address_is_blacklisted(addr) &&
+               (ast_sockaddr_is_ipv4(addr) || ast_sockaddr_is_any(addr))) {
                struct sockaddr_in answer;
                int rsp;
 
@@ -2969,28 +3304,41 @@ static void rtp_add_candidates_to_ice(struct ast_rtp_instance *instance, struct
                ao2_lock(instance);
                if (!rsp) {
                        pj_sockaddr base;
-                       pj_sockaddr ext;
-                       pj_str_t mapped = pj_str(ast_strdupa(ast_inet_ntoa(answer.sin_addr)));
-                       int srflx = 1;
-
-                       /* Use the first local host candidate as the base */
-                       pj_sockaddr_cp(&base, &address[basepos]);
 
-                       pj_sockaddr_init(pj_AF_INET(), &ext, &mapped, ntohs(answer.sin_port));
-
-                       /* If the returned address is the same as one of our host candidates, don't send the srflx */
-                       for (pos = 0; pos < count; pos++) {
-                               if ((pj_sockaddr_cmp(&address[pos], &ext) == 0) && !rtp_address_is_ice_blacklisted(&address[pos])) {
-                                       srflx = 0;
+                       /* Use the first local IPv4 host candidate as the base */
+                       for (pos = basepos; pos < count; pos++) {
+                               if (address[pos].addr.sa_family == PJ_AF_INET &&
+                                       !rtp_address_is_ice_blacklisted(&address[pos])) {
+                                       pj_sockaddr_cp(&base, &address[pos]);
                                        break;
                                }
                        }
 
-                       if (srflx) {
-                               ast_rtp_ice_add_cand(instance, rtp, component, transport,
-                                       PJ_ICE_CAND_TYPE_SRFLX, 65535, &ext, &base, &base,
-                                       pj_sockaddr_get_len(&ext));
-                       }
+                       if (pos < count) {
+                               pj_sockaddr ext;
+                               pj_str_t mapped = pj_str(ast_strdupa(ast_inet_ntoa(answer.sin_addr)));
+                               int srflx = 1;
+
+                               pj_sockaddr_init(pj_AF_INET(), &ext, &mapped, ntohs(answer.sin_port));
+
+                               /*
+                                * If the returned address is the same as one of our host
+                                * candidates, don't send the srflx
+                                */
+                               for (pos = 0; pos < count; pos++) {
+                                       if (pj_sockaddr_cmp(&address[pos], &ext) == 0 &&
+                                               !rtp_address_is_ice_blacklisted(&address[pos])) {
+                                               srflx = 0;
+                                               break;
+                                       }
+                               }
+
+                               if (srflx) {
+                                       ast_rtp_ice_add_cand(instance, rtp, component, transport,
+                                               PJ_ICE_CAND_TYPE_SRFLX, 65535, &ext, &base, &base,
+                                               pj_sockaddr_get_len(&ext));
+                               }
+                       }
                }
        }
 
@@ -3123,10 +3471,7 @@ static int rtp_allocate_transport(struct ast_rtp_instance *instance, struct ast_
 {
        int x, startplace;
 
-       rtp->strict_rtp_state = (strictrtp ? STRICT_RTP_LEARN : STRICT_RTP_OPEN);
-       if (strictrtp) {
-               rtp_learning_seq_init(&rtp->rtp_source_learn, (uint16_t)rtp->seqno);
-       }
+       rtp->strict_rtp_state = (strictrtp ? STRICT_RTP_CLOSED : STRICT_RTP_OPEN);
 
        /* Create a new socket for us to listen on and use */
        if ((rtp->s =
@@ -3148,6 +3493,7 @@ static int rtp_allocate_transport(struct ast_rtp_instance *instance, struct ast_
                if (!ast_bind(rtp->s, &rtp->bind_address)) {
                        ast_debug(1, "Allocated port %d for RTP instance '%p'\n", x, instance);
                        ast_rtp_instance_set_local_address(instance, &rtp->bind_address);
+                       ast_test_suite_event_notify("RTP_PORT_ALLOCATED", "Port: %d", x);
                        break;
                }
 
@@ -3160,6 +3506,7 @@ static int rtp_allocate_transport(struct ast_rtp_instance *instance, struct ast_
                if (x == startplace || (errno != EADDRINUSE && errno != EACCES)) {
                        ast_log(LOG_ERROR, "Oh dear... we couldn't allocate a port for RTP instance '%p'\n", instance);
                        close(rtp->s);
+                       rtp->s = -1;
                        return -1;
                }
        }
@@ -3184,7 +3531,7 @@ static int rtp_allocate_transport(struct ast_rtp_instance *instance, struct ast_
        }
 #endif
 
-#ifdef HAVE_OPENSSL_SRTP
+#if defined(HAVE_OPENSSL) && (OPENSSL_VERSION_NUMBER >= 0x10001000L) && !defined(OPENSSL_NO_SRTP)
        rtp->rekeyid = -1;
        rtp->dtls.timeout_timer = -1;
 #endif
@@ -3194,12 +3541,13 @@ static int rtp_allocate_transport(struct ast_rtp_instance *instance, struct ast_
 
 static void rtp_deallocate_transport(struct ast_rtp_instance *instance, struct ast_rtp *rtp)
 {
+       int saved_rtp_s = rtp->s;
 #ifdef HAVE_PJPROJECT
        struct timeval wait = ast_tvadd(ast_tvnow(), ast_samp2tv(TURN_STATE_WAIT_TIME, 1000));
        struct timespec ts = { .tv_sec = wait.tv_sec, .tv_nsec = wait.tv_usec * 1000, };
 #endif
 
-#ifdef HAVE_OPENSSL_SRTP
+#if defined(HAVE_OPENSSL) && (OPENSSL_VERSION_NUMBER >= 0x10001000L) && !defined(OPENSSL_NO_SRTP)
        ast_rtp_dtls_stop(instance);
 #endif
 
@@ -3211,7 +3559,9 @@ static void rtp_deallocate_transport(struct ast_rtp_instance *instance, struct a
 
        /* Destroy RTCP if it was being used */
        if (rtp->rtcp && rtp->rtcp->s > -1) {
-               close(rtp->rtcp->s);
+               if (saved_rtp_s != rtp->rtcp->s) {
+                       close(rtp->rtcp->s);
+               }
                rtp->rtcp->s = -1;
        }
 
@@ -3294,6 +3644,7 @@ static int ast_rtp_new(struct ast_rtp_instance *instance,
        rtp->ssrc = ast_random();
        ast_uuid_generate_str(rtp->cname, sizeof(rtp->cname));
        rtp->seqno = ast_random() & 0x7fff;
+       rtp->expectedrxseqno = -1;
        rtp->expectedseqno = -1;
        rtp->sched = sched;
        ast_sockaddr_copy(&rtp->bind_address, addr);
@@ -3302,7 +3653,10 @@ static int ast_rtp_new(struct ast_rtp_instance *instance,
        ast_rtp_instance_set_data(instance, rtp);
 
        if (rtp_allocate_transport(instance, rtp)) {
-               ast_free(rtp);
+               return -1;
+       }
+
+       if (AST_VECTOR_INIT(&rtp->ssrc_mapping, 1)) {
                return -1;
        }
 
@@ -3310,7 +3664,6 @@ static int ast_rtp_new(struct ast_rtp_instance *instance,
        rtp->lastrxformat = ao2_bump(ast_format_none);
        rtp->lasttxformat = ao2_bump(ast_format_none);
        rtp->stream_num = -1;
-       AST_VECTOR_INIT(&rtp->ssrc_mapping, 1);
 
        return 0;
 }
@@ -3324,7 +3677,7 @@ static int ast_rtp_new(struct ast_rtp_instance *instance,
  * \return 0 if element does not match.
  * \return Non-zero if element matches.
  */
-#define SSRC_MAPPING_ELEM_CMP(elem, value) (elem.instance == value)
+#define SSRC_MAPPING_ELEM_CMP(elem, value) ((elem).instance == (value))
 
 /*! \pre instance is locked */
 static int ast_rtp_destroy(struct ast_rtp_instance *instance)
@@ -3373,10 +3726,21 @@ static int ast_rtp_destroy(struct ast_rtp_instance *instance)
                rtp->red = NULL;
        }
 
+       /* Destroy the send buffer if it was being used */
+       if (rtp->send_buffer) {
+               ast_data_buffer_free(rtp->send_buffer);
+       }
+
+       /* Destroy the recv buffer if it was being used */
+       if (rtp->recv_buffer) {
+               ast_data_buffer_free(rtp->recv_buffer);
+       }
+
        ao2_cleanup(rtp->lasttxformat);
        ao2_cleanup(rtp->lastrxformat);
        ao2_cleanup(rtp->f.subclass.format);
        AST_VECTOR_FREE(&rtp->ssrc_mapping);
+       AST_VECTOR_FREE(&rtp->missing_seqno);
 
        /* Finally destroy ourselves */
        ast_free(rtp);
@@ -3593,6 +3957,12 @@ static int ast_rtp_dtmf_end_with_duration(struct ast_rtp_instance *instance, cha
 
        /* 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;
+
+       /* Reset the smoother as the delivery time stored in it is now out of date */
+       if (rtp->smoother) {
+               ast_smoother_free(rtp->smoother);
+               rtp->smoother = NULL;
+       }
 cleanup:
        rtp->sending_digit = 0;
        rtp->send_digit = 0;
@@ -3629,20 +3999,23 @@ static void ast_rtp_change_source(struct ast_rtp_instance *instance)
        if (rtp->lastts) {
                /* We simply set this bit so that the next packet sent will have the marker bit turned on */
                ast_set_flag(rtp, FLAG_NEED_MARKER_BIT);
+       }
 
-               ast_debug(3, "Changing ssrc from %u to %u due to a source change\n", rtp->ssrc, ssrc);
+       ast_debug(3, "Changing ssrc from %u to %u due to a source change\n", rtp->ssrc, ssrc);
 
-               if (srtp) {
-                       ast_debug(3, "Changing ssrc for SRTP from %u to %u\n", rtp->ssrc, ssrc);
-                       res_srtp->change_source(srtp, rtp->ssrc, ssrc);
-                       if (rtcp_srtp != srtp) {
-                               res_srtp->change_source(rtcp_srtp, rtp->ssrc, ssrc);
-                       }
+       if (srtp) {
+               ast_debug(3, "Changing ssrc for SRTP from %u to %u\n", rtp->ssrc, ssrc);
+               res_srtp->change_source(srtp, rtp->ssrc, ssrc);
+               if (rtcp_srtp != srtp) {
+                       res_srtp->change_source(rtcp_srtp, rtp->ssrc, ssrc);
                }
        }
 
        rtp->ssrc = ssrc;
 
+       /* Since the source is changing, we don't know what sequence number to expect next */
+       rtp->expectedrxseqno = -1;
+
        return;
 }
 
@@ -3738,38 +4111,24 @@ static void calculate_lost_packet_statistics(struct ast_rtp *rtp,
        rtp->rtcp->rxlost_count++;
 }
 
-/*!
- * \brief Send RTCP SR or RR report
- *
- * \pre instance is locked
- */
-static int ast_rtcp_write_report(struct ast_rtp_instance *instance, int sr)
+static int ast_rtcp_generate_report(struct ast_rtp_instance *instance, unsigned char *rtcpheader,
+               struct ast_rtp_rtcp_report *rtcp_report, int *sr)
 {
        struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
-       RAII_VAR(struct ast_json *, message_blob, NULL, ast_json_unref);
-       int res;
        int len = 0;
        struct timeval now;
        unsigned int now_lsw;
        unsigned int now_msw;
-       unsigned char *rtcpheader;
        unsigned int lost_packets;
        int fraction_lost;
        struct timeval dlsr = { 0, };
-       unsigned char bdata[512] = "";
-       int rate = rtp_get_rate(rtp->f.subclass.format);
-       int ice;
-       struct ast_sockaddr remote_address = { { 0, } };
        struct ast_rtp_rtcp_report_block *report_block = NULL;
-       RAII_VAR(struct ast_rtp_rtcp_report *, rtcp_report,
-                       ast_rtp_rtcp_report_alloc(rtp->themssrc ? 1 : 0),
-                       ao2_cleanup);
 
        if (!rtp || !rtp->rtcp) {
                return 0;
        }
 
-       if (ast_sockaddr_isnull(&rtp->rtcp->them)) {  /* This'll stop rtcp for this rtp session */
+       if (ast_sockaddr_isnull(&rtp->rtcp->them)) { /* This'll stop rtcp for this rtp session */
                /* RTCP was stopped. */
                return 0;
        }
@@ -3778,21 +4137,23 @@ static int ast_rtcp_write_report(struct ast_rtp_instance *instance, int sr)
                return 1;
        }
 
+       *sr = rtp->txcount > rtp->rtcp->lastsrtxcount ? 1 : 0;
+
        /* Compute statistics */
        calculate_lost_packet_statistics(rtp, &lost_packets, &fraction_lost);
 
        gettimeofday(&now, NULL);
-       rtcp_report->reception_report_count = rtp->themssrc ? 1 : 0;
+       rtcp_report->reception_report_count = rtp->themssrc_valid ? 1 : 0;
        rtcp_report->ssrc = rtp->ssrc;
-       rtcp_report->type = sr ? RTCP_PT_SR : RTCP_PT_RR;
-       if (sr) {
+       rtcp_report->type = *sr ? RTCP_PT_SR : RTCP_PT_RR;
+       if (*sr) {
                rtcp_report->sender_information.ntp_timestamp = now;
                rtcp_report->sender_information.rtp_timestamp = rtp->lastts;
                rtcp_report->sender_information.packet_count = rtp->txcount;
                rtcp_report->sender_information.octet_count = rtp->txoctetcount;
        }
 
-       if (rtp->themssrc) {
+       if (rtp->themssrc_valid) {
                report_block = ast_calloc(1, sizeof(*report_block));
                if (!report_block) {
                        return 1;
@@ -3803,7 +4164,7 @@ static int ast_rtcp_write_report(struct ast_rtp_instance *instance, int sr)
                report_block->lost_count.fraction = (fraction_lost & 0xff);
                report_block->lost_count.packets = (lost_packets & 0xffffff);
                report_block->highest_seq_no = (rtp->cycles | (rtp->lastrxseqno & 0xffff));
-               report_block->ia_jitter = (unsigned int)(rtp->rxjitter * rate);
+               report_block->ia_jitter = (unsigned int)(rtp->rxjitter * rtp_get_rate(rtp->f.subclass.format));
                report_block->lsr = rtp->rtcp->themrxlsr;
                /* If we haven't received an SR report, DLSR should be 0 */
                if (!ast_tvzero(rtp->rtcp->rxlsr)) {
@@ -3812,11 +4173,10 @@ static int ast_rtcp_write_report(struct ast_rtp_instance *instance, int sr)
                }
        }
        timeval2ntp(rtcp_report->sender_information.ntp_timestamp, &now_msw, &now_lsw);
-       rtcpheader = bdata;
        put_unaligned_uint32(rtcpheader + 4, htonl(rtcp_report->ssrc)); /* Our SSRC */
        len += 8;
-       if (sr) {
-               put_unaligned_uint32(rtcpheader + len, htonl(now_msw)); /* now, MSW. gettimeofday() + SEC_BETWEEN_1900_AND_1970*/
+       if (*sr) {
+               put_unaligned_uint32(rtcpheader + len, htonl(now_msw)); /* now, MSW. gettimeofday() + SEC_BETWEEN_1900_AND_1970 */
                put_unaligned_uint32(rtcpheader + len + 4, htonl(now_lsw)); /* now, LSW */
                put_unaligned_uint32(rtcpheader + len + 8, htonl(rtcp_report->sender_information.rtp_timestamp));
                put_unaligned_uint32(rtcpheader + len + 12, htonl(rtcp_report->sender_information.packet_count));
@@ -3834,30 +4194,32 @@ static int ast_rtcp_write_report(struct ast_rtp_instance *instance, int sr)
        }
 
        put_unaligned_uint32(rtcpheader, htonl((2 << 30) | (rtcp_report->reception_report_count << 24)
-                                       | ((sr ? RTCP_PT_SR : RTCP_PT_RR) << 16) | ((len/4)-1)));
+                               | ((*sr ? RTCP_PT_SR : RTCP_PT_RR) << 16) | ((len/4)-1)));
 
-       put_unaligned_uint32(rtcpheader + len, htonl((2 << 30) | (1 << 24) | (RTCP_PT_SDES << 16) | (2 + (AST_UUID_STR_LEN / 4))));
-       put_unaligned_uint32(rtcpheader + len + 4, htonl(rtcp_report->ssrc));
-       put_unaligned_uint16(rtcpheader + len + 8, htonl(0x01 << 24));
-       put_unaligned_uint16(rtcpheader + len + 9, htonl(AST_UUID_STR_LEN << 24));
-       memcpy(rtcpheader + len + 10, rtp->cname, AST_UUID_STR_LEN);
-       len += 12 + AST_UUID_STR_LEN;
+       return len;
+}
 
-       if (rtp->bundled) {
-               ast_rtp_instance_get_remote_address(instance, &remote_address);
-       } else {
-               ast_sockaddr_copy(&remote_address, &rtp->rtcp->them);
+static int ast_rtcp_calculate_sr_rr_statistics(struct ast_rtp_instance *instance,
+               struct ast_rtp_rtcp_report *rtcp_report, struct ast_sockaddr remote_address, int ice, int sr)
+{
+       struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
+       struct ast_rtp_rtcp_report_block *report_block = NULL;
+       RAII_VAR(struct ast_json *, message_blob, NULL, ast_json_unref);
+
+       if (!rtp || !rtp->rtcp) {
+               return 0;
        }
-       res = rtcp_sendto(instance, (unsigned int *)rtcpheader, len, 0, &remote_address, &ice);
-       if (res < 0) {
-               ast_log(LOG_ERROR, "RTCP %s transmission error to %s, rtcp halted %s\n",
-                       sr ? "SR" : "RR",
-                       ast_sockaddr_stringify(&rtp->rtcp->them),
-                       strerror(errno));
+
+       if (ast_sockaddr_isnull(&rtp->rtcp->them)) {
                return 0;
        }
 
-       /* Update RTCP SR/RR statistics */
+       if (!rtcp_report) {
+               return -1;
+       }
+
+       report_block = rtcp_report->report_block[0];
+
        if (sr) {
                rtp->rtcp->txlsr = rtcp_report->sender_information.ntp_timestamp;
                rtp->rtcp->sr_count++;
@@ -3884,7 +4246,7 @@ static int ast_rtcp_write_report(struct ast_rtp_instance *instance, int sr)
                        ast_verbose("    Fraction lost: %d\n", report_block->lost_count.fraction);
                        ast_verbose("    Cumulative loss: %u\n", report_block->lost_count.packets);
                        ast_verbose("    Highest seq no: %u\n", report_block->highest_seq_no);
-                       ast_verbose("    IA jitter: %.4f\n", (double)report_block->ia_jitter / rate);
+                       ast_verbose("    IA jitter: %.4f\n", (double)report_block->ia_jitter / rtp_get_rate(rtp->f.subclass.format));
                        ast_verbose("    Their last SR: %u\n", report_block->lsr);
                        ast_verbose("    DLSR: %4.4f (sec)\n\n", (double)(report_block->dlsr / 65536.0));
                }
@@ -3894,9 +4256,121 @@ static int ast_rtcp_write_report(struct ast_rtp_instance *instance, int sr)
                        "to", ast_sockaddr_stringify(&remote_address),
                        "from", rtp->rtcp->local_addr_str);
        ast_rtp_publish_rtcp_message(instance, ast_rtp_rtcp_sent_type(),
-                       rtcp_report,
-                       message_blob);
-       return res;
+                       rtcp_report, message_blob);
+
+       return 1;
+}
+
+static int ast_rtcp_generate_sdes(struct ast_rtp_instance *instance, unsigned char *rtcpheader,
+               struct ast_rtp_rtcp_report *rtcp_report)
+{
+       struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
+       int len = 0;
+       uint16_t sdes_packet_len_bytes;
+       uint16_t sdes_packet_len_rounded;
+
+       if (!rtp || !rtp->rtcp) {
+               return 0;
+       }
+
+       if (ast_sockaddr_isnull(&rtp->rtcp->them)) {
+               return 0;
+       }
+
+       if (!rtcp_report) {
+               return -1;
+       }
+
+       sdes_packet_len_bytes =
+               4 + /* RTCP Header */
+               4 + /* SSRC */
+               1 + /* Type (CNAME) */
+               1 + /* Text Length */
+               AST_UUID_STR_LEN /* Text and NULL terminator */
+               ;
+
+       /* Round to 32 bit boundary */
+       sdes_packet_len_rounded = (sdes_packet_len_bytes + 3) & ~0x3;
+
+       put_unaligned_uint32(rtcpheader, htonl((2 << 30) | (1 << 24) | (RTCP_PT_SDES << 16) | ((sdes_packet_len_rounded / 4) - 1)));
+       put_unaligned_uint32(rtcpheader + 4, htonl(rtcp_report->ssrc));
+       rtcpheader[8] = 0x01; /* CNAME */
+       rtcpheader[9] = AST_UUID_STR_LEN - 1; /* Number of bytes of text */
+       memcpy(rtcpheader + 10, rtp->cname, AST_UUID_STR_LEN);
+       len += 10 + AST_UUID_STR_LEN;
+
+       /* Padding - Note that we don't set the padded bit on the packet. From
+        * RFC 3550 Section 6.5:
+        *
+        *   No length octet follows the null item type octet, but additional null
+        *   octets MUST be included if needd to pad until the next 32-bit
+        *   boundary. Note that this padding is separate from that indicated by
+        *   the P bit in the RTCP header.
+        *
+        * These bytes will already be zeroed out during array initialization.
+        */
+       len += (sdes_packet_len_rounded - sdes_packet_len_bytes);
+
+       return len;
+}
+
+static int ast_rtcp_generate_nack(struct ast_rtp_instance *instance, unsigned char *rtcpheader)
+{
+       struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
+       int packet_len;
+       int blp_index;
+       int current_seqno;
+       int seqno;
+       unsigned int fci;
+
+       if (!rtp || !rtp->rtcp) {
+               return 0;
+       }
+
+       if (ast_sockaddr_isnull(&rtp->rtcp->them)) {
+               return 0;
+       }
+
+       current_seqno = rtp->expectedrxseqno;
+       seqno = rtp->lastrxseqno;
+       packet_len = 12; /* The header length is 12 (version line, packet source SSRC, media source SSRC) */
+
+       /* Get the missing sequence numbers for the FCI section of the NACK request */
+       for (blp_index = 0, fci = 0; current_seqno < seqno; current_seqno++, blp_index++) {
+               int *missing_seqno;
+
+               missing_seqno = AST_VECTOR_GET_CMP(&rtp->missing_seqno, current_seqno,
+                               find_by_value);
+
+               if (!missing_seqno) {
+                       continue;
+               }
+
+               /* We hit the max blp size, reset */
+               if (blp_index >= 17) {
+                       put_unaligned_uint32(rtcpheader + packet_len, htonl(fci));
+                       fci = 0;
+                       blp_index = 0;
+                       packet_len += 4;
+               }
+
+               if (blp_index == 0) {
+                       fci |= (current_seqno << 16);
+               } else {
+                       fci |= (1 << (blp_index - 1));
+               }
+       }
+
+       put_unaligned_uint32(rtcpheader + packet_len, htonl(fci));
+       packet_len += 4;
+
+       /* Length MUST be 2+n, where n is the number of NACKs. Same as length in words minus 1 */
+       put_unaligned_uint32(rtcpheader, htonl((2 << 30) | (AST_RTP_RTCP_FMT_NACK << 24)
+                               | (AST_RTP_RTCP_RTPFB << 16) | ((packet_len / 4) - 1)));
+       put_unaligned_uint32(rtcpheader + 4, htonl(rtp->ssrc));
+       put_unaligned_uint32(rtcpheader + 8, htonl(rtp->themssrc));
+
+       return packet_len;
 }
 
 /*!
@@ -3912,6 +4386,15 @@ static int ast_rtcp_write(const void *data)
        struct ast_rtp_instance *instance = (struct ast_rtp_instance *) data;
        struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
        int res;
+       int sr = 0;
+       int packet_len = 0;
+       int ice;
+       struct ast_sockaddr remote_address = { { 0, } };
+       unsigned char *rtcpheader;
+       unsigned char bdata[AST_UUID_STR_LEN + 128] = ""; /* More than enough */
+       RAII_VAR(struct ast_rtp_rtcp_report *, rtcp_report,
+                       ast_rtp_rtcp_report_alloc(rtp->themssrc_valid ? 1 : 0),
+                       ao2_cleanup);
 
        if (!rtp || !rtp->rtcp || rtp->rtcp->schedid == -1) {
                ao2_ref(instance, -1);
@@ -3919,13 +4402,44 @@ static int ast_rtcp_write(const void *data)
        }
 
        ao2_lock(instance);
-       if (rtp->txcount > rtp->rtcp->lastsrtxcount) {
-               /* Send an SR */
-               res = ast_rtcp_write_report(instance, 1);
+       rtcpheader = bdata;
+
+       res = ast_rtcp_generate_report(instance, rtcpheader, rtcp_report, &sr);
+
+       if (res == 0 || res == 1) {
+               ast_debug(1, "Failed to add %s report to RTCP packet!\n", sr ? "SR" : "RR");
+               goto cleanup;
+       }
+
+       packet_len += res;
+
+       res = ast_rtcp_generate_sdes(instance, rtcpheader + packet_len, rtcp_report);
+
+       if (res == 0 || res == 1) {
+               ast_debug(1, "Failed to add SDES to RTCP packet!\n");
+               goto cleanup;
+       }
+
+       packet_len += res;
+
+       if (rtp->bundled) {
+               ast_rtp_instance_get_remote_address(instance, &remote_address);
+       } else {
+               ast_sockaddr_copy(&remote_address, &rtp->rtcp->them);
+       }
+
+       res = rtcp_sendto(instance, (unsigned int *)rtcpheader, packet_len, 0, &remote_address, &ice);
+       if (res < 0) {
+               ast_log(LOG_ERROR, "RTCP %s transmission error to %s, rtcp halted %s\n",
+                               sr ? "SR" : "RR",
+                               ast_sockaddr_stringify(&rtp->rtcp->them),
+                               strerror(errno));
+               res = 0;
        } else {
-               /* Send an RR */
-               res = ast_rtcp_write_report(instance, 0);
+               ast_rtcp_calculate_sr_rr_statistics(instance, rtcp_report, remote_address, ice, sr);
        }
+
+cleanup:
        ao2_unlock(instance);
 
        if (!res) {
@@ -3939,6 +4453,20 @@ static int ast_rtcp_write(const void *data)
        return res;
 }
 
+static void put_unaligned_time24(void *p, uint32_t time_msw, uint32_t time_lsw)
+{
+       unsigned char *cp = p;
+       uint32_t datum;
+
+       /* Convert the time to 6.18 format */
+       datum = (time_msw << 18) & 0x00fc0000;
+       datum |= (time_lsw >> 14) & 0x0003ffff;
+
+       cp[0] = datum >> 16;
+       cp[1] = datum >> 8;
+       cp[2] = datum;
+}
+
 /*! \pre instance is locked */
 static int rtp_raw_write(struct ast_rtp_instance *instance, struct ast_frame *frame, int codec)
 {
@@ -4043,7 +4571,7 @@ static int rtp_raw_write(struct ast_rtp_instance *instance, struct ast_frame *fr
                } else {
                        /* This is the first frame with sequence number we've seen, so start keeping track */
                        rtp->expectedseqno = frame->seqno + 1;
-        }
+               }
        } else {
                rtp->expectedseqno = -1;
        }
@@ -4056,14 +4584,60 @@ static int rtp_raw_write(struct ast_rtp_instance *instance, struct ast_frame *fr
 
        /* If we know the remote address construct a packet and send it out */
        if (!ast_sockaddr_isnull(&remote_address)) {
-               int hdrlen = 12, res, ice;
-               unsigned char *rtpheader = (unsigned char *)(frame->data.ptr - hdrlen);
+               int hdrlen = 12;
+               int res;
+               int ice;
+               int ext = 0;
+               int abs_send_time_id;
+               int packet_len;
+               unsigned char *rtpheader;
+
+               /* If the abs-send-time extension has been negotiated determine how much space we need */
+               abs_send_time_id = ast_rtp_instance_extmap_get_id(instance, AST_RTP_EXTENSION_ABS_SEND_TIME);
+               if (abs_send_time_id != -1) {
+                       /* 4 bytes for the shared information, 1 byte for identifier, 3 bytes for abs-send-time */
+                       hdrlen += 8;
+                       ext = 1;
+               }
+
+               packet_len = frame->datalen + hdrlen;
+               rtpheader = (unsigned char *)(frame->data.ptr - hdrlen);
 
-               put_unaligned_uint32(rtpheader, htonl((2 << 30) | (codec << 16) | (seqno) | (mark << 23)));
+               put_unaligned_uint32(rtpheader, htonl((2 << 30) | (ext << 28) | (codec << 16) | (seqno) | (mark << 23)));
                put_unaligned_uint32(rtpheader + 4, htonl(rtp->lastts));
                put_unaligned_uint32(rtpheader + 8, htonl(rtp->ssrc));
 
-               if ((res = rtp_sendto(instance, (void *)rtpheader, frame->datalen + hdrlen, 0, &remote_address, &ice)) < 0) {
+               /* We assume right now that we will only ever have the abs-send-time extension in the packet
+                * which simplifies things a bit.
+                */
+               if (abs_send_time_id != -1) {
+                       unsigned int now_msw;
+                       unsigned int now_lsw;
+
+                       /* This happens before being placed into the retransmission buffer so that when we
+                        * retransmit we only have to update the timestamp, not everything else.
+                        */
+                       put_unaligned_uint32(rtpheader + 12, htonl((0xBEDE << 16) | 1));
+                       rtpheader[16] = (abs_send_time_id << 4) | 2;
+
+                       timeval2ntp(ast_tvnow(), &now_msw, &now_lsw);
+                       put_unaligned_time24(rtpheader + 17, now_msw, now_lsw);
+               }
+
+               /* If retransmissions are enabled, we need to store this packet for future use */
+               if (rtp->send_buffer) {
+                       struct ast_rtp_rtcp_nack_payload *payload;
+
+                       payload = ast_malloc(sizeof(*payload) + packet_len);
+                       if (payload) {
+                               payload->size = packet_len;
+                               memcpy(payload->buf, rtpheader, packet_len);
+                               ast_data_buffer_put(rtp->send_buffer, rtp->seqno, payload);
+                       }
+               }
+
+               res = rtp_sendto(instance, (void *)rtpheader, packet_len, 0, &remote_address, &ice);
+               if (res < 0) {
                        if (!ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_NAT) || (ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_NAT) && (ast_test_flag(rtp, FLAG_NAT_ACTIVE) == FLAG_NAT_ACTIVE))) {
                                ast_debug(1, "RTP Transmission error of packet %d to %s: %s\n",
                                          rtp->seqno,
@@ -4147,6 +4721,94 @@ static struct ast_frame *red_t140_to_red(struct rtp_red *red)
        return &red->t140red;
 }
 
+static void rtp_write_rtcp_fir(struct ast_rtp_instance *instance, struct ast_rtp *rtp, struct ast_sockaddr *remote_address)
+{
+       unsigned int *rtcpheader;
+       char bdata[1024];
+       int len = 20;
+       int ice;
+       int res;
+
+       if (!rtp || !rtp->rtcp) {
+               return;
+       }
+
+       if (ast_sockaddr_isnull(&rtp->rtcp->them) || rtp->rtcp->schedid < 0) {
+               /*
+                * RTCP was stopped.
+                */
+               return;
+       }
+
+       if (!rtp->themssrc_valid) {
+               /* We don't know their SSRC value so we don't know who to update. */
+               return;
+       }
+
+       /* Prepare RTCP FIR (PT=206, FMT=4) */
+       rtp->rtcp->firseq++;
+       if(rtp->rtcp->firseq == 256) {
+               rtp->rtcp->firseq = 0;
+       }
+
+       rtcpheader = (unsigned int *)bdata;
+       rtcpheader[0] = htonl((2 << 30) | (4 << 24) | (RTCP_PT_PSFB << 16) | ((len/4)-1));
+       rtcpheader[1] = htonl(rtp->ssrc);
+       rtcpheader[2] = htonl(rtp->themssrc);
+       rtcpheader[3] = htonl(rtp->themssrc);   /* FCI: SSRC */
+       rtcpheader[4] = htonl(rtp->rtcp->firseq << 24);                 /* FCI: Sequence number */
+       res = rtcp_sendto(instance, (unsigned int *)rtcpheader, len, 0, rtp->bundled ? remote_address : &rtp->rtcp->them, &ice);
+       if (res < 0) {
+               ast_log(LOG_ERROR, "RTCP FIR transmission error: %s\n", strerror(errno));
+       }
+}
+
+static void rtp_write_rtcp_psfb(struct ast_rtp_instance *instance, struct ast_rtp *rtp, struct ast_frame *frame, struct ast_sockaddr *remote_address)
+{
+       struct ast_rtp_rtcp_feedback *feedback = frame->data.ptr;
+       unsigned int *rtcpheader;
+       char bdata[1024];
+       int len = 24;
+       int ice;
+       int res;
+
+       if (feedback->fmt != AST_RTP_RTCP_FMT_REMB) {
+               ast_debug(1, "Provided an RTCP feedback frame of format %d to write on RTP instance '%p' but only REMB is supported\n",
+                       feedback->fmt, instance);
+               return;
+       }
+
+       if (!rtp || !rtp->rtcp) {
+               return;
+       }
+
+       /* If REMB support is not enabled don't send this RTCP packet */
+       if (!ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_REMB)) {
+               ast_debug(1, "Provided an RTCP feedback REMB report to write on RTP instance '%p' but REMB support not enabled\n",
+                       instance);
+               return;
+       }
+
+       if (ast_sockaddr_isnull(&rtp->rtcp->them) || rtp->rtcp->schedid < 0) {
+               /*
+                * RTCP was stopped.
+                */
+               return;
+       }
+
+       rtcpheader = (unsigned int *)bdata;
+       rtcpheader[0] = htonl((2 << 30) | (AST_RTP_RTCP_FMT_REMB << 24) | (RTCP_PT_PSFB << 16) | ((len/4)-1));
+       rtcpheader[1] = htonl(rtp->ssrc);
+       rtcpheader[2] = htonl(0); /* Per the draft this should always be 0 */
+       rtcpheader[3] = htonl(('R' << 24) | ('E' << 16) | ('M' << 8) | ('B')); /* Unique identifier 'R' 'E' 'M' 'B' */
+       rtcpheader[4] = htonl((1 << 24) | (feedback->remb.br_exp << 18) | (feedback->remb.br_mantissa)); /* Number of SSRCs / BR Exp / BR Mantissa */
+       rtcpheader[5] = htonl(rtp->ssrc); /* The SSRC this feedback message applies to */
+       res = rtcp_sendto(instance, (unsigned int *)rtcpheader, len, 0, rtp->bundled ? remote_address : &rtp->rtcp->them, &ice);
+       if (res < 0) {
+               ast_log(LOG_ERROR, "RTCP PSFB transmission error: %s\n", strerror(errno));
+       }
+}
+
 /*! \pre instance is locked */
 static int ast_rtp_write(struct ast_rtp_instance *instance, struct ast_frame *frame)
 {
@@ -4165,38 +4827,11 @@ static int ast_rtp_write(struct ast_rtp_instance *instance, struct ast_frame *fr
 
        /* VP8: is this a request to send a RTCP FIR? */
        if (frame->frametype == AST_FRAME_CONTROL && frame->subclass.integer == AST_CONTROL_VIDUPDATE) {
-               unsigned int *rtcpheader;
-               char bdata[1024];
-               int len = 20;
-               int ice;
-               int res;
-
-               if (!rtp || !rtp->rtcp) {
-                       return 0;
-               }
-
-               if (ast_sockaddr_isnull(&rtp->rtcp->them) || rtp->rtcp->schedid < 0) {
-                       /*
-                        * RTCP was stopped.
-                        */
-                       return 0;
-               }
-
-               /* Prepare RTCP FIR (PT=206, FMT=4) */
-               rtp->rtcp->firseq++;
-               if(rtp->rtcp->firseq == 256) {
-                       rtp->rtcp->firseq = 0;
-               }
-
-               rtcpheader = (unsigned int *)bdata;
-               rtcpheader[0] = htonl((2 << 30) | (4 << 24) | (RTCP_PT_PSFB << 16) | ((len/4)-1));
-               rtcpheader[1] = htonl(rtp->ssrc);
-               rtcpheader[2] = htonl(rtp->themssrc);
-               rtcpheader[3] = htonl(rtp->themssrc);   /* FCI: SSRC */
-               rtcpheader[4] = htonl(rtp->rtcp->firseq << 24);                 /* FCI: Sequence number */
-               res = rtcp_sendto(instance, (unsigned int *)rtcpheader, len, 0, rtp->bundled ? &remote_address : &rtp->rtcp->them, &ice);
-               if (res < 0) {
-                       ast_log(LOG_ERROR, "RTCP FIR transmission error: %s\n", strerror(errno));
+               rtp_write_rtcp_fir(instance, rtp, &remote_address);
+               return 0;
+       } else if (frame->frametype == AST_FRAME_RTCP) {
+               if (frame->subclass.integer == AST_RTP_RTCP_PSFB) {
+                       rtp_write_rtcp_psfb(instance, rtp, frame, &remote_address);
                }
                return 0;
        }
@@ -4235,11 +4870,9 @@ static int ast_rtp_write(struct ast_rtp_instance *instance, struct ast_frame *fr
        format = frame->subclass.format;
        if (ast_format_cmp(rtp->lasttxformat, format) == AST_FORMAT_CMP_NOT_EQUAL) {
                /* Oh dear, if the format changed we will have to set up a new smoother */
-               if (option_debug > 0) {
-                       ast_debug(1, "Ooh, format changed from %s to %s\n",
-                               ast_format_get_name(rtp->lasttxformat),
-                               ast_format_get_name(frame->subclass.format));
-               }
+               ast_debug(1, "Ooh, format changed from %s to %s\n",
+                       ast_format_get_name(rtp->lasttxformat),
+                       ast_format_get_name(frame->subclass.format));
                ao2_replace(rtp->lasttxformat, format);
                if (rtp->smoother) {
                        ast_smoother_free(rtp->smoother);
@@ -4389,7 +5022,7 @@ static struct ast_frame *create_dtmf_frame(struct ast_rtp_instance *instance, en
        return &rtp->f;
 }
 
-static void process_dtmf_rfc2833(struct ast_rtp_instance *instance, unsigned char *data, int len, unsigned int seqno, unsigned int timestamp, struct ast_sockaddr *addr, int payloadtype, int mark, struct frame_list *frames)
+static void process_dtmf_rfc2833(struct ast_rtp_instance *instance, unsigned char *data, int len, unsigned int seqno, unsigned int timestamp, int payloadtype, int mark, struct frame_list *frames)
 {
        struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
        struct ast_sockaddr remote_address = { {0,} };
@@ -4524,7 +5157,7 @@ static void process_dtmf_rfc2833(struct ast_rtp_instance *instance, unsigned cha
        return;
 }
 
-static struct ast_frame *process_dtmf_cisco(struct ast_rtp_instance *instance, unsigned char *data, int len, unsigned int seqno, unsigned int timestamp, struct ast_sockaddr *addr, int payloadtype, int mark)
+static struct ast_frame *process_dtmf_cisco(struct ast_rtp_instance *instance, unsigned char *data, int len, unsigned int seqno, unsigned int timestamp, int payloadtype, int mark)
 {
        struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
        unsigned int event, flags, power;
@@ -4604,7 +5237,7 @@ static struct ast_frame *process_dtmf_cisco(struct ast_rtp_instance *instance, u
        return f;
 }
 
-static struct ast_frame *process_cn_rfc3389(struct ast_rtp_instance *instance, unsigned char *data, int len, unsigned int seqno, unsigned int timestamp, struct ast_sockaddr *addr, int payloadtype, int mark)
+static struct ast_frame *process_cn_rfc3389(struct ast_rtp_instance *instance, unsigned char *data, int len, unsigned int seqno, unsigned int timestamp, int payloadtype, int mark)
 {
        struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
 
@@ -4760,111 +5393,466 @@ static void update_lost_stats(struct ast_rtp *rtp, unsigned int lost_packets)
 }
 
 /*! \pre instance is locked */
-static struct ast_rtp_instance *rtp_find_instance_by_ssrc(struct ast_rtp_instance *instance,
-       struct ast_rtp *rtp, unsigned int ssrc)
+static struct ast_rtp_instance *__rtp_find_instance_by_ssrc(struct ast_rtp_instance *instance,
+       struct ast_rtp *rtp, unsigned int ssrc, int source)
 {
        int index;
-       struct ast_rtp_instance *found = instance;
 
+       if (!AST_VECTOR_SIZE(&rtp->ssrc_mapping)) {
+               /* This instance is not bundled */
+               return instance;
+       }
+
+       /* Find the bundled child instance */
        for (index = 0; index < AST_VECTOR_SIZE(&rtp->ssrc_mapping); ++index) {
                struct rtp_ssrc_mapping *mapping = AST_VECTOR_GET_ADDR(&rtp->ssrc_mapping, index);
+               unsigned int mapping_ssrc = source ? ast_rtp_get_ssrc(mapping->instance) : mapping->ssrc;
 
-               if (mapping->ssrc == ssrc) {
-                       found = mapping->instance;
-                       break;
+               if (mapping->ssrc_valid && mapping_ssrc == ssrc) {
+                       return mapping->instance;
                }
        }
 
-       return found;
+       /* Does the SSRC match the bundled parent? */
+       if (rtp->themssrc_valid && rtp->themssrc == ssrc) {
+               return instance;
+       }
+       return NULL;
 }
 
-static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, const unsigned char *rtcpdata, size_t size, struct ast_sockaddr *addr)
+/*! \pre instance is locked */
+static struct ast_rtp_instance *rtp_find_instance_by_packet_source_ssrc(struct ast_rtp_instance *instance,
+       struct ast_rtp *rtp, unsigned int ssrc)
 {
-       struct ast_rtp_instance *transport = instance;
-       struct ast_rtp *transport_rtp = ast_rtp_instance_get_data(instance);
-       unsigned int *rtcpheader = (unsigned int *)(rtcpdata);
-       int packetwords, position = 0;
-       int report_counter = 0;
-       struct ast_rtp_rtcp_report_block *report_block;
-       struct ast_frame *f = &ast_null_frame;
-
-       packetwords = size / 4;
+       return __rtp_find_instance_by_ssrc(instance, rtp, ssrc, 0);
+}
 
-       ast_debug(1, "Got RTCP report of %zu bytes\n", size);
+/*! \pre instance is locked */
+static struct ast_rtp_instance *rtp_find_instance_by_media_source_ssrc(struct ast_rtp_instance *instance,
+       struct ast_rtp *rtp, unsigned int ssrc)
+{
+       return __rtp_find_instance_by_ssrc(instance, rtp, ssrc, 1);
+}
 
-       while (position < packetwords) {
-               int i, pt, rc;
-               unsigned int length;
-               struct ast_json *message_blob;
-               RAII_VAR(struct ast_rtp_rtcp_report *, rtcp_report, NULL, ao2_cleanup);
-               struct ast_rtp_instance *child;
-               struct ast_rtp *rtp;
+static const char *rtcp_payload_type2str(unsigned int pt)
+{
+       const char *str;
 
-               i = position;
-               length = ntohl(rtcpheader[i]);
-               pt = (length & 0xff0000) >> 16;
-               rc = (length & 0x1f000000) >> 24;
-               length &= 0xffff;
+       switch (pt) {
+       case RTCP_PT_SR:
+               str = "Sender Report";
+               break;
+       case RTCP_PT_RR:
+               str = "Receiver Report";
+               break;
+       case RTCP_PT_FUR:
+               /* Full INTRA-frame Request / Fast Update Request */
+               str = "H.261 FUR";
+               break;
+       case RTCP_PT_PSFB:
+               /* Payload Specific Feed Back */
+               str = "PSFB";
+               break;
+       case RTCP_PT_SDES:
+               str = "Source Description";
+               break;
+       case RTCP_PT_BYE:
+               str = "BYE";
+               break;
+       default:
+               str = "Unknown";
+               break;
+       }
+       return str;
+}
 
-               rtcp_report = ast_rtp_rtcp_report_alloc(rc);
-               if (!rtcp_report) {
-                       return &ast_null_frame;
+/*! \pre instance is locked */
+static int ast_rtp_rtcp_handle_nack(struct ast_rtp_instance *instance, unsigned int *nackdata, unsigned int position,
+       unsigned int length)
+{
+       struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
+       int res = 0;
+       int blp_index;
+       int packet_index;
+       int ice;
+       struct ast_rtp_rtcp_nack_payload *payload;
+       unsigned int current_word;
+       unsigned int pid;       /* Packet ID which refers to seqno of lost packet */
+       unsigned int blp;       /* Bitmask of following lost packets */
+       struct ast_sockaddr remote_address = { {0,} };
+       int abs_send_time_id;
+       unsigned int now_msw = 0;
+       unsigned int now_lsw = 0;
+
+       if (!rtp->send_buffer) {
+               ast_debug(1, "Tried to handle NACK request, but we don't have a RTP packet storage!\n");
+               return res;
+       }
+
+       abs_send_time_id = ast_rtp_instance_extmap_get_id(instance, AST_RTP_EXTENSION_ABS_SEND_TIME);
+       if (abs_send_time_id != -1) {
+               timeval2ntp(ast_tvnow(), &now_msw, &now_lsw);
+       }
+
+       ast_rtp_instance_get_remote_address(instance, &remote_address);
+
+       /*
+        * We use index 3 because with feedback messages, the FCI (Feedback Control Information)
+        * does not begin until after the version, packet SSRC, and media SSRC words.
+        */
+       for (packet_index = 3; packet_index < length; packet_index++) {
+               current_word = ntohl(nackdata[position + packet_index]);
+               pid = current_word >> 16;
+               /* We know the remote end is missing this packet. Go ahead and send it if we still have it. */
+               payload = (struct ast_rtp_rtcp_nack_payload *)ast_data_buffer_get(rtp->send_buffer, pid);
+               if (payload) {
+                       if (abs_send_time_id != -1) {
+                               /* On retransmission we need to update the timestamp within the packet, as it
+                                * is supposed to contain when the packet was actually sent.
+                                */
+                               put_unaligned_time24(payload->buf + 17, now_msw, now_lsw);
+                       }
+                       res += rtp_sendto(instance, payload->buf, payload->size, 0, &remote_address, &ice);
+               } else {
+                       ast_debug(1, "Received NACK request for RTP packet with seqno %d, but we don't have it\n", pid);
+               }
+               /*
+                * The bitmask. Denoting the least significant bit as 1 and its most significant bit
+                * as 16, then bit i of the bitmask is set to 1 if the receiver has not received RTP
+                * packet (pid+i)(modulo 2^16). Otherwise, it is set to 0. We cannot assume bits set
+                * to 0 after a bit set to 1 have actually been received.
+                */
+               blp = current_word & 0xFF;
+               blp_index = 1;
+               while (blp) {
+                       if (blp & 1) {
+                               /* Packet (pid + i)(modulo 2^16) is missing too. */
+                               unsigned int seqno = (pid + blp_index) % 65536;
+                               payload = (struct ast_rtp_rtcp_nack_payload *)ast_data_buffer_get(rtp->send_buffer, seqno);
+                               if (payload) {
+                                       if (abs_send_time_id != -1) {
+                                               put_unaligned_time24(payload->buf + 17, now_msw, now_lsw);
+                                       }
+                                       res += rtp_sendto(instance, payload->buf, payload->size, 0, &remote_address, &ice);
+                               } else {
+                                       ast_debug(1, "Remote end also requested RTP packet with seqno %d, but we don't have it\n", seqno);
+                               }
+                       }
+                       blp >>= 1;
+                       blp_index++;
+               }
+       }
+
+       return res;
+}
+
+/*
+ * Unshifted RTCP header bit field masks
+ */
+#define RTCP_LENGTH_MASK                       0xFFFF
+#define RTCP_PAYLOAD_TYPE_MASK         0xFF
+#define RTCP_REPORT_COUNT_MASK         0x1F
+#define RTCP_PADDING_MASK                      0x01
+#define RTCP_VERSION_MASK                      0x03
+
+/*
+ * RTCP header bit field shift offsets
+ */
+#define RTCP_LENGTH_SHIFT                      0
+#define RTCP_PAYLOAD_TYPE_SHIFT                16
+#define RTCP_REPORT_COUNT_SHIFT                24
+#define RTCP_PADDING_SHIFT                     29
+#define RTCP_VERSION_SHIFT                     30
+
+#define RTCP_VERSION                           2U
+#define RTCP_VERSION_SHIFTED           (RTCP_VERSION << RTCP_VERSION_SHIFT)
+#define RTCP_VERSION_MASK_SHIFTED      (RTCP_VERSION_MASK << RTCP_VERSION_SHIFT)
+
+/*
+ * RTCP first packet record validity header mask and value.
+ *
+ * RFC3550 intentionally defines the encoding of RTCP_PT_SR and RTCP_PT_RR
+ * such that they differ in the least significant bit.  Either of these two
+ * payload types MUST be the first RTCP packet record in a compound packet.
+ *
+ * RFC3550 checks the padding bit in the algorithm they use to check the
+ * RTCP packet for validity.  However, we aren't masking the padding bit
+ * to check since we don't know if it is a compound RTCP packet or not.
+ */
+#define RTCP_VALID_MASK (RTCP_VERSION_MASK_SHIFTED | (((RTCP_PAYLOAD_TYPE_MASK & ~0x1)) << RTCP_PAYLOAD_TYPE_SHIFT))
+#define RTCP_VALID_VALUE (RTCP_VERSION_SHIFTED | (RTCP_PT_SR << RTCP_PAYLOAD_TYPE_SHIFT))
+
+#define RTCP_SR_BLOCK_WORD_LENGTH 5
+#define RTCP_RR_BLOCK_WORD_LENGTH 6
+#define RTCP_HEADER_SSRC_LENGTH   2
+#define RTCP_FB_REMB_BLOCK_WORD_LENGTH 4
+#define RTCP_FB_NACK_BLOCK_WORD_LENGTH 2
+
+static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, struct ast_srtp *srtp,
+       const unsigned char *rtcpdata, size_t size, struct ast_sockaddr *addr)
+{
+       struct ast_rtp_instance *transport = instance;
+       struct ast_rtp *transport_rtp = ast_rtp_instance_get_data(instance);
+       int len = size;
+       unsigned int *rtcpheader = (unsigned int *)(rtcpdata);
+       unsigned int packetwords;
+       unsigned int position;
+       unsigned int first_word;
+       /*! True if we have seen an acceptable SSRC to learn the remote RTCP address */
+       unsigned int ssrc_seen;
+       struct ast_rtp_rtcp_report_block *report_block;
+       struct ast_frame *f = &ast_null_frame;
+
+       /* If this is encrypted then decrypt the payload */
+       if ((*rtcpheader & 0xC0) && res_srtp && srtp && res_srtp->unprotect(
+                   srtp, rtcpheader, &len, 1) < 0) {
+          return &ast_null_frame;
+       }
+
+       packetwords = len / 4;
+
+       ast_debug(1, "Got RTCP report of %d bytes from %s\n",
+               len, ast_sockaddr_stringify(addr));
+
+       /*
+        * Validate the RTCP packet according to an adapted and slightly
+        * modified RFC3550 validation algorithm.
+        */
+       if (packetwords < RTCP_HEADER_SSRC_LENGTH) {
+               ast_debug(1, "%p -- RTCP from %s: Frame size (%u words) is too short\n",
+                       transport_rtp, ast_sockaddr_stringify(addr), packetwords);
+               return &ast_null_frame;
+       }
+       position = 0;
+       first_word = ntohl(rtcpheader[position]);
+       if ((first_word & RTCP_VALID_MASK) != RTCP_VALID_VALUE) {
+               ast_debug(1, "%p -- RTCP from %s: Failed first packet validity check\n",
+                       transport_rtp, ast_sockaddr_stringify(addr));
+               return &ast_null_frame;
+       }
+       do {
+               position += ((first_word >> RTCP_LENGTH_SHIFT) & RTCP_LENGTH_MASK) + 1;
+               if (packetwords <= position) {
+                       break;
                }
-               rtcp_report->reception_report_count = rc;
-               rtcp_report->ssrc = ntohl(rtcpheader[i + 1]);
+               first_word = ntohl(rtcpheader[position]);
+       } while ((first_word & RTCP_VERSION_MASK_SHIFTED) == RTCP_VERSION_SHIFTED);
+       if (position != packetwords) {
+               ast_debug(1, "%p -- RTCP from %s: Failed packet version or length check\n",
+                       transport_rtp, ast_sockaddr_stringify(addr));
+               return &ast_null_frame;
+       }
+
+       /*
+        * Note: RFC3605 points out that true NAT (vs NAPT) can cause RTCP
+        * to have a different IP address and port than RTP.  Otherwise, when
+        * strictrtp is enabled we could reject RTCP packets not coming from
+        * the learned RTP IP address if it is available.
+        */
+
+       /*
+        * strictrtp safety needs SSRC to match before we use the
+        * sender's address for symmetrical RTP to send our RTCP
+        * reports.
+        *
+        * If strictrtp is not enabled then claim to have already seen
+        * a matching SSRC so we'll accept this packet's address for
+        * symmetrical RTP.
+        */
+       ssrc_seen = transport_rtp->strict_rtp_state == STRICT_RTP_OPEN;
+
+       position = 0;
+       while (position < packetwords) {
+               unsigned int i;
+               unsigned int pt;
+               unsigned int rc;
+               unsigned int ssrc;
+               /*! True if the ssrc value we have is valid and not garbage because it doesn't exist. */
+               unsigned int ssrc_valid;
+               unsigned int length;
+               unsigned int min_length;
+               /*! Always use packet source SSRC to find the rtp instance unless explicitly told not to. */
+               unsigned int use_packet_source = 1;
+
+               struct ast_json *message_blob;
+               RAII_VAR(struct ast_rtp_rtcp_report *, rtcp_report, NULL, ao2_cleanup);
+               struct ast_rtp_instance *child;
+               struct ast_rtp *rtp;
+               struct ast_rtp_rtcp_feedback *feedback;
 
-               if ((i + length) > packetwords) {
-                       if (rtpdebug) {
-                               ast_debug(1, "RTCP Read too short\n");
+               i = position;
+               first_word = ntohl(rtcpheader[i]);
+               pt = (first_word >> RTCP_PAYLOAD_TYPE_SHIFT) & RTCP_PAYLOAD_TYPE_MASK;
+               rc = (first_word >> RTCP_REPORT_COUNT_SHIFT) & RTCP_REPORT_COUNT_MASK;
+               /* RFC3550 says 'length' is the number of words in the packet - 1 */
+               length = ((first_word >> RTCP_LENGTH_SHIFT) & RTCP_LENGTH_MASK) + 1;
+
+               /* Check expected RTCP packet record length */
+               min_length = RTCP_HEADER_SSRC_LENGTH;
+               switch (pt) {
+               case RTCP_PT_SR:
+                       min_length += RTCP_SR_BLOCK_WORD_LENGTH;
+                       /* fall through */
+               case RTCP_PT_RR:
+                       min_length += (rc * RTCP_RR_BLOCK_WORD_LENGTH);
+                       use_packet_source = 0;
+                       break;
+               case RTCP_PT_FUR:
+                       break;
+               case AST_RTP_RTCP_RTPFB:
+                       switch (rc) {
+                       case AST_RTP_RTCP_FMT_NACK:
+                               min_length += RTCP_FB_NACK_BLOCK_WORD_LENGTH;
+                               break;
+                       default:
+                               break;
+                       }
+                       use_packet_source = 0;
+                       break;
+               case RTCP_PT_PSFB:
+                       switch (rc) {
+                       case AST_RTP_RTCP_FMT_REMB:
+                               min_length += RTCP_FB_REMB_BLOCK_WORD_LENGTH;
+                               break;
+                       default:
+                               break;
+                       }
+                       break;
+               case RTCP_PT_SDES:
+               case RTCP_PT_BYE:
+                       /*
+                        * There may not be a SSRC/CSRC present.  The packet is
+                        * useless but still valid if it isn't present.
+                        *
+                        * We don't know what min_length should be so disable the check
+                        */
+                       min_length = length;
+                       break;
+               default:
+                       ast_debug(1, "%p -- RTCP from %s: %u(%s) skipping record\n",
+                               transport_rtp, ast_sockaddr_stringify(addr), pt, rtcp_payload_type2str(pt));
+                       if (rtcp_debug_test_addr(addr)) {
+                               ast_verbose("\n");
+                               ast_verbose("RTCP from %s: %u(%s) skipping record\n",
+                                       ast_sockaddr_stringify(addr), pt, rtcp_payload_type2str(pt));
                        }
+                       position += length;
+                       continue;
+               }
+               if (length < min_length) {
+                       ast_debug(1, "%p -- RTCP from %s: %u(%s) length field less than expected minimum.  Min:%u Got:%u\n",
+                               transport_rtp, ast_sockaddr_stringify(addr), pt, rtcp_payload_type2str(pt),
+                               min_length - 1, length - 1);
                        return &ast_null_frame;
                }
 
+               /* Get the RTCP record SSRC if defined for the record */
+               ssrc_valid = 1;
+               switch (pt) {
+               case RTCP_PT_SR:
+               case RTCP_PT_RR:
+                       rtcp_report = ast_rtp_rtcp_report_alloc(rc);
+                       if (!rtcp_report) {
+                               return &ast_null_frame;
+                       }
+                       rtcp_report->reception_report_count = rc;
+
+                       ssrc = ntohl(rtcpheader[i + 2]);
+                       rtcp_report->ssrc = ssrc;
+                       break;
+               case RTCP_PT_FUR:
+               case RTCP_PT_PSFB:
+                       ssrc = ntohl(rtcpheader[i + 1]);
+                       break;
+               case AST_RTP_RTCP_RTPFB:
+                       ssrc = ntohl(rtcpheader[i + 2]);
+                       break;
+               case RTCP_PT_SDES:
+               case RTCP_PT_BYE:
+               default:
+                       ssrc = 0;
+                       ssrc_valid = 0;
+                       break;
+               }
+
                if (rtcp_debug_test_addr(addr)) {
-                       ast_verbose("\n\nGot RTCP from %s\n",
-                                   ast_sockaddr_stringify(addr));
-                       ast_verbose("PT: %d(%s)\n", pt, (pt == RTCP_PT_SR) ? "Sender Report" :
-                                                       (pt == RTCP_PT_RR) ? "Receiver Report" :
-                                                       (pt == RTCP_PT_FUR) ? "H.261 FUR" : "Unknown");
-                       ast_verbose("Reception reports: %d\n", rc);
-                       ast_verbose("SSRC of sender: %u\n", rtcp_report->ssrc);
+                       ast_verbose("\n");
+                       ast_verbose("RTCP from %s\n", ast_sockaddr_stringify(addr));
+                       ast_verbose("PT: %u(%s)\n", pt, rtcp_payload_type2str(pt));
+                       ast_verbose("Reception reports: %u\n", rc);
+                       ast_verbose("SSRC of sender: %u\n", ssrc);
                }
 
                /* Determine the appropriate instance for this */
-               child = rtp_find_instance_by_ssrc(transport, transport_rtp, rtcp_report->ssrc);
-               if (child != transport) {
-                       /* It is safe to hold the child lock while holding the parent lock, we guarantee that the locking order
-                        * is always parent->child or that the child lock is not held when acquiring the parent lock.
+               if (ssrc_valid) {
+                       /*
+                        * Depending on the payload type, either the packet source or media source
+                        * SSRC is used.
                         */
-                       ao2_lock(child);
-                       instance = child;
-                       rtp = ast_rtp_instance_get_data(instance);
+                       if (use_packet_source) {
+                               child = rtp_find_instance_by_packet_source_ssrc(transport, transport_rtp, ssrc);
+                       } else {
+                               child = rtp_find_instance_by_media_source_ssrc(transport, transport_rtp, ssrc);
+                       }
+                       if (child && child != transport) {
+                               /*
+                                * It is safe to hold the child lock while holding the parent lock.
+                                * We guarantee that the locking order is always parent->child or
+                                * that the child lock is not held when acquiring the parent lock.
+                                */
+                               ao2_lock(child);
+                               instance = child;
+                               rtp = ast_rtp_instance_get_data(instance);
+                       } else {
+                               /* The child is the parent! We don't need to unlock it. */
+                               child = NULL;
+                               rtp = transport_rtp;
+                       }
                } else {
-                       /* The child is the parent! We don't need to unlock it. */
                        child = NULL;
                        rtp = transport_rtp;
                }
 
-               if ((rtp->strict_rtp_state != STRICT_RTP_OPEN) && (rtcp_report->ssrc != rtp->themssrc)) {
-                       /* Skip over this RTCP record as it does not contain the correct SSRC */
-                       position += (length + 1);
-                       ast_debug(1, "%p -- Received RTCP report from %s, dropping due to strict RTP protection. Received SSRC '%u' but expected '%u'\n",
-                               rtp, ast_sockaddr_stringify(addr), rtcp_report->ssrc, rtp->themssrc);
-                       continue;
+               if (ssrc_valid && rtp->themssrc_valid) {
+                       /*
+                        * If the SSRC is 1, we still need to handle RTCP since this could be a
+                        * special case. For example, if we have a unidirectional video stream, the
+                        * SSRC may be set to 1 by the browser (in the case of chromium), and requests
+                        * will still need to be processed so that video can flow as expected. This
+                        * should only be done for PLI and FUR, since there is not a way to get the
+                        * appropriate rtp instance when the SSRC is 1.
+                        */
+                       int exception = (ssrc == 1 && !((pt == RTCP_PT_PSFB && rc == AST_RTP_RTCP_FMT_PLI) || pt == RTCP_PT_FUR));
+                       if ((ssrc != rtp->themssrc && use_packet_source && ssrc != 1)
+                                       || exception) {
+                               /*
+                                * Skip over this RTCP record as it does not contain the
+                                * correct SSRC.  We should not act upon RTCP records
+                                * for a different stream.
+                                */
+                               position += length;
+                               ast_debug(1, "%p -- RTCP from %s: Skipping record, received SSRC '%u' != expected '%u'\n",
+                                       rtp, ast_sockaddr_stringify(addr), ssrc, rtp->themssrc);
+                               if (child) {
+                                       ao2_unlock(child);
+                               }
+                               continue;
+                       }
+                       ssrc_seen = 1;
                }
 
-               if (ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_NAT)) {
+               if (ssrc_seen && ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_NAT)) {
                        /* Send to whoever sent to us */
                        if (ast_sockaddr_cmp(&rtp->rtcp->them, addr)) {
                                ast_sockaddr_copy(&rtp->rtcp->them, addr);
                                if (rtpdebug) {
                                        ast_debug(0, "RTCP NAT: Got RTCP from other end. Now sending to address %s\n",
-                                               ast_sockaddr_stringify(&rtp->rtcp->them));
+                                               ast_sockaddr_stringify(addr));
                                }
                        }
                }
 
-               i += 2; /* Advance past header and ssrc */
+               i += RTCP_HEADER_SSRC_LENGTH; /* Advance past header and ssrc */
                switch (pt) {
                case RTCP_PT_SR:
                        gettimeofday(&rtp->rtcp->rxlsr, NULL);
@@ -4888,7 +5876,7 @@ static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, c
                                                rtcp_report->sender_information.packet_count,
                                                rtcp_report->sender_information.octet_count);
                        }
-                       i += 5;
+                       i += RTCP_SR_BLOCK_WORD_LENGTH;
                        /* Intentional fall through */
                case RTCP_PT_RR:
                        if (rtcp_report->type != RTCP_PT_SR) {
@@ -4904,7 +5892,7 @@ static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, c
                                        }
                                        return &ast_null_frame;
                                }
-                               rtcp_report->report_block[report_counter] = report_block;
+                               rtcp_report->report_block[0] = report_block;
                                report_block->source_ssrc = ntohl(rtcpheader[i]);
                                report_block->lost_count.packets = ntohl(rtcpheader[i + 1]) & 0x00ffffff;
                                report_block->lost_count.fraction = ((ntohl(rtcpheader[i + 1]) & 0xff000000) >> 24);
@@ -4941,16 +5929,15 @@ static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, c
                                        ast_verbose("  DLSR: %4.4f (sec)\n",(double)report_block->dlsr / 65536.0);
                                        ast_verbose("  RTT: %4.4f(sec)\n", rtp->rtcp->rtt);
                                }
-                               report_counter++;
                        }
                        /* If and when we handle more than one report block, this should occur outside
                         * this loop.
                         */
 
                        message_blob = ast_json_pack("{s: s, s: s, s: f}",
-                                       "from", ast_sockaddr_stringify(&transport_rtp->rtcp->them),
-                                       "to", transport_rtp->rtcp->local_addr_str,
-                                       "rtt", rtp->rtcp->rtt);
+                               "from", ast_sockaddr_stringify(addr),
+                               "to", transport_rtp->rtcp->local_addr_str,
+                               "rtt", rtp->rtcp->rtt);
                        ast_rtp_publish_rtcp_message(instance, ast_rtp_rtcp_received_type(),
                                        rtcp_report,
                                        message_blob);
@@ -4959,6 +5946,7 @@ static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, c
                        /* Return an AST_FRAME_RTCP frame with the ast_rtp_rtcp_report
                         * object as a its data */
                        transport_rtp->f.frametype = AST_FRAME_RTCP;
+                       transport_rtp->f.subclass.integer = pt;
                        transport_rtp->f.data.ptr = rtp->rtcp->frame_buf + AST_FRIENDLY_OFFSET;
                        memcpy(transport_rtp->f.data.ptr, rtcp_report, sizeof(struct ast_rtp_rtcp_report));
                        transport_rtp->f.datalen = sizeof(struct ast_rtp_rtcp_report);
@@ -4966,9 +5954,9 @@ static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, c
                                /* There's always a single report block stored, here */
                                struct ast_rtp_rtcp_report *rtcp_report2;
                                report_block = transport_rtp->f.data.ptr + transport_rtp->f.datalen + sizeof(struct ast_rtp_rtcp_report_block *);
-                               memcpy(report_block, rtcp_report->report_block[report_counter-1], sizeof(struct ast_rtp_rtcp_report_block));
+                               memcpy(report_block, rtcp_report->report_block[0], sizeof(struct ast_rtp_rtcp_report_block));
                                rtcp_report2 = (struct ast_rtp_rtcp_report *)transport_rtp->f.data.ptr;
-                               rtcp_report2->report_block[report_counter-1] = report_block;
+                               rtcp_report2->report_block[0] = report_block;
                                transport_rtp->f.datalen += sizeof(struct ast_rtp_rtcp_report_block);
                        }
                        transport_rtp->f.offset = AST_FRIENDLY_OFFSET;
@@ -4979,38 +5967,92 @@ static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, c
                        transport_rtp->f.src = "RTP";
                        f = &transport_rtp->f;
                        break;
+               case AST_RTP_RTCP_RTPFB:
+                       switch (rc) {
+                       case AST_RTP_RTCP_FMT_NACK:
+                               /* If retransmissions are not enabled ignore this message */
+                               if (!rtp->send_buffer) {
+                                       break;
+                               }
+
+                               if (rtcp_debug_test_addr(addr)) {
+                                       ast_verbose("Received generic RTCP NACK message\n");
+                               }
+
+                               ast_rtp_rtcp_handle_nack(instance, rtcpheader, position, length);
+                               break;
+                       default:
+                               break;
+                       }
+                       break;
                case RTCP_PT_FUR:
-               /* Handle RTCP FIR as FUR */
+                       /* Handle RTCP FUR as FIR by setting the format to 4 */
+                       rc = AST_RTP_RTCP_FMT_FIR;
                case RTCP_PT_PSFB:
-                       if (rtcp_debug_test_addr(addr)) {
-                               ast_verbose("Received an RTCP Fast Update Request\n");
+                       switch (rc) {
+                       case AST_RTP_RTCP_FMT_PLI:
+                       case AST_RTP_RTCP_FMT_FIR:
+                               if (rtcp_debug_test_addr(addr)) {
+                                       ast_verbose("Received an RTCP Fast Update Request\n");
+                               }
+                               transport_rtp->f.frametype = AST_FRAME_CONTROL;
+                               transport_rtp->f.subclass.integer = AST_CONTROL_VIDUPDATE;
+                               transport_rtp->f.datalen = 0;
+                               transport_rtp->f.samples = 0;
+                               transport_rtp->f.mallocd = 0;
+                               transport_rtp->f.src = "RTP";
+                               f = &transport_rtp->f;
+                               break;
+                       case AST_RTP_RTCP_FMT_REMB:
+                               /* If REMB support is not enabled ignore this message */
+                               if (!ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_REMB)) {
+                                       break;
+                               }
+
+                               if (rtcp_debug_test_addr(addr)) {
+                                       ast_verbose("Received REMB report\n");
+                               }
+                               transport_rtp->f.frametype = AST_FRAME_RTCP;
+                               transport_rtp->f.subclass.integer = pt;
+                               transport_rtp->f.stream_num = rtp->stream_num;
+                               transport_rtp->f.data.ptr = rtp->rtcp->frame_buf + AST_FRIENDLY_OFFSET;
+                               feedback = transport_rtp->f.data.ptr;
+                               feedback->fmt = rc;
+
+                               /* We don't actually care about the SSRC information in the feedback message */
+                               first_word = ntohl(rtcpheader[i + 2]);
+                               feedback->remb.br_exp = (first_word >> 18) & ((1 << 6) - 1);
+                               feedback->remb.br_mantissa = first_word & ((1 << 18) - 1);
+
+                               transport_rtp->f.datalen = sizeof(struct ast_rtp_rtcp_feedback);
+                               transport_rtp->f.offset = AST_FRIENDLY_OFFSET;
+                               transport_rtp->f.samples = 0;
+                               transport_rtp->f.mallocd = 0;
+                               transport_rtp->f.delivery.tv_sec = 0;
+                               transport_rtp->f.delivery.tv_usec = 0;
+                               transport_rtp->f.src = "RTP";
+                               f = &transport_rtp->f;
+                               break;
+                       default:
+                               break;
                        }
-                       transport_rtp->f.frametype = AST_FRAME_CONTROL;
-                       transport_rtp->f.subclass.integer = AST_CONTROL_VIDUPDATE;
-                       transport_rtp->f.datalen = 0;
-                       transport_rtp->f.samples = 0;
-                       transport_rtp->f.mallocd = 0;
-                       transport_rtp->f.src = "RTP";
-                       f = &transport_rtp->f;
                        break;
                case RTCP_PT_SDES:
                        if (rtcp_debug_test_addr(addr)) {
                                ast_verbose("Received an SDES from %s\n",
-                                           ast_sockaddr_stringify(&transport_rtp->rtcp->them));
+                                       ast_sockaddr_stringify(addr));
                        }
                        break;
                case RTCP_PT_BYE:
                        if (rtcp_debug_test_addr(addr)) {
                                ast_verbose("Received a BYE from %s\n",
-                                           ast_sockaddr_stringify(&transport_rtp->rtcp->them));
+                                       ast_sockaddr_stringify(addr));
                        }
                        break;
                default:
-                       ast_debug(1, "Unknown RTCP packet (pt=%d) received from %s\n",
-                                 pt, ast_sockaddr_stringify(&transport_rtp->rtcp->them));
                        break;
                }
-               position += (length + 1);
+               position += length;
                rtp->rtcp->rtcp_info = 1;
 
                if (child) {
@@ -5019,13 +6061,13 @@ static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, c
        }
 
        return f;
-
 }
 
 /*! \pre instance is locked */
 static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance)
 {
        struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
+       struct ast_srtp *srtp = ast_rtp_instance_get_srtp(instance, 1);
        struct ast_sockaddr addr;
        unsigned char rtcpdata[8192 + AST_FRIENDLY_OFFSET];
        unsigned char *read_area = rtcpdata + AST_FRIENDLY_OFFSET;
@@ -5077,7 +6119,7 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance)
                return &ast_null_frame;
        }
 
-       return ast_rtcp_interpret(instance, read_area, res, &addr);
+       return ast_rtcp_interpret(instance, srtp, read_area, res, &addr);
 }
 
 /*! \pre instance is locked */
@@ -5085,7 +6127,7 @@ static int bridge_p2p_rtp_write(struct ast_rtp_instance *instance,
        struct ast_rtp_instance *instance1, unsigned int *rtpheader, int len, int hdrlen)
 {
        struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
-       struct ast_rtp *bridged = ast_rtp_instance_get_data(instance1);
+       struct ast_rtp *bridged;
        int res = 0, payload = 0, bridged_payload = 0, mark;
        RAII_VAR(struct ast_rtp_payload_type *, payload_type, NULL, ao2_cleanup);
        int reconstruct = ntohl(rtpheader[0]);
@@ -5095,7 +6137,7 @@ static int bridge_p2p_rtp_write(struct ast_rtp_instance *instance,
 
        /* Get fields from packet */
        payload = (reconstruct & 0x7f0000) >> 16;
-       mark = (((reconstruct & 0x800000) >> 23) != 0);
+       mark = (reconstruct & 0x800000) >> 23;
 
        /* Check what the payload value should be */
        payload_type = ast_rtp_codecs_get_payload(ast_rtp_instance_get_codecs(instance), payload);
@@ -5118,12 +6160,6 @@ static int bridge_p2p_rtp_write(struct ast_rtp_instance *instance,
                return -1;
        }
 
-       /* If bridged peer is in dtmf, feed all packets to core until it finishes to avoid infinite dtmf */
-       if (bridged->sending_digit) {
-               ast_debug(1, "Feeding packets to core until DTMF finishes\n");
-               return -1;
-       }
-
        /*
         * Even if we are no longer in dtmf, we could still be receiving
         * re-transmissions of the last dtmf end still.  Feed those to the
@@ -5134,35 +6170,10 @@ static int bridge_p2p_rtp_write(struct ast_rtp_instance *instance,
                return -1;
        }
 
-
-       ao2_replace(rtp->lastrxformat, payload_type->format);
-       ao2_replace(bridged->lasttxformat, payload_type->format);
-
-       /*
-        * If bridged peer has already received rtp, perform the asymmetric codec check
-        * if that feature has been activated
-        */
-       if (!bridged->asymmetric_codec && bridged->lastrxformat != ast_format_none) {
-               if (ast_format_cmp(bridged->lasttxformat, bridged->lastrxformat) == AST_FORMAT_CMP_NOT_EQUAL) {
-                       ast_debug(1, "Asymmetric RTP codecs detected (TX: %s, RX: %s) sending frame to core\n",
-                                       ast_format_get_name(bridged->lasttxformat),
-                                       ast_format_get_name(bridged->lastrxformat));
-                       return -1;
-               }
-       }
-
-       /* If the marker bit has been explicitly set turn it on */
-       if (ast_test_flag(rtp, FLAG_NEED_MARKER_BIT)) {
-               mark = 1;
-               ast_clear_flag(rtp, FLAG_NEED_MARKER_BIT);
+       if (payload_type->asterisk_format) {
+               ao2_replace(rtp->lastrxformat, payload_type->format);
        }
 
-       /* Reconstruct part of the packet */
-       reconstruct &= 0xFF80FFFF;
-       reconstruct |= (bridged_payload << 16);
-       reconstruct |= (mark << 23);
-       rtpheader[0] = htonl(reconstruct);
-
        /*
         * We have now determined that we need to send the RTP packet
         * out the bridged instance to do local bridging so we must unlock
@@ -5178,6 +6189,40 @@ static int bridge_p2p_rtp_write(struct ast_rtp_instance *instance,
        ao2_unlock(instance);
        ao2_lock(instance1);
 
+       /*
+        * Get the peer rtp pointer now to emphasize that using it
+        * must happen while instance1 is locked.
+        */
+       bridged = ast_rtp_instance_get_data(instance1);
+
+
+       /* If bridged peer is in dtmf, feed all packets to core until it finishes to avoid infinite dtmf */
+       if (bridged->sending_digit) {
+               ast_debug(1, "Feeding packet to core until DTMF finishes\n");
+               ao2_unlock(instance1);
+               ao2_lock(instance);
+               return -1;
+       }
+
+       if (payload_type->asterisk_format) {
+               /*
+                * If bridged peer has already received rtp, perform the asymmetric codec check
+                * if that feature has been activated
+                */
+               if (!bridged->asymmetric_codec
+                       && bridged->lastrxformat != ast_format_none
+                       && ast_format_cmp(payload_type->format, bridged->lastrxformat) == AST_FORMAT_CMP_NOT_EQUAL) {
+                       ast_debug(1, "Asymmetric RTP codecs detected (TX: %s, RX: %s) sending frame to core\n",
+                               ast_format_get_name(payload_type->format),
+                               ast_format_get_name(bridged->lastrxformat));
+                       ao2_unlock(instance1);
+                       ao2_lock(instance);
+                       return -1;
+               }
+
+               ao2_replace(bridged->lasttxformat, payload_type->format);
+       }
+
        ast_rtp_instance_get_remote_address(instance1, &remote_address);
 
        if (ast_sockaddr_isnull(&remote_address)) {
@@ -5187,6 +6232,24 @@ static int bridge_p2p_rtp_write(struct ast_rtp_instance *instance,
                return 0;
        }
 
+       /* If the marker bit has been explicitly set turn it on */
+       if (ast_test_flag(bridged, FLAG_NEED_MARKER_BIT)) {
+               mark = 1;
+               ast_clear_flag(bridged, FLAG_NEED_MARKER_BIT);
+       }
+
+       /* Set the marker bit for the first local bridged packet which has the first bridged peer's SSRC. */
+       if (ast_test_flag(bridged, FLAG_REQ_LOCAL_BRIDGE_BIT)) {
+               mark = 1;
+               ast_clear_flag(bridged, FLAG_REQ_LOCAL_BRIDGE_BIT);
+       }
+
+       /* Reconstruct part of the packet */
+       reconstruct &= 0xFF80FFFF;
+       reconstruct |= (bridged_payload << 16);
+       reconstruct |= (mark << 23);
+       rtpheader[0] = htonl(reconstruct);
+
        /* Send the packet back out */
        res = rtp_sendto(instance1, (void *)rtpheader, len, 0, &remote_address, &ice);
        if (res < 0) {
@@ -5196,7 +6259,7 @@ static int bridge_p2p_rtp_write(struct ast_rtp_instance *instance,
                                ast_sockaddr_stringify(&remote_address),
                                strerror(errno));
                } else if (((ast_test_flag(bridged, FLAG_NAT_ACTIVE) == FLAG_NAT_INACTIVE) || rtpdebug) && !ast_test_flag(bridged, FLAG_NAT_INACTIVE_NOWARN)) {
-                       if (option_debug || rtpdebug) {
+                       if (rtpdebug || DEBUG_ATLEAST(1)) {
                                ast_log(LOG_WARNING,
                                        "RTP NAT: Can't write RTP to private "
                                        "address %s, waiting for other end to "
@@ -5229,42 +6292,323 @@ static void rtp_instance_unlock(struct ast_rtp_instance *instance)
        }
 }
 
-/*! \pre instance is locked */
-static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtcp)
+static struct ast_frame *ast_rtp_interpret(struct ast_rtp_instance *instance, struct ast_srtp *srtp,
+       const struct ast_sockaddr *remote_address, unsigned char *read_area, int length, int prev_seqno)
 {
+       unsigned int *rtpheader = (unsigned int*)(read_area);
        struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
        struct ast_rtp_instance *instance1;
-       RAII_VAR(struct ast_rtp_instance *, child, NULL, rtp_instance_unlock);
-       struct ast_sockaddr addr;
-       int res, hdrlen = 12, version, payloadtype, padding, mark, ext, cc, prev_seqno;
-       unsigned char *read_area = rtp->rawdata + AST_FRIENDLY_OFFSET;
-       size_t read_area_size = sizeof(rtp->rawdata) - AST_FRIENDLY_OFFSET;
-       unsigned int *rtpheader = (unsigned int*)(read_area), seqno, ssrc, timestamp;
+       int res = length, hdrlen = 12, seqno, timestamp, payloadtype, padding, mark, ext, cc;
        RAII_VAR(struct ast_rtp_payload_type *, payload, NULL, ao2_cleanup);
-       struct ast_sockaddr remote_address = { {0,} };
        struct frame_list frames;
 
-       /* If this is actually RTCP let's hop on over and handle it */
-       if (rtcp) {
-               if (rtp->rtcp && rtp->rtcp->type == AST_RTP_INSTANCE_RTCP_STANDARD) {
-                       return ast_rtcp_read(instance);
-               }
+       /* If this payload is encrypted then decrypt it using the given SRTP instance */
+       if ((*read_area & 0xC0) && res_srtp && srtp && res_srtp->unprotect(
+                   srtp, read_area, &res, 0) < 0) {
                return &ast_null_frame;
        }
 
-       /* Actually read in the data from the socket */
-       if ((res = rtp_recvfrom(instance, read_area, read_area_size, 0,
-                               &addr)) < 0) {
-               if (res == RTP_DTLS_ESTABLISHED) {
-                       rtp->f.frametype = AST_FRAME_CONTROL;
-                       rtp->f.subclass.integer = AST_CONTROL_SRCCHANGE;
-                       return &rtp->f;
-               }
+       /* If we are currently sending DTMF to the remote party send a continuation packet */
+       if (rtp->sending_digit) {
+               ast_rtp_dtmf_continuation(instance);
+       }
 
-               ast_assert(errno != EBADF);
-               if (errno != EAGAIN) {
-                       ast_log(LOG_WARNING, "RTP Read error: %s.  Hanging up.\n",
-                               (errno) ? strerror(errno) : "Unspecified");
+       /* Pull out the various other fields we will need */
+       seqno = ntohl(rtpheader[0]);
+       payloadtype = (seqno & 0x7f0000) >> 16;
+       padding = seqno & (1 << 29);
+       mark = seqno & (1 << 23);
+       ext = seqno & (1 << 28);
+       cc = (seqno & 0xF000000) >> 24;
+       seqno &= 0xffff;
+       timestamp = ntohl(rtpheader[1]);
+
+       AST_LIST_HEAD_INIT_NOLOCK(&frames);
+
+       /* Remove any padding bytes that may be present */
+       if (padding) {
+               res -= read_area[res - 1];
+       }
+
+       /* Skip over any CSRC fields */
+       if (cc) {
+               hdrlen += cc * 4;
+       }
+
+       /* Look for any RTP extensions, currently we do not support any */
+       if (ext) {
+               hdrlen += (ntohl(rtpheader[hdrlen/4]) & 0xffff) << 2;
+               hdrlen += 4;
+               if (DEBUG_ATLEAST(1)) {
+                       unsigned int profile;
+                       profile = (ntohl(rtpheader[3]) & 0xffff0000) >> 16;
+                       if (profile == 0x505a) {
+                               ast_log(LOG_DEBUG, "Found Zfone extension in RTP stream - zrtp - not supported.\n");
+                       } else if (profile != 0xbede) {
+                               /* SDP negotiated RTP extensions can not currently be output in logging */
+                               ast_log(LOG_DEBUG, "Found unknown RTP Extensions %x\n", profile);
+                       }
+               }
+       }
+
+       /* Make sure after we potentially mucked with the header length that it is once again valid */
+       if (res < hdrlen) {
+               ast_log(LOG_WARNING, "RTP Read too short (%d, expecting %d\n", res, hdrlen);
+               return AST_LIST_FIRST(&frames) ? AST_LIST_FIRST(&frames) : &ast_null_frame;
+       }
+
+       rtp->rxcount++;
+       rtp->rxoctetcount += (res - hdrlen);
+       if (rtp->rxcount == 1) {
+               rtp->seedrxseqno = seqno;
+       }
+
+       /* Do not schedule RR if RTCP isn't run */
+       if (rtp->rtcp && !ast_sockaddr_isnull(&rtp->rtcp->them) && rtp->rtcp->schedid < 0) {
+               /* Schedule transmission of Receiver Report */
+               ao2_ref(instance, +1);
+               rtp->rtcp->schedid = ast_sched_add(rtp->sched, ast_rtcp_calc_interval(rtp), ast_rtcp_write, instance);
+               if (rtp->rtcp->schedid < 0) {
+                       ao2_ref(instance, -1);
+                       ast_log(LOG_WARNING, "scheduling RTCP transmission failed.\n");
+               }
+       }
+       if ((int)rtp->lastrxseqno - (int)seqno  > 100) /* if so it would indicate that the sender cycled; allow for misordering */
+               rtp->cycles += RTP_SEQ_MOD;
+
+       /* If we are directly bridged to another instance send the audio directly out,
+        * but only after updating core information about the received traffic so that
+        * outgoing RTCP reflects it.
+        */
+       instance1 = ast_rtp_instance_get_bridged(instance);
+       if (instance1
+               && !bridge_p2p_rtp_write(instance, instance1, rtpheader, res, hdrlen)) {
+               struct timeval rxtime;
+               struct ast_frame *f;
+
+               /* Update statistics for jitter so they are correct in RTCP */
+               calc_rxstamp(&rxtime, rtp, timestamp, mark);
+
+               /* When doing P2P we don't need to raise any frames about SSRC change to the core */
+               while ((f = AST_LIST_REMOVE_HEAD(&frames, frame_list)) != NULL) {
+                       ast_frfree(f);
+               }
+
+               return &ast_null_frame;
+       }
+
+       payload = ast_rtp_codecs_get_payload(ast_rtp_instance_get_codecs(instance), payloadtype);
+       if (!payload) {
+               /* Unknown payload type. */
+               return AST_LIST_FIRST(&frames) ? AST_LIST_FIRST(&frames) : &ast_null_frame;
+       }
+
+       /* If the payload is not actually an Asterisk one but a special one pass it off to the respective handler */
+       if (!payload->asterisk_format) {
+               struct ast_frame *f = NULL;
+               if (payload->rtp_code == AST_RTP_DTMF) {
+                       /* process_dtmf_rfc2833 may need to return multiple frames. We do this
+                        * by passing the pointer to the frame list to it so that the method
+                        * can append frames to the list as needed.
+                        */
+                       process_dtmf_rfc2833(instance, read_area + hdrlen, res - hdrlen, seqno, timestamp, payloadtype, mark, &frames);
+               } else if (payload->rtp_code == AST_RTP_CISCO_DTMF) {
+                       f = process_dtmf_cisco(instance, read_area + hdrlen, res - hdrlen, seqno, timestamp, payloadtype, mark);
+               } else if (payload->rtp_code == AST_RTP_CN) {
+                       f = process_cn_rfc3389(instance, read_area + hdrlen, res - hdrlen, seqno, timestamp, payloadtype, mark);
+               } else {
+                       ast_log(LOG_NOTICE, "Unknown RTP codec %d received from '%s'\n",
+                               payloadtype,
+                               ast_sockaddr_stringify(remote_address));
+               }
+
+               if (f) {
+                       AST_LIST_INSERT_TAIL(&frames, f, frame_list);
+               }
+               /* Even if no frame was returned by one of the above methods,
+                * we may have a frame to return in our frame list
+                */
+               return AST_LIST_FIRST(&frames) ? AST_LIST_FIRST(&frames) : &ast_null_frame;
+       }
+
+       ao2_replace(rtp->lastrxformat, payload->format);
+       ao2_replace(rtp->f.subclass.format, payload->format);
+       switch (ast_format_get_type(rtp->f.subclass.format)) {
+       case AST_MEDIA_TYPE_AUDIO:
+               rtp->f.frametype = AST_FRAME_VOICE;
+               break;
+       case AST_MEDIA_TYPE_VIDEO:
+               rtp->f.frametype = AST_FRAME_VIDEO;
+               break;
+       case AST_MEDIA_TYPE_TEXT:
+               rtp->f.frametype = AST_FRAME_TEXT;
+               break;
+       case AST_MEDIA_TYPE_IMAGE:
+               /* Fall through */
+       default:
+               ast_log(LOG_WARNING, "Unknown or unsupported media type: %s\n",
+                       ast_codec_media_type2str(ast_format_get_type(rtp->f.subclass.format)));
+               return &ast_null_frame;
+       }
+
+       if (rtp->dtmf_timeout && rtp->dtmf_timeout < timestamp) {
+               rtp->dtmf_timeout = 0;
+
+               if (rtp->resp) {
+                       struct ast_frame *f;
+                       f = create_dtmf_frame(instance, AST_FRAME_DTMF_END, 0);
+                       f->len = ast_tvdiff_ms(ast_samp2tv(rtp->dtmf_duration, rtp_get_rate(f->subclass.format)), ast_tv(0, 0));
+                       rtp->resp = 0;
+                       rtp->dtmf_timeout = rtp->dtmf_duration = 0;
+                       AST_LIST_INSERT_TAIL(&frames, f, frame_list);
+                       return AST_LIST_FIRST(&frames);
+               }
+       }
+
+       rtp->f.src = "RTP";
+       rtp->f.mallocd = 0;
+       rtp->f.datalen = res - hdrlen;
+       rtp->f.data.ptr = read_area + hdrlen;
+       rtp->f.offset = hdrlen + AST_FRIENDLY_OFFSET;
+       ast_set_flag(&rtp->f, AST_FRFLAG_HAS_SEQUENCE_NUMBER);
+       rtp->f.seqno = seqno;
+       rtp->f.stream_num = rtp->stream_num;
+
+       if ((ast_format_cmp(rtp->f.subclass.format, ast_format_t140) == AST_FORMAT_CMP_EQUAL)
+               && ((int)seqno - (prev_seqno + 1) > 0)
+               && ((int)seqno - (prev_seqno + 1) < 10)) {
+               unsigned char *data = rtp->f.data.ptr;
+
+               memmove(rtp->f.data.ptr+3, rtp->f.data.ptr, rtp->f.datalen);
+               rtp->f.datalen +=3;
+               *data++ = 0xEF;
+               *data++ = 0xBF;
+               *data = 0xBD;
+       }
+
+       if (ast_format_cmp(rtp->f.subclass.format, ast_format_t140_red) == AST_FORMAT_CMP_EQUAL) {
+               unsigned char *data = rtp->f.data.ptr;
+               unsigned char *header_end;
+               int num_generations;
+               int header_length;
+               int len;
+               int diff =(int)seqno - (prev_seqno+1); /* if diff = 0, no drop*/
+               int x;
+
+               ao2_replace(rtp->f.subclass.format, ast_format_t140);
+               header_end = memchr(data, ((*data) & 0x7f), rtp->f.datalen);
+               if (header_end == NULL) {
+                       return AST_LIST_FIRST(&frames) ? AST_LIST_FIRST(&frames) : &ast_null_frame;
+               }
+               header_end++;
+
+               header_length = header_end - data;
+               num_generations = header_length / 4;
+               len = header_length;
+
+               if (!diff) {
+                       for (x = 0; x < num_generations; x++)
+                               len += data[x * 4 + 3];
+
+                       if (!(rtp->f.datalen - len))
+                               return AST_LIST_FIRST(&frames) ? AST_LIST_FIRST(&frames) : &ast_null_frame;
+
+                       rtp->f.data.ptr += len;
+                       rtp->f.datalen -= len;
+               } else if (diff > num_generations && diff < 10) {
+                       len -= 3;
+                       rtp->f.data.ptr += len;
+                       rtp->f.datalen -= len;
+
+                       data = rtp->f.data.ptr;
+                       *data++ = 0xEF;
+                       *data++ = 0xBF;
+                       *data = 0xBD;
+               } else {
+                       for ( x = 0; x < num_generations - diff; x++)
+                               len += data[x * 4 + 3];
+
+                       rtp->f.data.ptr += len;
+                       rtp->f.datalen -= len;
+               }
+       }
+
+       if (ast_format_get_type(rtp->f.subclass.format) == AST_MEDIA_TYPE_AUDIO) {
+               rtp->f.samples = ast_codec_samples_count(&rtp->f);
+               if (ast_format_cache_is_slinear(rtp->f.subclass.format)) {
+                       ast_frame_byteswap_be(&rtp->f);
+               }
+               calc_rxstamp(&rtp->f.delivery, rtp, timestamp, mark);
+               /* Add timing data to let ast_generic_bridge() put the frame into a jitterbuf */
+               ast_set_flag(&rtp->f, AST_FRFLAG_HAS_TIMING_INFO);
+               rtp->f.ts = timestamp / (rtp_get_rate(rtp->f.subclass.format) / 1000);
+               rtp->f.len = rtp->f.samples / ((ast_format_get_sample_rate(rtp->f.subclass.format) / 1000));
+       } else if (ast_format_get_type(rtp->f.subclass.format) == AST_MEDIA_TYPE_VIDEO) {
+               /* Video -- samples is # of samples vs. 90000 */
+               if (!rtp->lastividtimestamp)
+                       rtp->lastividtimestamp = timestamp;
+               ast_set_flag(&rtp->f, AST_FRFLAG_HAS_TIMING_INFO);
+               rtp->f.ts = timestamp / (rtp_get_rate(rtp->f.subclass.format) / 1000);
+               rtp->f.samples = timestamp - rtp->lastividtimestamp;
+               rtp->lastividtimestamp = timestamp;
+               rtp->f.delivery.tv_sec = 0;
+               rtp->f.delivery.tv_usec = 0;
+               /* Pass the RTP marker bit as bit */
+               rtp->f.subclass.frame_ending = mark ? 1 : 0;
+       } else if (ast_format_get_type(rtp->f.subclass.format) == AST_MEDIA_TYPE_TEXT) {
+               /* TEXT -- samples is # of samples vs. 1000 */
+               if (!rtp->lastitexttimestamp)
+                       rtp->lastitexttimestamp = timestamp;
+               rtp->f.samples = timestamp - rtp->lastitexttimestamp;
+               rtp->lastitexttimestamp = timestamp;
+               rtp->f.delivery.tv_sec = 0;
+               rtp->f.delivery.tv_usec = 0;
+       } else {
+               ast_log(LOG_WARNING, "Unknown or unsupported media type: %s\n",
+                       ast_codec_media_type2str(ast_format_get_type(rtp->f.subclass.format)));
+               return &ast_null_frame;
+       }
+
+       AST_LIST_INSERT_TAIL(&frames, &rtp->f, frame_list);
+       return AST_LIST_FIRST(&frames);
+}
+
+/*! \pre instance is locked */
+static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtcp)
+{
+       struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
+       struct ast_srtp *srtp;
+       RAII_VAR(struct ast_rtp_instance *, child, NULL, rtp_instance_unlock);
+       struct ast_sockaddr addr;
+       int res, hdrlen = 12, version, payloadtype, mark;
+       unsigned char *read_area = rtp->rawdata + AST_FRIENDLY_OFFSET;
+       size_t read_area_size = sizeof(rtp->rawdata) - AST_FRIENDLY_OFFSET;
+       unsigned int *rtpheader = (unsigned int*)(read_area), seqno, ssrc, timestamp, prev_seqno;
+       struct ast_sockaddr remote_address = { {0,} };
+       struct frame_list frames;
+       struct ast_frame *frame;
+
+       /* If this is actually RTCP let's hop on over and handle it */
+       if (rtcp) {
+               if (rtp->rtcp && rtp->rtcp->type == AST_RTP_INSTANCE_RTCP_STANDARD) {
+                       return ast_rtcp_read(instance);
+               }
+               return &ast_null_frame;
+       }
+
+       /* Actually read in the data from the socket */
+       if ((res = rtp_recvfrom(instance, read_area, read_area_size, 0,
+                               &addr)) < 0) {
+               if (res == RTP_DTLS_ESTABLISHED) {
+                       rtp->f.frametype = AST_FRAME_CONTROL;
+                       rtp->f.subclass.integer = AST_CONTROL_SRCCHANGE;
+                       return &rtp->f;
+               }
+
+               ast_assert(errno != EBADF);
+               if (errno != EAGAIN) {
+                       ast_log(LOG_WARNING, "RTP Read error: %s.  Hanging up.\n",
+                               (errno) ? strerror(errno) : "Unspecified");
                        return NULL;
                }
                return &ast_null_frame;
@@ -5277,7 +6621,7 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
 
        /* This could be a multiplexed RTCP packet. If so, be sure to interpret it correctly */
        if (rtcp_mux(rtp, read_area)) {
-               return ast_rtcp_interpret(instance, read_area, res, &addr);
+               return ast_rtcp_interpret(instance, ast_rtp_instance_get_srtp(instance, 1), read_area, res, &addr);
        }
 
        /* Make sure the data that was read in is actually enough to make up an RTP packet */
@@ -5328,8 +6672,15 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
        /* We use the SSRC to determine what RTP instance this packet is actually for */
        ssrc = ntohl(rtpheader[2]);
 
+       /* We use the SRTP data from the provided instance that it came in on, not the child */
+       srtp = ast_rtp_instance_get_srtp(instance, 0);
+
        /* Determine the appropriate instance for this */
-       child = rtp_find_instance_by_ssrc(instance, rtp, ssrc);
+       child = rtp_find_instance_by_packet_source_ssrc(instance, rtp, ssrc);
+       if (!child) {
+               /* Neither the bundled parent nor any child has this SSRC */
+               return &ast_null_frame;
+       }
        if (child != instance) {
                /* It is safe to hold the child lock while holding the parent lock, we guarantee that the locking order
                 * is always parent->child or that the child lock is not held when acquiring the parent lock.
@@ -5343,31 +6694,154 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
        }
 
        /* If strict RTP protection is enabled see if we need to learn the remote address or if we need to drop the packet */
-       if (rtp->strict_rtp_state == STRICT_RTP_LEARN) {
-               if (!ast_sockaddr_cmp(&rtp->strict_rtp_address, &addr)) {
-                       /* We are learning a new address but have received traffic from the existing address,
-                        * accept it but reset the current learning for the new source so it only takes over
-                        * once sufficient traffic has been received. */
-                       rtp_learning_seq_init(&rtp->rtp_source_learn, seqno);
+       switch (rtp->strict_rtp_state) {
+       case STRICT_RTP_LEARN:
+               /*
+                * Scenario setup:
+                * PartyA -- Ast1 -- Ast2 -- PartyB
+                *
+                * The learning timeout is necessary for Ast1 to handle the above
+                * setup where PartyA calls PartyB and Ast2 initiates direct media
+                * between Ast1 and PartyB.  Ast1 may lock onto the Ast2 stream and
+                * never learn the PartyB stream when it starts.  The timeout makes
+                * Ast1 stay in the learning state long enough to see and learn the
+                * RTP stream from PartyB.
+                *
+                * To mitigate against attack, the learning state cannot switch
+                * streams while there are competing streams.  The competing streams
+                * interfere with each other's qualification.  Once we accept a
+                * stream and reach the timeout, an attacker cannot interfere
+                * anymore.
+                *
+                * Here are a few scenarios and each one assumes that the streams
+                * are continuous:
+                *
+                * 1) We already have a known stream source address and the known
+                * stream wants to change to a new source address.  An attacking
+                * stream will block learning the new stream source.  After the
+                * timeout we re-lock onto the original stream source address which
+                * likely went away.  The result is one way audio.
+                *
+                * 2) We already have a known stream source address and the known
+                * stream doesn't want to change source addresses.  An attacking
+                * stream will not be able to replace the known stream.  After the
+                * timeout we re-lock onto the known stream.  The call is not
+                * affected.
+                *
+                * 3) We don't have a known stream source address.  This presumably
+                * is the start of a call.  Competing streams will result in staying
+                * in learning mode until a stream becomes the victor and we reach
+                * the timeout.  We cannot exit learning if we have no known stream
+                * to lock onto.  The result is one way audio until there is a victor.
+                *
+                * If we learn a stream source address before the timeout we will be
+                * in scenario 1) or 2) when a competing stream starts.
+                */
+               if (!ast_sockaddr_isnull(&rtp->strict_rtp_address)
+                       && STRICT_RTP_LEARN_TIMEOUT < ast_tvdiff_ms(ast_tvnow(), rtp->rtp_source_learn.start)) {
+                       ast_verb(4, "%p -- Strict RTP learning complete - Locking on source address %s\n",
+                               rtp, ast_sockaddr_stringify(&rtp->strict_rtp_address));
+                       ast_test_suite_event_notify("STRICT_RTP_LEARN", "Source: %s",
+                               ast_sockaddr_stringify(&rtp->strict_rtp_address));
+                       rtp->strict_rtp_state = STRICT_RTP_CLOSED;
                } else {
-                       /* Start trying to learn from the new address. If we pass a probationary period with
-                        * it, that means we've stopped getting RTP from the original source and we should
-                        * switch to it.
+                       struct ast_sockaddr target_address;
+
+                       if (!ast_sockaddr_cmp(&rtp->strict_rtp_address, &addr)) {
+                               /*
+                                * We are open to learning a new address but have received
+                                * traffic from the current address, accept it and reset
+                                * the learning counts for a new source.  When no more
+                                * current source packets arrive a new source can take over
+                                * once sufficient traffic is received.
+                                */
+                               rtp_learning_seq_init(&rtp->rtp_source_learn, seqno);
+                               break;
+                       }
+
+                       /*
+                        * We give preferential treatment to the requested target address
+                        * (negotiated SDP address) where we are to send our RTP.  However,
+                        * the other end has no obligation to send from that address even
+                        * though it is practically a requirement when NAT is involved.
                         */
-                       if (rtp_learning_rtp_seq_update(&rtp->rtp_source_learn, seqno)) {
-                               ast_debug(1, "%p -- Received RTP packet from %s, dropping due to strict RTP protection. Will switch to it in %d packets\n",
-                                       rtp, ast_sockaddr_stringify(&addr), rtp->rtp_source_learn.packets);
-                               return &ast_null_frame;
+                       ast_rtp_instance_get_requested_target_address(instance, &target_address);
+                       if (!ast_sockaddr_cmp(&target_address, &addr)) {
+                               /* Accept the negotiated target RTP stream as the source */
+                               ast_verb(4, "%p -- Strict RTP switching to RTP target address %s as source\n",
+                                       rtp, ast_sockaddr_stringify(&addr));
+                               ast_sockaddr_copy(&rtp->strict_rtp_address, &addr);
+                               rtp_learning_seq_init(&rtp->rtp_source_learn, seqno);
+                               break;
                        }
-                       ast_sockaddr_copy(&rtp->strict_rtp_address, &addr);
 
-                       ast_verb(4, "%p -- Probation passed - setting RTP source address to %s\n", rtp, ast_sockaddr_stringify(&addr));
-                       rtp->strict_rtp_state = STRICT_RTP_CLOSED;
+                       /*
+                        * Trying to learn a new address.  If we pass a probationary period
+                        * with it, that means we've stopped getting RTP from the original
+                        * source and we should switch to it.
+                        */
+                       if (!ast_sockaddr_cmp(&rtp->rtp_source_learn.proposed_address, &addr)) {
+                               if (rtp->rtp_source_learn.stream_type == AST_MEDIA_TYPE_UNKNOWN) {
+                                       struct ast_rtp_codecs *codecs;
+
+                                       codecs = ast_rtp_instance_get_codecs(instance);
+                                       rtp->rtp_source_learn.stream_type =
+                                               ast_rtp_codecs_get_stream_type(codecs);
+                                       ast_verb(4, "%p -- Strict RTP qualifying stream type: %s\n",
+                                               rtp, ast_codec_media_type2str(rtp->rtp_source_learn.stream_type));
+                               }
+                               if (!rtp_learning_rtp_seq_update(&rtp->rtp_source_learn, seqno)) {
+                                       /* Accept the new RTP stream */
+                                       ast_verb(4, "%p -- Strict RTP switching source address to %s\n",
+                                               rtp, ast_sockaddr_stringify(&addr));
+                                       ast_sockaddr_copy(&rtp->strict_rtp_address, &addr);
+                                       rtp_learning_seq_init(&rtp->rtp_source_learn, seqno);
+                                       break;
+                               }
+                               /* Not ready to accept the RTP stream candidate */
+                               ast_debug(1, "%p -- Received RTP packet from %s, dropping due to strict RTP protection. Will switch to it in %d packets.\n",
+                                       rtp, ast_sockaddr_stringify(&addr), rtp->rtp_source_learn.packets);
+                       } else {
+                               /*
+                                * This is either an attacking stream or
+                                * the start of the expected new stream.
+                                */
+                               ast_sockaddr_copy(&rtp->rtp_source_learn.proposed_address, &addr);
+                               rtp_learning_seq_init(&rtp->rtp_source_learn, seqno);
+                               ast_debug(1, "%p -- Received RTP packet from %s, dropping due to strict RTP protection. Qualifying new stream.\n",
+                                       rtp, ast_sockaddr_stringify(&addr));
+                       }
+                       return &ast_null_frame;
+               }
+               /* Fall through */
+       case STRICT_RTP_CLOSED:
+               /*
+                * We should not allow a stream address change if the SSRC matches
+                * once strictrtp learning is closed.  Any kind of address change
+                * like this should have happened while we were in the learning
+                * state.  We do not want to allow the possibility of an attacker
+                * interfering with the RTP stream after the learning period.
+                * An attacker could manage to get an RTCP packet redirected to
+                * them which can contain the SSRC value.
+                */
+               if (!ast_sockaddr_cmp(&rtp->strict_rtp_address, &addr)) {
+                       break;
                }
-       } else if (rtp->strict_rtp_state == STRICT_RTP_CLOSED && ast_sockaddr_cmp(&rtp->strict_rtp_address, &addr)) {
                ast_debug(1, "%p -- Received RTP packet from %s, dropping due to strict RTP protection.\n",
                        rtp, ast_sockaddr_stringify(&addr));
+#ifdef TEST_FRAMEWORK
+       {
+               static int strict_rtp_test_event = 1;
+               if (strict_rtp_test_event) {
+                       ast_test_suite_event_notify("STRICT_RTP_CLOSED", "Source: %s",
+                               ast_sockaddr_stringify(&addr));
+                       strict_rtp_test_event = 0; /* Only run this event once to prevent possible spam */
+               }
+       }
+#endif
                return &ast_null_frame;
+       case STRICT_RTP_OPEN:
+               break;
        }
 
        /* If symmetric RTP is enabled see if the remote side is not what we expected and change where we are sending audio */
@@ -5380,7 +6854,6 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
                                ast_sockaddr_copy(&rtp->rtcp->them, &addr);
                                ast_sockaddr_set_port(&rtp->rtcp->them, ast_sockaddr_port(&addr) + 1);
                        }
-                       rtp->rxseqno = 0;
                        ast_set_flag(rtp, FLAG_NAT_ACTIVE);
                        if (rtpdebug)
                                ast_debug(0, "RTP NAT: Got audio from other end. Now sending to address %s\n",
@@ -5388,314 +6861,314 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
                }
        }
 
-       /* If we are currently sending DTMF to the remote party send a continuation packet */
-       if (rtp->sending_digit) {
-               ast_rtp_dtmf_continuation(instance);
-       }
-
        /* Pull out the various other fields we will need */
        payloadtype = (seqno & 0x7f0000) >> 16;
-       padding = seqno & (1 << 29);
        mark = seqno & (1 << 23);
-       ext = seqno & (1 << 28);
-       cc = (seqno & 0xF000000) >> 24;
        seqno &= 0xffff;
        timestamp = ntohl(rtpheader[1]);
 
-       AST_LIST_HEAD_INIT_NOLOCK(&frames);
-       /* Force a marker bit and change SSRC if the SSRC changes */
-       if (rtp->rxssrc && rtp->rxssrc != ssrc) {
-               struct ast_frame *f, srcupdate = {
-                       AST_FRAME_CONTROL,
-                       .subclass.integer = AST_CONTROL_SRCCHANGE,
-               };
-
-               if (!mark) {
-                       if (rtpdebug) {
-                               ast_debug(1, "Forcing Marker bit, because SSRC has changed\n");
-                       }
-                       mark = 1;
-               }
-
-               f = ast_frisolate(&srcupdate);
-               AST_LIST_INSERT_TAIL(&frames, f, frame_list);
-
-               rtp->seedrxseqno = 0;
-               rtp->rxcount = 0;
-               rtp->rxoctetcount = 0;
-               rtp->cycles = 0;
-               rtp->lastrxseqno = 0;
-               rtp->last_seqno = 0;
-               rtp->last_end_timestamp = 0;
-               if (rtp->rtcp) {
-                       rtp->rtcp->expected_prior = 0;
-                       rtp->rtcp->received_prior = 0;
-               }
-       }
-
-       rtp->rxssrc = ssrc;
-
-       /* Remove any padding bytes that may be present */
-       if (padding) {
-               res -= read_area[res - 1];
-       }
-
-       /* Skip over any CSRC fields */
-       if (cc) {
-               hdrlen += cc * 4;
-       }
-
-       /* Look for any RTP extensions, currently we do not support any */
-       if (ext) {
-               hdrlen += (ntohl(rtpheader[hdrlen/4]) & 0xffff) << 2;
-               hdrlen += 4;
-               if (option_debug) {
-                       unsigned int profile;
-                       profile = (ntohl(rtpheader[3]) & 0xffff0000) >> 16;
-                       if (profile == 0x505a)
-                               ast_debug(1, "Found Zfone extension in RTP stream - zrtp - not supported.\n");
-                       else
-                               ast_debug(1, "Found unknown RTP Extensions %x\n", profile);
-               }
+       if (rtp_debug_test_addr(&addr)) {
+               ast_verbose("Got  RTP packet from    %s (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6d)\n",
+                           ast_sockaddr_stringify(&addr),
+                           payloadtype, seqno, timestamp, res - hdrlen);
        }
 
-       /* Make sure after we potentially mucked with the header length that it is once again valid */
-       if (res < hdrlen) {
-               ast_log(LOG_WARNING, "RTP Read too short (%d, expecting %d\n", res, hdrlen);
-               return AST_LIST_FIRST(&frames) ? AST_LIST_FIRST(&frames) : &ast_null_frame;
-       }
+       AST_LIST_HEAD_INIT_NOLOCK(&frames);
 
-       rtp->rxcount++;
-       rtp->rxoctetcount += (res - hdrlen);
-       if (rtp->rxcount == 1) {
-               rtp->seedrxseqno = seqno;
-       }
+       /* Only non-bundled instances can change/learn the remote's SSRC implicitly. */
+       if (!child && !AST_VECTOR_SIZE(&rtp->ssrc_mapping)) {
+               /* Force a marker bit and change SSRC if the SSRC changes */
+               if (rtp->themssrc_valid && rtp->themssrc != ssrc) {
+                       struct ast_frame *f, srcupdate = {
+                               AST_FRAME_CONTROL,
+                               .subclass.integer = AST_CONTROL_SRCCHANGE,
+                       };
 
-       /* Do not schedule RR if RTCP isn't run */
-       if (rtp->rtcp && !ast_sockaddr_isnull(&rtp->rtcp->them) && rtp->rtcp->schedid < 0) {
-               /* Schedule transmission of Receiver Report */
-               ao2_ref(instance, +1);
-               rtp->rtcp->schedid = ast_sched_add(rtp->sched, ast_rtcp_calc_interval(rtp), ast_rtcp_write, instance);
-               if (rtp->rtcp->schedid < 0) {
-                       ao2_ref(instance, -1);
-                       ast_log(LOG_WARNING, "scheduling RTCP transmission failed.\n");
+                       if (!mark) {
+                               if (rtpdebug) {
+                                       ast_debug(1, "Forcing Marker bit, because SSRC has changed\n");
+                               }
+                               mark = 1;
+                       }
+
+                       f = ast_frisolate(&srcupdate);
+                       AST_LIST_INSERT_TAIL(&frames, f, frame_list);
+
+                       rtp->seedrxseqno = 0;
+                       rtp->rxcount = 0;
+                       rtp->rxoctetcount = 0;
+                       rtp->cycles = 0;
+                       rtp->lastrxseqno = 0;
+                       rtp->last_seqno = 0;
+                       rtp->last_end_timestamp = 0;
+                       if (rtp->rtcp) {
+                               rtp->rtcp->expected_prior = 0;
+                               rtp->rtcp->received_prior = 0;
+                       }
                }
+
+               rtp->themssrc = ssrc; /* Record their SSRC to put in future RR */
+               rtp->themssrc_valid = 1;
        }
-       if ((int)rtp->lastrxseqno - (int)seqno  > 100) /* if so it would indicate that the sender cycled; allow for misordering */
-               rtp->cycles += RTP_SEQ_MOD;
 
        prev_seqno = rtp->lastrxseqno;
        rtp->lastrxseqno = seqno;
 
-       if (!rtp->themssrc) {
-               rtp->themssrc = ntohl(rtpheader[2]); /* Record their SSRC to put in future RR */
-       }
+       if (!rtp->recv_buffer) {
+               /* If there is no receive buffer then we can pass back the frame directly */
+               return ast_rtp_interpret(instance, srtp, &addr, read_area, res, prev_seqno);
+       } else if (rtp->expectedrxseqno == -1 || seqno == rtp->expectedrxseqno) {
+               rtp->expectedrxseqno = seqno + 1;
 
+               /* If there are no buffered packets that will be placed after this frame then we can
+                * return it directly without duplicating it.
+                */
+               if (!ast_data_buffer_count(rtp->recv_buffer)) {
+                       return ast_rtp_interpret(instance, srtp, &addr, read_area, res, prev_seqno);
+               }
 
-       /* If we are directly bridged to another instance send the audio directly out,
-        * but only after updating core information about the received traffic so that
-        * outgoing RTCP reflects it.
-        */
-       instance1 = ast_rtp_instance_get_bridged(instance);
-       if (instance1
-               && !bridge_p2p_rtp_write(instance, instance1, rtpheader, res, hdrlen)) {
-               struct timeval rxtime;
-               struct ast_frame *f;
+               if (!AST_VECTOR_REMOVE_CMP_ORDERED(&rtp->missing_seqno, seqno, find_by_value,
+                       AST_VECTOR_ELEM_CLEANUP_NOOP)) {
+                       ast_debug(2, "Packet with sequence number '%d' on RTP instance '%p' is no longer missing\n",
+                               seqno, instance);
+               }
 
-               /* Update statistics for jitter so they are correct in RTCP */
-               calc_rxstamp(&rxtime, rtp, timestamp, mark);
+               /* If we don't have the next packet after this we can directly return the frame, as there is no
+                * chance it will be overwritten.
+                */
+               if (!ast_data_buffer_get(rtp->recv_buffer, seqno + 1)) {
+                       return ast_rtp_interpret(instance, srtp, &addr, read_area, res, prev_seqno);
+               }
 
-               /* When doing P2P we don't need to raise any frames about SSRC change to the core */
-               while ((f = AST_LIST_REMOVE_HEAD(&frames, frame_list)) != NULL) {
-                       ast_frfree(f);
+               /* Otherwise we need to dupe the frame so that the potential processing of frames placed after
+                * it do not overwrite the data. You may be thinking that we could just add the current packet
+                * to the head of the frames list and avoid having to duplicate it but this would result in out
+                * of order packet processing by libsrtp which we are trying to avoid.
+                */
+               frame = ast_frdup(ast_rtp_interpret(instance, srtp, &addr, read_area, res, seqno - 1));
+               if (frame) {
+                       AST_LIST_INSERT_TAIL(&frames, frame, frame_list);
                }
 
-               return &ast_null_frame;
-       }
+               /* Add any additional packets that we have buffered and that are available */
+               while (ast_data_buffer_count(rtp->recv_buffer)) {
+                       struct ast_rtp_rtcp_nack_payload *payload;
 
-       if (rtp_debug_test_addr(&addr)) {
-               ast_verbose("Got  RTP packet from    %s (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6d)\n",
-                           ast_sockaddr_stringify(&addr),
-                           payloadtype, seqno, timestamp,res - hdrlen);
-       }
+                       payload = (struct ast_rtp_rtcp_nack_payload *)ast_data_buffer_remove(rtp->recv_buffer, rtp->expectedrxseqno);
+                       if (!payload) {
+                               break;
+                       }
 
-       payload = ast_rtp_codecs_get_payload(ast_rtp_instance_get_codecs(instance), payloadtype);
-       if (!payload) {
-               /* Unknown payload type. */
-               return AST_LIST_FIRST(&frames) ? AST_LIST_FIRST(&frames) : &ast_null_frame;
-       }
+                       frame = ast_frdup(ast_rtp_interpret(instance, srtp, &addr, payload->buf, payload->size, rtp->expectedrxseqno - 1));
+                       ast_free(payload);
 
-       /* If the payload is not actually an Asterisk one but a special one pass it off to the respective handler */
-       if (!payload->asterisk_format) {
-               struct ast_frame *f = NULL;
-               if (payload->rtp_code == AST_RTP_DTMF) {
-                       /* process_dtmf_rfc2833 may need to return multiple frames. We do this
-                        * by passing the pointer to the frame list to it so that the method
-                        * can append frames to the list as needed.
-                        */
-                       process_dtmf_rfc2833(instance, read_area + hdrlen, res - hdrlen, seqno, timestamp, &addr, payloadtype, mark, &frames);
-               } else if (payload->rtp_code == AST_RTP_CISCO_DTMF) {
-                       f = process_dtmf_cisco(instance, read_area + hdrlen, res - hdrlen, seqno, timestamp, &addr, payloadtype, mark);
-               } else if (payload->rtp_code == AST_RTP_CN) {
-                       f = process_cn_rfc3389(instance, read_area + hdrlen, res - hdrlen, seqno, timestamp, &addr, payloadtype, mark);
-               } else {
-                       ast_log(LOG_NOTICE, "Unknown RTP codec %d received from '%s'\n",
-                               payloadtype,
-                               ast_sockaddr_stringify(&remote_address));
-               }
+                       if (!frame) {
+                               /* If this packet can't be interpeted due to being out of memory we return what we have and assume
+                                * that we will determine it is a missing packet later and NACK for it.
+                                */
+                               return AST_LIST_FIRST(&frames);
+                       }
 
-               if (f) {
-                       AST_LIST_INSERT_TAIL(&frames, f, frame_list);
+                       ast_debug(2, "Pulled buffered packet with sequence number '%d' to additionally return on RTP instance '%p'\n",
+                               frame->seqno, instance);
+                       AST_LIST_INSERT_TAIL(&frames, frame, frame_list);
+                       rtp->expectedrxseqno++;
                }
-               /* Even if no frame was returned by one of the above methods,
-                * we may have a frame to return in our frame list
+
+               return AST_LIST_FIRST(&frames);
+       } else if ((abs(seqno - rtp->expectedrxseqno) > 100) ||
+               ast_data_buffer_count(rtp->recv_buffer) == ast_data_buffer_max(rtp->recv_buffer)) {
+               int inserted = 0;
+
+               /* We have a large number of outstanding buffered packets or we've jumped far ahead in time.
+                * To compensate we dump what we have in the buffer and place the current packet in a logical
+                * spot. In the case of video we also require a full frame to give the decoding side a fighting
+                * chance.
                 */
-               return AST_LIST_FIRST(&frames) ? AST_LIST_FIRST(&frames) : &ast_null_frame;
-       }
 
-       ao2_replace(rtp->lastrxformat, payload->format);
-       ao2_replace(rtp->f.subclass.format, payload->format);
-       switch (ast_format_get_type(rtp->f.subclass.format)) {
-       case AST_MEDIA_TYPE_AUDIO:
-               rtp->f.frametype = AST_FRAME_VOICE;
-               break;
-       case AST_MEDIA_TYPE_VIDEO:
-               rtp->f.frametype = AST_FRAME_VIDEO;
-               break;
-       case AST_MEDIA_TYPE_TEXT:
-               rtp->f.frametype = AST_FRAME_TEXT;
-               break;
-       case AST_MEDIA_TYPE_IMAGE:
-               /* Fall through */
-       default:
-               ast_log(LOG_WARNING, "Unknown or unsupported media type: %s\n",
-                       ast_codec_media_type2str(ast_format_get_type(rtp->f.subclass.format)));
-               return &ast_null_frame;
-       }
-       rtp->rxseqno = seqno;
+               if (rtp->rtp_source_learn.stream_type == AST_MEDIA_TYPE_VIDEO) {
+                       ast_debug(2, "Source on RTP instance '%p' has wild gap or packet loss, sending FIR\n",
+                               instance);
+                       rtp_write_rtcp_fir(instance, rtp, &remote_address);
+               }
 
-       if (rtp->dtmf_timeout && rtp->dtmf_timeout < timestamp) {
-               rtp->dtmf_timeout = 0;
+               while (ast_data_buffer_count(rtp->recv_buffer)) {
+                       struct ast_rtp_rtcp_nack_payload *payload;
 
-               if (rtp->resp) {
-                       struct ast_frame *f;
-                       f = create_dtmf_frame(instance, AST_FRAME_DTMF_END, 0);
-                       f->len = ast_tvdiff_ms(ast_samp2tv(rtp->dtmf_duration, rtp_get_rate(f->subclass.format)), ast_tv(0, 0));
-                       rtp->resp = 0;
-                       rtp->dtmf_timeout = rtp->dtmf_duration = 0;
-                       AST_LIST_INSERT_TAIL(&frames, f, frame_list);
-                       return AST_LIST_FIRST(&frames);
+                       payload = (struct ast_rtp_rtcp_nack_payload *)ast_data_buffer_remove_head(rtp->recv_buffer);
+                       if (!payload) {
+                               continue;
+                       }
+
+                       /* Even when dumping the receive buffer we do our best to order things, so we ensure that the
+                        * packet we just received is processed in the correct order, so see if we need to insert it now.
+                        */
+                       if (!inserted) {
+                               int buffer_seqno;
+
+                               buffer_seqno = ntohl(payload->buf[0]) & 0xffff;
+                               if (seqno < buffer_seqno) {
+                                       frame = ast_frdup(ast_rtp_interpret(instance, srtp, &addr, read_area, res, prev_seqno));
+                                       if (frame) {
+                                               AST_LIST_INSERT_TAIL(&frames, frame, frame_list);
+                                               rtp->expectedrxseqno = seqno + 1;
+                                               prev_seqno = seqno;
+                                               ast_debug(2, "Inserted just received packet with sequence number '%d' in correct order on RTP instance '%p'\n",
+                                                       seqno, instance);
+                                       }
+                                       inserted = 1;
+                               }
+                       }
+
+                       frame = ast_frdup(ast_rtp_interpret(instance, srtp, &addr, payload->buf, payload->size, prev_seqno));
+                       if (frame) {
+                               AST_LIST_INSERT_TAIL(&frames, frame, frame_list);
+                               prev_seqno = frame->seqno;
+                               ast_debug(2, "Emptying queue and returning packet with sequence number '%d' from RTP instance '%p'\n",
+                                       frame->seqno, instance);
+                       }
+
+                       ast_free(payload);
                }
-       }
 
-       rtp->lastrxts = timestamp;
+               if (!inserted) {
+                       /* This current packet goes after them, and we assume that packets going forward will follow
+                        * that new sequence number increment. It is okay for this to not be duplicated as it is guaranteed
+                        * to be the last packet processed right now and it is also guaranteed that it will always return
+                        * non-NULL.
+                        */
+                       frame = ast_rtp_interpret(instance, srtp, &addr, read_area, res, prev_seqno);
+                       AST_LIST_INSERT_TAIL(&frames, frame, frame_list);
+                       rtp->expectedrxseqno = seqno + 1;
 
-       rtp->f.src = "RTP";
-       rtp->f.mallocd = 0;
-       rtp->f.datalen = res - hdrlen;
-       rtp->f.data.ptr = read_area + hdrlen;
-       rtp->f.offset = hdrlen + AST_FRIENDLY_OFFSET;
-       ast_set_flag(&rtp->f, AST_FRFLAG_HAS_SEQUENCE_NUMBER);
-       rtp->f.seqno = seqno;
-       rtp->f.stream_num = rtp->stream_num;
+                       ast_debug(2, "Adding just received packet with sequence number '%d' to end of dumped queue on RTP instance '%p'\n",
+                               seqno, instance);
+               }
 
-       if ((ast_format_cmp(rtp->f.subclass.format, ast_format_t140) == AST_FORMAT_CMP_EQUAL)
-               && ((int)seqno - (prev_seqno + 1) > 0)
-               && ((int)seqno - (prev_seqno + 1) < 10)) {
-               unsigned char *data = rtp->f.data.ptr;
+               /* As there is such a large gap we don't want to flood the order side with missing packets, so we
+                * give up and start anew.
+                */
+               AST_VECTOR_RESET(&rtp->missing_seqno, AST_VECTOR_ELEM_CLEANUP_NOOP);
 
-               memmove(rtp->f.data.ptr+3, rtp->f.data.ptr, rtp->f.datalen);
-               rtp->f.datalen +=3;
-               *data++ = 0xEF;
-               *data++ = 0xBF;
-               *data = 0xBD;
-       }
+               return AST_LIST_FIRST(&frames);
+       } else if (seqno < rtp->expectedrxseqno) {
+               /* If this is a packet from the past then we have received a duplicate packet, so just drop it */
+               ast_debug(2, "Received an old packet with sequence number '%d' on RTP instance '%p', dropping it\n",
+                       seqno, instance);
+               return &ast_null_frame;
+       } else if (ast_data_buffer_get(rtp->recv_buffer, seqno)) {
+               /* If this is a packet we already have buffered then it is a duplicate, so just drop it */
+               ast_debug(2, "Received a duplicate transmission of packet with sequence number '%d' on RTP instance '%p', dropping it\n",
+                       seqno, instance);
+               return &ast_null_frame;
+       } else {
+               /* This is an out of order packet from the future */
+               struct ast_rtp_rtcp_nack_payload *payload;
+               int difference;
+
+               ast_debug(2, "Received an out of order packet with sequence number '%d' from the future on RTP instance '%p'\n",
+                       seqno, instance);
+
+               payload = ast_malloc(sizeof(*payload) + res);
+               if (!payload) {
+                       /* If the payload can't be allocated then we can't defer this packet right now.
+                        * Instead of dumping what we have we pretend we lost this packet. It will then
+                        * get NACKed later or the existing buffer will be returned entirely. Well, we may
+                        * try since we're seemingly out of memory. It's a bad situation all around and
+                        * packets are likely to get lost anyway.
+                        */
+                       return &ast_null_frame;
+               }
 
-       if (ast_format_cmp(rtp->f.subclass.format, ast_format_t140_red) == AST_FORMAT_CMP_EQUAL) {
-               unsigned char *data = rtp->f.data.ptr;
-               unsigned char *header_end;
-               int num_generations;
-               int header_length;
-               int len;
-               int diff =(int)seqno - (prev_seqno+1); /* if diff = 0, no drop*/
-               int x;
+               payload->size = res;
+               memcpy(payload->buf, rtpheader, res);
+               ast_data_buffer_put(rtp->recv_buffer, seqno, payload);
+               AST_VECTOR_REMOVE_CMP_ORDERED(&rtp->missing_seqno, seqno, find_by_value,
+                       AST_VECTOR_ELEM_CLEANUP_NOOP);
+
+               difference = seqno - (prev_seqno + 1);
+               while (difference > 0) {
+                       /* We don't want missing sequence number duplicates. If, for some reason,
+                        * packets are really out of order, we could end up in this scenario:
+                        *
+                        * We are expecting sequence number 100
+                        * We receive sequence number 105
+                        * Sequence numbers 100 through 104 get added to the vector
+                        * We receive sequence number 101 (this section is skipped)
+                        * We receive sequence number 103
+                        * Sequence number 102 is added to the vector
+                        *
+                        * This will prevent the duplicate from being added.
+                        */
+                       if (AST_VECTOR_GET_CMP(&rtp->missing_seqno, seqno - difference,
+                                               find_by_value)) {
+                               difference--;
+                               continue;
+                       }
 
-               ao2_replace(rtp->f.subclass.format, ast_format_t140);
-               header_end = memchr(data, ((*data) & 0x7f), rtp->f.datalen);
-               if (header_end == NULL) {
-                       return AST_LIST_FIRST(&frames) ? AST_LIST_FIRST(&frames) : &ast_null_frame;
+                       ast_debug(2, "Added missing sequence number '%d' to RTP instance '%p'\n",
+                               seqno - difference, instance);
+                       AST_VECTOR_ADD_SORTED(&rtp->missing_seqno, seqno - difference,
+                                       compare_by_value);
+                       difference--;
                }
-               header_end++;
 
-               header_length = header_end - data;
-               num_generations = header_length / 4;
-               len = header_length;
+               /* When our data buffer is half full we assume that the packets aren't just out of order but
+                * have actually been lost. To get them back we construct and send a NACK causing the sender to
+                * retransmit them.
+                */
+               if (ast_data_buffer_count(rtp->recv_buffer) == ast_data_buffer_max(rtp->recv_buffer) / 2) {
+                       int packet_len = 0;
+                       int res = 0;
+                       int ice;
+                       int sr;
+                       size_t data_size = AST_UUID_STR_LEN + 128 + (seqno - rtp->expectedrxseqno) / 17;
+                       RAII_VAR(unsigned char *, rtcpheader, NULL, ast_free_ptr);
+                       RAII_VAR(struct ast_rtp_rtcp_report *, rtcp_report,
+                                       ast_rtp_rtcp_report_alloc(rtp->themssrc_valid ? 1 : 0),
+                                       ao2_cleanup);
+
+                       rtcpheader = ast_malloc(sizeof(*rtcpheader) + data_size);
+                       if (!rtcpheader) {
+                               ast_debug(1, "Failed to allocate memory for NACK\n");
+                               return &ast_null_frame;
+                       }
 
-               if (!diff) {
-                       for (x = 0; x < num_generations; x++)
-                               len += data[x * 4 + 3];
+                       memset(rtcpheader, 0, data_size);
 
-                       if (!(rtp->f.datalen - len))
-                               return AST_LIST_FIRST(&frames) ? AST_LIST_FIRST(&frames) : &ast_null_frame;
+                       res = ast_rtcp_generate_report(instance, rtcpheader, rtcp_report, &sr);
 
-                       rtp->f.data.ptr += len;
-                       rtp->f.datalen -= len;
-               } else if (diff > num_generations && diff < 10) {
-                       len -= 3;
-                       rtp->f.data.ptr += len;
-                       rtp->f.datalen -= len;
+                       if (res == 0 || res == 1) {
+                               ast_debug(1, "Failed to add %s report to NACK, stopping here\n", sr ? "SR" : "RR");
+                               return &ast_null_frame;
+                       }
 
-                       data = rtp->f.data.ptr;
-                       *data++ = 0xEF;
-                       *data++ = 0xBF;
-                       *data = 0xBD;
-               } else {
-                       for ( x = 0; x < num_generations - diff; x++)
-                               len += data[x * 4 + 3];
+                       packet_len += res;
 
-                       rtp->f.data.ptr += len;
-                       rtp->f.datalen -= len;
-               }
-       }
+                       res = ast_rtcp_generate_nack(instance, rtcpheader + packet_len);
 
-       if (ast_format_get_type(rtp->f.subclass.format) == AST_MEDIA_TYPE_AUDIO) {
-               rtp->f.samples = ast_codec_samples_count(&rtp->f);
-               if (ast_format_cache_is_slinear(rtp->f.subclass.format)) {
-                       ast_frame_byteswap_be(&rtp->f);
+                       if (res == 0) {
+                               ast_debug(1, "Failed to construct NACK, stopping here\n");
+                               return &ast_null_frame;
+                       }
+
+                       packet_len += res;
+
+                       res = rtcp_sendto(instance, rtcpheader, packet_len, 0, &remote_address, &ice);
+                       if (res < 0) {
+                               ast_debug(1, "Failed to send NACK request out\n");
+                       } else {
+                               /* Update RTCP SR/RR statistics */
+                               ast_rtcp_calculate_sr_rr_statistics(instance, rtcp_report, remote_address, ice, sr);
+                       }
+
+                       ast_debug(2, "Sending a NACK request on RTP instance '%p' to get missing packets\n", instance);
                }
-               calc_rxstamp(&rtp->f.delivery, rtp, timestamp, mark);
-               /* Add timing data to let ast_generic_bridge() put the frame into a jitterbuf */
-               ast_set_flag(&rtp->f, AST_FRFLAG_HAS_TIMING_INFO);
-               rtp->f.ts = timestamp / (rtp_get_rate(rtp->f.subclass.format) / 1000);
-               rtp->f.len = rtp->f.samples / ((ast_format_get_sample_rate(rtp->f.subclass.format) / 1000));
-       } else if (ast_format_get_type(rtp->f.subclass.format) == AST_MEDIA_TYPE_VIDEO) {
-               /* Video -- samples is # of samples vs. 90000 */
-               if (!rtp->lastividtimestamp)
-                       rtp->lastividtimestamp = timestamp;
-               ast_set_flag(&rtp->f, AST_FRFLAG_HAS_TIMING_INFO);
-               rtp->f.ts = timestamp / (rtp_get_rate(rtp->f.subclass.format) / 1000);
-               rtp->f.samples = timestamp - rtp->lastividtimestamp;
-               rtp->lastividtimestamp = timestamp;
-               rtp->f.delivery.tv_sec = 0;
-               rtp->f.delivery.tv_usec = 0;
-               /* Pass the RTP marker bit as bit */
-               rtp->f.subclass.frame_ending = mark ? 1 : 0;
-       } else if (ast_format_get_type(rtp->f.subclass.format) == AST_MEDIA_TYPE_TEXT) {
-               /* TEXT -- samples is # of samples vs. 1000 */
-               if (!rtp->lastitexttimestamp)
-                       rtp->lastitexttimestamp = timestamp;
-               rtp->f.samples = timestamp - rtp->lastitexttimestamp;
-               rtp->lastitexttimestamp = timestamp;
-               rtp->f.delivery.tv_sec = 0;
-               rtp->f.delivery.tv_usec = 0;
-       } else {
-               ast_log(LOG_WARNING, "Unknown or unsupported media type: %s\n",
-                       ast_codec_media_type2str(ast_format_get_type(rtp->f.subclass.format)));
-               return &ast_null_frame;;
+
+               return &ast_null_frame;
        }
 
-       AST_LIST_INSERT_TAIL(&frames, &rtp->f, frame_list);
-       return AST_LIST_FIRST(&frames);
+       return &ast_null_frame;
 }
 
 /*! \pre instance is locked */
@@ -5718,7 +7191,7 @@ static void ast_rtp_prop_set(struct ast_rtp_instance *instance, enum ast_rtp_pro
                                        return;
                                }
                                rtp->rtcp->s = -1;
-#ifdef HAVE_OPENSSL_SRTP
+#if defined(HAVE_OPENSSL) && (OPENSSL_VERSION_NUMBER >= 0x10001000L) && !defined(OPENSSL_NO_SRTP)
                                rtp->rtcp->dtls.timeout_timer = -1;
 #endif
                                rtp->rtcp->schedid = -1;
@@ -5781,7 +7254,7 @@ static void ast_rtp_prop_set(struct ast_rtp_instance *instance, enum ast_rtp_pro
                                        rtp_add_candidates_to_ice(instance, rtp, &rtp->rtcp->us, ast_sockaddr_port(&rtp->rtcp->us), AST_RTP_ICE_COMPONENT_RTCP, TRANSPORT_SOCKET_RTCP);
                                }
 #endif
-#ifdef HAVE_OPENSSL_SRTP
+#if defined(HAVE_OPENSSL) && (OPENSSL_VERSION_NUMBER >= 0x10001000L) && !defined(OPENSSL_NO_SRTP)
                                dtls_setup_rtcp(instance);
 #endif
                        } else {
@@ -5801,7 +7274,7 @@ static void ast_rtp_prop_set(struct ast_rtp_instance *instance, enum ast_rtp_pro
                                rtp->rtcp->s = rtp->s;
                                ast_rtp_instance_get_remote_address(instance, &addr);
                                ast_sockaddr_copy(&rtp->rtcp->them, &addr);
-#ifdef HAVE_OPENSSL_SRTP
+#if defined(HAVE_OPENSSL) && (OPENSSL_VERSION_NUMBER >= 0x10001000L) && !defined(OPENSSL_NO_SRTP)
                                if (rtp->rtcp->dtls.ssl && rtp->rtcp->dtls.ssl != rtp->dtls.ssl) {
                                        SSL_free(rtp->rtcp->dtls.ssl);
                                }
@@ -5829,7 +7302,7 @@ static void ast_rtp_prop_set(struct ast_rtp_instance *instance, enum ast_rtp_pro
                                if (rtp->rtcp->s > -1 && rtp->rtcp->s != rtp->s) {
                                        close(rtp->rtcp->s);
                                }
-#ifdef HAVE_OPENSSL_SRTP
+#if defined(HAVE_OPENSSL) && (OPENSSL_VERSION_NUMBER >= 0x10001000L) && !defined(OPENSSL_NO_SRTP)
                                ao2_unlock(instance);
                                dtls_srtp_stop_timeout_timer(instance, rtp, 1);
                                ao2_lock(instance);
@@ -5845,6 +7318,11 @@ static void ast_rtp_prop_set(struct ast_rtp_instance *instance, enum ast_rtp_pro
                }
        } else if (property == AST_RTP_PROPERTY_ASYMMETRIC_CODEC) {
                rtp->asymmetric_codec = value;
+       } else if (property == AST_RTP_PROPERTY_RETRANS_SEND) {
+               rtp->send_buffer = ast_data_buffer_alloc(ast_free_ptr, DEFAULT_RTP_SEND_BUFFER_SIZE);
+       } else if (property == AST_RTP_PROPERTY_RETRANS_RECV) {
+               rtp->recv_buffer = ast_data_buffer_alloc(ast_free_ptr, DEFAULT_RTP_RECV_BUFFER_SIZE);
+               AST_VECTOR_INIT(&rtp->missing_seqno, 0);
        }
 }
 
@@ -5897,15 +7375,18 @@ static void ast_rtp_remote_address_set(struct ast_rtp_instance *instance, struct
                ast_rtp_instance_set_remote_address(mapping->instance, addr);
        }
 
-       rtp->rxseqno = 0;
+       /* Need to reset the DTMF last sequence number and the timestamp of the last END packet */
+       rtp->last_seqno = 0;
+       rtp->last_end_timestamp = 0;
 
-       if (strictrtp && rtp->strict_rtp_state != STRICT_RTP_OPEN && !ast_sockaddr_isnull(addr) &&
-               ast_sockaddr_cmp(addr, &rtp->strict_rtp_address)) {
+       if (strictrtp && rtp->strict_rtp_state != STRICT_RTP_OPEN
+               && !ast_sockaddr_isnull(addr) && ast_sockaddr_cmp(addr, &rtp->strict_rtp_address)) {
                /* We only need to learn a new strict source address if we've been told the source is
                 * changing to something different.
                 */
-               rtp->strict_rtp_state = STRICT_RTP_LEARN;
-               rtp_learning_seq_init(&rtp->rtp_source_learn, rtp->seqno);
+               ast_verb(4, "%p -- Strict RTP learning after remote address set to: %s\n",
+                       rtp, ast_sockaddr_stringify(addr));
+               rtp_learning_start(rtp);
        }
 }
 
@@ -5922,7 +7403,9 @@ static int red_write(const void *data)
        struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
 
        ao2_lock(instance);
-       ast_rtp_write(instance, &rtp->red->t140);
+       if (rtp->red->t140.datalen > 0) {
+               ast_rtp_write(instance, &rtp->red->t140);
+       }
        ao2_unlock(instance);
 
        return 1;
@@ -5965,9 +7448,29 @@ static int rtp_red_init(struct ast_rtp_instance *instance, int buffer_time, int
 static int rtp_red_buffer(struct ast_rtp_instance *instance, struct ast_frame *frame)
 {
        struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
+       struct rtp_red *red = rtp->red;
+
+       if (!red) {
+               return 0;
+       }
+
+       if (frame->datalen > 0) {
+               if (red->t140.datalen > 0) {
+                       const unsigned char *primary = red->buf_data;
+
+                       /* There is something already in the T.140 buffer */
+                       if (primary[0] == 0x08 || primary[0] == 0x0a || primary[0] == 0x0d) {
+                               /* Flush the previous T.140 packet if it is a command */
+                               ast_rtp_write(instance, &rtp->red->t140);
+                       } else {
+                               primary = frame->data.ptr;
+                               if (primary[0] == 0x08 || primary[0] == 0x0a || primary[0] == 0x0d) {
+                                       /* Flush the previous T.140 packet if we are buffering a command now */
+                                       ast_rtp_write(instance, &rtp->red->t140);
+                               }
+                       }
+               }
 
-       if (frame->datalen > -1) {
-               struct rtp_red *red = rtp->red;
                memcpy(&red->buf_data[red->t140.datalen], frame->data.ptr, frame->datalen);
                red->t140.datalen += frame->datalen;
                red->t140.ts = frame->ts;
@@ -5982,7 +7485,11 @@ static int ast_rtp_local_bridge(struct ast_rtp_instance *instance0, struct ast_r
        struct ast_rtp *rtp = ast_rtp_instance_get_data(instance0);
 
        ao2_lock(instance0);
-       ast_set_flag(rtp, FLAG_NEED_MARKER_BIT);
+       ast_set_flag(rtp, FLAG_NEED_MARKER_BIT | FLAG_REQ_LOCAL_BRIDGE_BIT);
+       if (rtp->smoother) {
+               ast_smoother_free(rtp->smoother);
+               rtp->smoother = NULL;
+       }
        ao2_unlock(instance0);
 
        return 0;
@@ -6078,7 +7585,7 @@ static void ast_rtp_stop(struct ast_rtp_instance *instance)
        struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
        struct ast_sockaddr addr = { {0,} };
 
-#ifdef HAVE_OPENSSL_SRTP
+#if defined(HAVE_OPENSSL) && (OPENSSL_VERSION_NUMBER >= 0x10001000L) && !defined(OPENSSL_NO_SRTP)
        ao2_unlock(instance);
        AST_SCHED_DEL_UNREF(rtp->sched, rtp->rekeyid, ao2_ref(instance, -1));
 
@@ -6189,14 +7696,18 @@ static const char *ast_rtp_get_cname(struct ast_rtp_instance *instance)
        return rtp->cname;
 }
 
+/*! \pre instance is locked */
 static void ast_rtp_set_remote_ssrc(struct ast_rtp_instance *instance, unsigned int ssrc)
 {
        struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
 
-       if (rtp->themssrc == ssrc) {
+       if (rtp->themssrc_valid && rtp->themssrc == ssrc) {
                return;
        }
 
+       rtp->themssrc = ssrc;
+       rtp->themssrc_valid = 1;
+
        /* If this is bundled we need to update the SSRC mapping */
        if (rtp->bundled) {
                struct ast_rtp *bundled_rtp;
@@ -6211,8 +7722,9 @@ static void ast_rtp_set_remote_ssrc(struct ast_rtp_instance *instance, unsigned
                for (index = 0; index < AST_VECTOR_SIZE(&bundled_rtp->ssrc_mapping); ++index) {
                        struct rtp_ssrc_mapping *mapping = AST_VECTOR_GET_ADDR(&bundled_rtp->ssrc_mapping, index);
 
-                       if (mapping->ssrc == rtp->themssrc) {
+                       if (mapping->instance == instance) {
                                mapping->ssrc = ssrc;
+                               mapping->ssrc_valid = 1;
                                break;
                        }
                }
@@ -6221,8 +7733,6 @@ static void ast_rtp_set_remote_ssrc(struct ast_rtp_instance *instance, unsigned
 
                ao2_lock(instance);
        }
-
-       rtp->themssrc = ssrc;
 }
 
 static void ast_rtp_set_stream_num(struct ast_rtp_instance *instance, int stream_num)
@@ -6232,6 +7742,17 @@ static void ast_rtp_set_stream_num(struct ast_rtp_instance *instance, int stream
        rtp->stream_num = stream_num;
 }
 
+static int ast_rtp_extension_enable(struct ast_rtp_instance *instance, enum ast_rtp_extension extension)
+{
+       switch (extension) {
+       case AST_RTP_EXTENSION_ABS_SEND_TIME:
+               return 1;
+       default:
+               return 0;
+       }
+}
+
+/*! \pre child is locked */
 static int ast_rtp_bundle(struct ast_rtp_instance *child, struct ast_rtp_instance *parent)
 {
        struct ast_rtp *child_rtp = ast_rtp_instance_get_data(child);
@@ -6275,6 +7796,7 @@ static int ast_rtp_bundle(struct ast_rtp_instance *child, struct ast_rtp_instanc
        child_rtp->bundled = ao2_bump(parent);
 
        mapping.ssrc = child_rtp->themssrc;
+       mapping.ssrc_valid = child_rtp->themssrc_valid;
        mapping.instance = child;
 
        ao2_unlock(child);
@@ -6283,12 +7805,12 @@ static int ast_rtp_bundle(struct ast_rtp_instance *child, struct ast_rtp_instanc
 
        AST_VECTOR_APPEND(&parent_rtp->ssrc_mapping, mapping);
 
-#ifdef HAVE_OPENSSL_SRTP
+#if defined(HAVE_OPENSSL) && (OPENSSL_VERSION_NUMBER >= 0x10001000L) && !defined(OPENSSL_NO_SRTP)
        /* If DTLS-SRTP is already in use then add the local SSRC to it, otherwise it will get added once DTLS
         * negotiation has been completed.
         */
        if (parent_rtp->dtls.connection == AST_RTP_DTLS_CONNECTION_EXISTING) {
-               dtls_srtp_add_local_ssrc(parent_rtp, ast_rtp_instance_get_srtp(parent, 0), parent, 0, child_rtp->ssrc, 0);
+               dtls_srtp_add_local_ssrc(parent_rtp, parent, 0, child_rtp->ssrc, 0);
        }
 #endif
 
@@ -6304,7 +7826,7 @@ static int ast_rtp_bundle(struct ast_rtp_instance *child, struct ast_rtp_instanc
        return 0;
 }
 
-#ifdef HAVE_OPENSSL_SRTP
+#if defined(HAVE_OPENSSL) && (OPENSSL_VERSION_NUMBER >= 0x10001000L) && !defined(OPENSSL_NO_SRTP)
 /*! \pre instance is locked */
 static int ast_rtp_activate(struct ast_rtp_instance *instance)
 {
@@ -6538,11 +8060,17 @@ static int rtp_reload(int reload)
                return 0;
        }
 
+#ifdef SO_NO_CHECK
+       nochecksums = 0;
+#endif
+
        rtpstart = DEFAULT_RTP_START;
        rtpend = DEFAULT_RTP_END;
+       rtcpinterval = RTCP_DEFAULT_INTERVALMS;
        dtmftimeout = DEFAULT_DTMF_TIMEOUT;
        strictrtp = DEFAULT_STRICT_RTP;
        learning_min_sequential = DEFAULT_LEARNING_MIN_SEQUENTIAL;
+       learning_min_duration = DEFAULT_LEARNING_MIN_DURATION;
 
        /** This resource is not "reloaded" so much as unloaded and loaded again.
         * In the case of the TURN related variables, the memory referenced by a
@@ -6604,13 +8132,21 @@ static int rtp_reload(int reload)
                };
        }
        if ((s = ast_variable_retrieve(cfg, "general", "strictrtp"))) {
-               strictrtp = ast_true(s);
+               if (ast_true(s)) {
+                       strictrtp = STRICT_RTP_YES;
+               } else if (!strcasecmp(s, "seqno")) {
+                       strictrtp = STRICT_RTP_SEQNO;
+               } else {
+                       strictrtp = STRICT_RTP_NO;
+               }
        }
        if ((s = ast_variable_retrieve(cfg, "general", "probation"))) {
-               if ((sscanf(s, "%d", &learning_min_sequential) <= 0) || learning_min_sequential <= 0) {
+               if ((sscanf(s, "%d", &learning_min_sequential) != 1) || learning_min_sequential <= 1) {
                        ast_log(LOG_WARNING, "Value for 'probation' could not be read, using default of '%d' instead\n",
                                DEFAULT_LEARNING_MIN_SEQUENTIAL);
+                       learning_min_sequential = DEFAULT_LEARNING_MIN_SEQUENTIAL;
                }
+               learning_min_duration = CALC_LEARNING_MIN_DURATION(learning_min_sequential);
        }
 #ifdef HAVE_PJPROJECT
        if ((s = ast_variable_retrieve(cfg, "general", "icesupport"))) {
@@ -6706,7 +8242,7 @@ static void rtp_terminate_pjproject(void)
                pj_thread_destroy(timer_thread);
        }
 
-       pj_caching_pool_destroy(&cachingpool);
+       ast_pjproject_caching_pool_destroy(&cachingpool);
        pj_shutdown();
 }
 #endif
@@ -6731,7 +8267,7 @@ static int load_module(void)
                return AST_MODULE_LOAD_DECLINE;
        }
 
-       pj_caching_pool_init(&cachingpool, &pj_pool_factory_default_policy, 0);
+       ast_pjproject_caching_pool_init(&cachingpool, &pj_pool_factory_default_policy, 0);
 
        pool = pj_pool_create(&cachingpool.factory, "timer", 512, 512, NULL);
 
@@ -6794,4 +8330,7 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Asterisk RTP Stack",
        .unload = unload_module,
        .reload = reload_module,
        .load_pri = AST_MODPRI_CHANNEL_DEPEND,
+#ifdef HAVE_PJPROJECT
+       .requires = "res_pjproject",
+#endif
 );