res_pjsip: Add option to force G.726 to be treated as AAL2 packed.
[asterisk/asterisk.git] / channels / chan_iax2.c
index e27cc14..da6bec7 100644 (file)
@@ -58,7 +58,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+ASTERISK_REGISTER_FILE()
 
 #include <sys/mman.h>
 #include <dirent.h>
@@ -116,11 +116,17 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/stasis.h"
 #include "asterisk/stasis_system.h"
 #include "asterisk/stasis_channels.h"
+#include "asterisk/format_cache.h"
+#include "asterisk/format_compatibility.h"
+#include "asterisk/format_cap.h"
 
 #include "iax2/include/iax2.h"
 #include "iax2/include/firmware.h"
 #include "iax2/include/parser.h"
 #include "iax2/include/provision.h"
+#include "iax2/include/codec_pref.h"
+#include "iax2/include/format_compatibility.h"
+
 #include "jitterbuf.h"
 
 /*** DOCUMENTATION
@@ -279,7 +285,7 @@ static int nochecksums = 0;
 /* Sample over last 100 units to determine historic jitter */
 #define GAMMA (0.01)
 
-static struct ast_codec_pref prefs;
+static struct iax2_codec_pref prefs_global;
 
 static const char tdesc[] = "Inter Asterisk eXchange Driver (Ver 2)";
 
@@ -347,22 +353,22 @@ static int (*iax2_regfunk)(const char *username, int onoff) = NULL;
 #define IAX_CAPABILITY_FULLBANDWIDTH   0xFFFF
 /* T1, maybe ISDN */
 #define IAX_CAPABILITY_MEDBANDWIDTH (IAX_CAPABILITY_FULLBANDWIDTH & \
-                     ~ast_format_id_to_old_bitfield(AST_FORMAT_SLINEAR) &      \
-                     ~ast_format_id_to_old_bitfield(AST_FORMAT_SLINEAR16) &    \
-                     ~ast_format_id_to_old_bitfield(AST_FORMAT_SIREN7) &       \
-                     ~ast_format_id_to_old_bitfield(AST_FORMAT_SIREN14) &      \
-                     ~ast_format_id_to_old_bitfield(AST_FORMAT_G719) &         \
-                     ~ast_format_id_to_old_bitfield(AST_FORMAT_ULAW) &         \
-                     ~ast_format_id_to_old_bitfield(AST_FORMAT_ALAW) &         \
-                     ~ast_format_id_to_old_bitfield(AST_FORMAT_G722))
+                     ~AST_FORMAT_SLIN &      \
+                     ~AST_FORMAT_SLIN16 &    \
+                     ~AST_FORMAT_SIREN7 &       \
+                     ~AST_FORMAT_SIREN14 &      \
+                     ~AST_FORMAT_G719 &         \
+                     ~AST_FORMAT_ULAW &         \
+                     ~AST_FORMAT_ALAW &         \
+                     ~AST_FORMAT_G722)
 /* A modem */
 #define IAX_CAPABILITY_LOWBANDWIDTH (IAX_CAPABILITY_MEDBANDWIDTH & \
-                     ~ast_format_id_to_old_bitfield(AST_FORMAT_G726) &         \
-                     ~ast_format_id_to_old_bitfield(AST_FORMAT_G726_AAL2) &    \
-                     ~ast_format_id_to_old_bitfield(AST_FORMAT_ADPCM))
+                     ~AST_FORMAT_G726 &         \
+                     ~AST_FORMAT_G726_AAL2 &    \
+                     ~AST_FORMAT_ADPCM)
 
 #define IAX_CAPABILITY_LOWFREE      (IAX_CAPABILITY_LOWBANDWIDTH & \
-                     ~ast_format_id_to_old_bitfield(AST_FORMAT_G723_1))
+                     ~AST_FORMAT_G723)
 
 
 #define DEFAULT_MAXMS          2000            /* Must be faster than 2 seconds by default */
@@ -381,7 +387,7 @@ static int (*iax2_regfunk)(const char *username, int onoff) = NULL;
                        break; \
                \
                for (idx = 0; idx < 16; idx++) \
-                       sprintf(digest + (idx << 1), "%2.2x", (unsigned char) key[idx]); \
+                       sprintf(digest + (idx << 1), "%02hhx", (unsigned char) key[idx]); \
                \
                ast_log(LOG_NOTICE, msg " IAX_COMMAND_RTKEY to rotate key to '%s'\n", digest); \
        } while(0)
@@ -389,8 +395,6 @@ static int (*iax2_regfunk)(const char *username, int onoff) = NULL;
 static struct io_context *io;
 static struct ast_sched_context *sched;
 
-#define DONT_RESCHEDULE -2
-
 static iax2_format iax2_capability = IAX_CAPABILITY_FULLBANDWIDTH;
 
 static int iaxdebug = 0;
@@ -429,38 +433,37 @@ struct iax2_context {
 };
 
 
-#define        IAX_HASCALLERID         (uint64_t)(1 << 0)    /*!< CallerID has been specified */
-#define IAX_DELME               (uint64_t)(1 << 1)    /*!< Needs to be deleted */
-#define IAX_TEMPONLY            (uint64_t)(1 << 2)    /*!< Temporary (realtime) */
-#define IAX_TRUNK               (uint64_t)(1 << 3)    /*!< Treat as a trunk */
-#define IAX_NOTRANSFER          (uint64_t)(1 << 4)    /*!< Don't native bridge */
-#define IAX_USEJITTERBUF        (uint64_t)(1 << 5)    /*!< Use jitter buffer */
-#define IAX_DYNAMIC             (uint64_t)(1 << 6)    /*!< dynamic peer */
-#define IAX_SENDANI             (uint64_t)(1 << 7)    /*!< Send ANI along with CallerID */
-#define IAX_RTSAVE_SYSNAME      (uint64_t)(1 << 8)    /*!< Save Systname on Realtime Updates */
-#define IAX_ALREADYGONE         (uint64_t)(1 << 9)    /*!< Already disconnected */
-#define IAX_PROVISION           (uint64_t)(1 << 10)   /*!< This is a provisioning request */
-#define IAX_QUELCH              (uint64_t)(1 << 11)   /*!< Whether or not we quelch audio */
-#define IAX_ENCRYPTED           (uint64_t)(1 << 12)   /*!< Whether we should assume encrypted tx/rx */
-#define IAX_KEYPOPULATED        (uint64_t)(1 << 13)   /*!< Whether we have a key populated */
-#define IAX_CODEC_USER_FIRST    (uint64_t)(1 << 14)   /*!< are we willing to let the other guy choose the codec? */
-#define IAX_CODEC_NOPREFS       (uint64_t)(1 << 15)   /*!< Force old behaviour by turning off prefs */
-#define IAX_CODEC_NOCAP         (uint64_t)(1 << 16)   /*!< only consider requested format and ignore capabilities*/
-#define IAX_RTCACHEFRIENDS      (uint64_t)(1 << 17)   /*!< let realtime stay till your reload */
-#define IAX_RTUPDATE            (uint64_t)(1 << 18)   /*!< Send a realtime update */
-#define IAX_RTAUTOCLEAR         (uint64_t)(1 << 19)   /*!< erase me on expire */
-#define IAX_FORCEJITTERBUF      (uint64_t)(1 << 20)   /*!< Force jitterbuffer, even when bridged to a channel that can take jitter */
-#define IAX_RTIGNOREREGEXPIRE   (uint64_t)(1 << 21)   /*!< When using realtime, ignore registration expiration */
-#define IAX_TRUNKTIMESTAMPS     (uint64_t)(1 << 22)   /*!< Send trunk timestamps */
-#define IAX_TRANSFERMEDIA       (uint64_t)(1 << 23)   /*!< When doing IAX2 transfers, transfer media only */
-#define IAX_MAXAUTHREQ          (uint64_t)(1 << 24)   /*!< Maximum outstanding AUTHREQ restriction is in place */
-#define IAX_DELAYPBXSTART       (uint64_t)(1 << 25)   /*!< Don't start a PBX on the channel until the peer sends us a response, so that we've achieved a three-way handshake with them before sending voice or anything else */
-#define IAX_ALLOWFWDOWNLOAD     (uint64_t)(1 << 26)   /*!< Allow the FWDOWNL command? */
-#define IAX_IMMEDIATE           (uint64_t)(1 << 27)   /*!< Allow immediate off-hook to extension s */
-#define IAX_SENDCONNECTEDLINE   (uint64_t)(1 << 28)   /*!< Allow sending of connected line updates */
-#define IAX_RECVCONNECTEDLINE   (uint64_t)(1 << 29)   /*!< Allow receiving of connected line updates */
-#define IAX_FORCE_ENCRYPT       (uint64_t)(1 << 30)   /*!< Forces call encryption, if encryption not possible hangup */
-#define IAX_SHRINKCALLERID      (uint64_t)(1 << 31)   /*!< Turn on and off caller id shrinking */
+#define IAX_HASCALLERID         (uint64_t)(1LLU << 0)    /*!< CallerID has been specified */
+#define IAX_DELME               (uint64_t)(1LLU << 1)    /*!< Needs to be deleted */
+#define IAX_TEMPONLY            (uint64_t)(1LLU << 2)    /*!< Temporary (realtime) */
+#define IAX_TRUNK               (uint64_t)(1LLU << 3)    /*!< Treat as a trunk */
+#define IAX_NOTRANSFER          (uint64_t)(1LLU << 4)    /*!< Don't native bridge */
+#define IAX_USEJITTERBUF        (uint64_t)(1LLU << 5)    /*!< Use jitter buffer */
+#define IAX_DYNAMIC             (uint64_t)(1LLU << 6)    /*!< dynamic peer */
+#define IAX_SENDANI             (uint64_t)(1LLU << 7)    /*!< Send ANI along with CallerID */
+#define IAX_RTSAVE_SYSNAME      (uint64_t)(1LLU << 8)    /*!< Save Systname on Realtime Updates */
+#define IAX_ALREADYGONE         (uint64_t)(1LLU << 9)    /*!< Already disconnected */
+#define IAX_PROVISION           (uint64_t)(1LLU << 10)   /*!< This is a provisioning request */
+#define IAX_QUELCH              (uint64_t)(1LLU << 11)   /*!< Whether or not we quelch audio */
+#define IAX_ENCRYPTED           (uint64_t)(1LLU << 12)   /*!< Whether we should assume encrypted tx/rx */
+#define IAX_KEYPOPULATED        (uint64_t)(1LLU << 13)   /*!< Whether we have a key populated */
+#define IAX_CODEC_USER_FIRST    (uint64_t)(1LLU << 14)   /*!< are we willing to let the other guy choose the codec? */
+#define IAX_CODEC_NOPREFS       (uint64_t)(1LLU << 15)   /*!< Force old behaviour by turning off prefs */
+#define IAX_CODEC_NOCAP         (uint64_t)(1LLU << 16)   /*!< only consider requested format and ignore capabilities*/
+#define IAX_RTCACHEFRIENDS      (uint64_t)(1LLU << 17)   /*!< let realtime stay till your reload */
+#define IAX_RTUPDATE            (uint64_t)(1LLU << 18)   /*!< Send a realtime update */
+#define IAX_RTAUTOCLEAR         (uint64_t)(1LLU << 19)   /*!< erase me on expire */
+#define IAX_RTIGNOREREGEXPIRE   (uint64_t)(1LLU << 21)   /*!< When using realtime, ignore registration expiration */
+#define IAX_TRUNKTIMESTAMPS     (uint64_t)(1LLU << 22)   /*!< Send trunk timestamps */
+#define IAX_TRANSFERMEDIA       (uint64_t)(1LLU << 23)   /*!< When doing IAX2 transfers, transfer media only */
+#define IAX_MAXAUTHREQ          (uint64_t)(1LLU << 24)   /*!< Maximum outstanding AUTHREQ restriction is in place */
+#define IAX_DELAYPBXSTART       (uint64_t)(1LLU << 25)   /*!< Don't start a PBX on the channel until the peer sends us a response, so that we've achieved a three-way handshake with them before sending voice or anything else */
+#define IAX_ALLOWFWDOWNLOAD     (uint64_t)(1LLU << 26)   /*!< Allow the FWDOWNL command? */
+#define IAX_IMMEDIATE           (uint64_t)(1LLU << 27)   /*!< Allow immediate off-hook to extension s */
+#define IAX_SENDCONNECTEDLINE   (uint64_t)(1LLU << 28)   /*!< Allow sending of connected line updates */
+#define IAX_RECVCONNECTEDLINE   (uint64_t)(1LLU << 29)   /*!< Allow receiving of connected line updates */
+#define IAX_FORCE_ENCRYPT       (uint64_t)(1LLU << 30)   /*!< Forces call encryption, if encryption not possible hangup */
+#define IAX_SHRINKCALLERID      (uint64_t)(1LLU << 31)   /*!< Turn on and off caller id shrinking */
 static int global_rtautoclear = 120;
 
 static int reload_config(int forced_reload);
@@ -503,7 +506,7 @@ struct iax2_user {
        iax2_format capability;
        int maxauthreq; /*!< Maximum allowed outstanding AUTHREQs */
        int curauthreq; /*!< Current number of outstanding AUTHREQs */
-       struct ast_codec_pref prefs;
+       struct iax2_codec_pref prefs;
        struct ast_acl_list *acl;
        struct iax2_context *contexts;
        struct ast_variable *vars;
@@ -532,7 +535,7 @@ struct iax2_peer {
                AST_STRING_FIELD(zonetag);              /*!< Time Zone */
                AST_STRING_FIELD(parkinglot);   /*!< Default parkinglot for device */
        );
-       struct ast_codec_pref prefs;
+       struct iax2_codec_pref prefs;
        struct ast_dnsmgr_entry *dnsmgr;                /*!< DNS refresh manager */
        struct ast_sockaddr addr;
        int formats;
@@ -629,6 +632,8 @@ struct iax2_registry {
        struct ast_sockaddr us;                 /*!< Who the server thinks we are */
        struct ast_dnsmgr_entry *dnsmgr;        /*!< DNS refresh manager */
        AST_LIST_ENTRY(iax2_registry) entry;
+       int port;
+       char hostname[];
 };
 
 static AST_LIST_HEAD_STATIC(registrations, iax2_registry);
@@ -676,7 +681,7 @@ struct chan_iax2_pvt {
        /*! Socket to send/receive on for this call */
        int sockfd;
        /*! ast_callid bound to dialog */
-       struct ast_callid *callid;
+       ast_callid callid;
        /*! Last received voice format */
        iax2_format voiceformat;
        /*! Last received video format */
@@ -708,9 +713,9 @@ struct chan_iax2_pvt {
        /*! Peer Address */
        struct ast_sockaddr addr;
        /*! Actual used codec preferences */
-       struct ast_codec_pref prefs;
+       struct iax2_codec_pref prefs;
        /*! Requested codec preferences */
-       struct ast_codec_pref rprefs;
+       struct iax2_codec_pref rprefs;
        /*! Our call number */
        unsigned short callno;
        /*! Our callno_entry entry */
@@ -857,6 +862,8 @@ struct chan_iax2_pvt {
        int frames_dropped;
        /*! received frame count: (just for stats) */
        int frames_received;
+       /*! Destroying this call initiated. */
+       int destroy_initiated;
        /*! num bytes used for calltoken ie, even an empty ie should contain 2 */
        unsigned char calltoken_ie_len;
        /*! hold all signaling frames from the pbx thread until we have a destination callno */
@@ -911,7 +918,7 @@ static struct ast_taskprocessor *transmit_processor;
 
 static int randomcalltokendata;
 
-static const time_t MAX_CALLTOKEN_DELAY = 10;
+static time_t max_calltoken_delay = 10;
 
 /*!
  * This module will get much higher performance when doing a lot of
@@ -1100,30 +1107,22 @@ static void signal_condition(ast_mutex_t *lock, ast_cond_t *cond)
  */
 static struct chan_iax2_pvt *iaxs[IAX_MAX_CALLS];
 
-static struct ast_callid *iax_pvt_callid_get(int callno)
+static ast_callid iax_pvt_callid_get(int callno)
 {
-       if (iaxs[callno]->callid) {
-               return ast_callid_ref(iaxs[callno]->callid);
-       }
-       return NULL;
+       return iaxs[callno]->callid;
 }
 
-static void iax_pvt_callid_set(int callno, struct ast_callid *callid)
+static void iax_pvt_callid_set(int callno, ast_callid callid)
 {
-       if (iaxs[callno]->callid) {
-               ast_callid_unref(iaxs[callno]->callid);
-       }
-       ast_callid_ref(callid);
        iaxs[callno]->callid = callid;
 }
 
 static void iax_pvt_callid_new(int callno)
 {
-       struct ast_callid *callid = ast_create_callid();
+       ast_callid callid = ast_create_callid();
        char buffer[AST_CALLID_BUFFER_LENGTH];
        ast_callid_strnprint(buffer, sizeof(buffer), callid);
        iax_pvt_callid_set(callno, callid);
-       ast_callid_unref(callid);
 }
 
 /*!
@@ -1253,7 +1252,7 @@ static int send_command_final(struct chan_iax2_pvt *, char, int, unsigned int, c
 static int send_command_immediate(struct chan_iax2_pvt *, char, int, unsigned int, const unsigned char *, int, int);
 static int send_command_locked(unsigned short callno, char, int, unsigned int, const unsigned char *, int, int);
 static int send_command_transfer(struct chan_iax2_pvt *, char, int, unsigned int, const unsigned char *, int);
-static struct ast_channel *iax2_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause);
+static struct ast_channel *iax2_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause);
 static struct ast_frame *iax2_read(struct ast_channel *c);
 static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, struct ast_variable *alt, int temponly);
 static struct iax2_user *build_user(const char *name, struct ast_variable *v, struct ast_variable *alt, int temponly);
@@ -1332,11 +1331,103 @@ static void iax2_lock_owner(int callno)
        }
 }
 
-static void mwi_event_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
+/*!
+ * \internal
+ * \brief Check if a control subtype is allowed on the wire.
+ *
+ * \param subtype Control frame subtype to check if allowed to/from the wire.
+ *
+ * \retval non-zero if allowed.
+ */
+static int iax2_is_control_frame_allowed(int subtype)
 {
-       /* The MWI subscriptions exist just so the core knows we care about those
-        * mailboxes.  However, we just grab the events out of the cache when it
-        * is time to send MWI, since it is only sent with a REGACK. */
+       enum ast_control_frame_type control = subtype;
+       int is_allowed;
+
+       /*
+        * Note: If we compare the enumeration type, which does not have any
+        * negative constants, the compiler may optimize this code away.
+        * Therefore, we must perform an integer comparison here.
+        */
+       if (subtype == -1) {
+               return -1;
+       }
+
+       /* Default to not allowing control frames to pass. */
+       is_allowed = 0;
+
+       /*
+        * The switch default is not present in order to take advantage
+        * of the compiler complaining of a missing enum case.
+        */
+       switch (control) {
+       /*
+        * These control frames make sense to send/receive across the link.
+        */
+       case AST_CONTROL_HANGUP:
+       case AST_CONTROL_RING:
+       case AST_CONTROL_RINGING:
+       case AST_CONTROL_ANSWER:
+       case AST_CONTROL_BUSY:
+       case AST_CONTROL_TAKEOFFHOOK:
+       case AST_CONTROL_OFFHOOK:
+       case AST_CONTROL_CONGESTION:
+       case AST_CONTROL_FLASH:
+       case AST_CONTROL_WINK:
+       case AST_CONTROL_OPTION:
+       case AST_CONTROL_RADIO_KEY:
+       case AST_CONTROL_RADIO_UNKEY:
+       case AST_CONTROL_PROGRESS:
+       case AST_CONTROL_PROCEEDING:
+       case AST_CONTROL_HOLD:
+       case AST_CONTROL_UNHOLD:
+       case AST_CONTROL_VIDUPDATE:
+       case AST_CONTROL_CONNECTED_LINE:
+       case AST_CONTROL_REDIRECTING:
+       case AST_CONTROL_T38_PARAMETERS:
+       case AST_CONTROL_AOC:
+       case AST_CONTROL_INCOMPLETE:
+       case AST_CONTROL_MCID:
+               is_allowed = -1;
+               break;
+
+       /*
+        * These control frames do not make sense to send/receive across the link.
+        */
+       case _XXX_AST_CONTROL_T38:
+               /* The control value is deprecated in favor of AST_CONTROL_T38_PARAMETERS. */
+       case AST_CONTROL_SRCUPDATE:
+               /* Across an IAX link the source is still the same. */
+       case AST_CONTROL_TRANSFER:
+               /* A success/fail status report from calling ast_transfer() on this machine. */
+       case AST_CONTROL_CC:
+               /* The payload contains pointers that are valid for the sending machine only. */
+       case AST_CONTROL_SRCCHANGE:
+               /* Across an IAX link the source is still the same. */
+       case AST_CONTROL_READ_ACTION:
+               /* The action can only be done by the sending machine. */
+       case AST_CONTROL_END_OF_Q:
+               /* This frame would cause the call to unexpectedly hangup. */
+       case AST_CONTROL_UPDATE_RTP_PEER:
+               /* Only meaningful across a bridge on this machine for direct-media exchange. */
+       case AST_CONTROL_PVT_CAUSE_CODE:
+               /* Intended only for the sending machine's local channel structure. */
+       case AST_CONTROL_MASQUERADE_NOTIFY:
+               /* Intended only for masquerades when calling ast_indicate_data(). */
+       case AST_CONTROL_STREAM_STOP:
+       case AST_CONTROL_STREAM_SUSPEND:
+       case AST_CONTROL_STREAM_RESTART:
+       case AST_CONTROL_STREAM_REVERSE:
+       case AST_CONTROL_STREAM_FORWARD:
+               /* None of these playback stream control frames should go across the link. */
+       case AST_CONTROL_RECORD_CANCEL:
+       case AST_CONTROL_RECORD_STOP:
+       case AST_CONTROL_RECORD_SUSPEND:
+       case AST_CONTROL_RECORD_MUTE:
+               /* None of these media recording control frames should go across the link. */
+               break;
+       }
+       return is_allowed;
 }
 
 static void network_change_stasis_subscribe(void)
@@ -1573,23 +1664,48 @@ static int iax2_sched_add(struct ast_sched_context *con, int when,
        return ast_sched_add(con, when, callback, data);
 }
 
+/*
+ * \brief Acquire the iaxsl[callno] if call exists and not having ongoing hangup.
+ * \param callno Call number to lock.
+ * \return 0 If call disappeared or has ongoing hangup procedure. 1 If call found and mutex is locked.
+ */
+static int iax2_lock_callno_unless_destroyed(int callno)
+{
+       ast_mutex_lock(&iaxsl[callno]);
+
+       /* We acquired the lock; but the call was already destroyed (we came after full hang up procedures)
+        * or destroy initiated (in middle of hang up procedure. */
+       if (!iaxs[callno] || iaxs[callno]->destroy_initiated) {
+               ast_debug(3, "I wanted to lock callno %d, but it is dead or going to die.\n", callno);
+               ast_mutex_unlock(&iaxsl[callno]);
+               return 0;
+       }
+
+       /* Lock acquired, and callno is alive and kicking. */
+       return 1;
+}
+
 static int send_ping(const void *data);
 
 static void __send_ping(const void *data)
 {
-       int callno = (long) data;
+       int callno = PTR_TO_CALLNO(data);
 
-       ast_mutex_lock(&iaxsl[callno]);
+       if (iax2_lock_callno_unless_destroyed(callno) == 0) {
+               ast_debug(3, "Hangup initiated on call %d, aborting __send_ping\n", callno);
+               return;
+       }
 
-       if (iaxs[callno]) {
-               if (iaxs[callno]->peercallno) {
-                       send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_PING, 0, NULL, 0, -1);
-                       if (iaxs[callno]->pingid != DONT_RESCHEDULE) {
-                               iaxs[callno]->pingid = iax2_sched_add(sched, ping_time * 1000, send_ping, data);
-                       }
-               }
-       } else {
-               ast_debug(1, "I was supposed to send a PING with callno %d, but no such call exists.\n", callno);
+       /* Mark pingid as invalid scheduler id. */
+       iaxs[callno]->pingid = -1;
+
+       /* callno is now locked. */
+       if (iaxs[callno]->peercallno) {
+               /* Send PING packet. */
+               send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_PING, 0, NULL, 0, -1);
+
+               /* Schedule sending next ping. */
+               iaxs[callno]->pingid = iax2_sched_add(sched, ping_time * 1000, send_ping, data);
        }
 
        ast_mutex_unlock(&iaxsl[callno]);
@@ -1597,13 +1713,6 @@ static void __send_ping(const void *data)
 
 static int send_ping(const void *data)
 {
-       int callno = (long) data;
-       ast_mutex_lock(&iaxsl[callno]);
-       if (iaxs[callno] && iaxs[callno]->pingid != DONT_RESCHEDULE) {
-               iaxs[callno]->pingid = -1;
-       }
-       ast_mutex_unlock(&iaxsl[callno]);
-
 #ifdef SCHED_MULTITHREADED
        if (schedule_action(__send_ping, data))
 #endif
@@ -1644,19 +1753,23 @@ static int send_lagrq(const void *data);
 
 static void __send_lagrq(const void *data)
 {
-       int callno = (long) data;
+       int callno = PTR_TO_CALLNO(data);
 
-       ast_mutex_lock(&iaxsl[callno]);
+       if (iax2_lock_callno_unless_destroyed(callno) == 0) {
+               ast_debug(3, "Hangup initiated on call %d, aborting __send_lagrq\n", callno);
+               return;
+       }
 
-       if (iaxs[callno]) {
-               if (iaxs[callno]->peercallno) {
-                       send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_LAGRQ, 0, NULL, 0, -1);
-                       if (iaxs[callno]->lagid != DONT_RESCHEDULE) {
-                               iaxs[callno]->lagid = iax2_sched_add(sched, lagrq_time * 1000, send_lagrq, data);
-                       }
-               }
-       } else {
-               ast_debug(1, "I was supposed to send a LAGRQ with callno %d, but no such call exists.\n", callno);
+       /* Mark lagid as invalid scheduler id. */
+       iaxs[callno]->lagid = -1;
+
+       /* callno is now locked. */
+       if (iaxs[callno]->peercallno) {
+               /* Send LAGRQ packet. */
+               send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_LAGRQ, 0, NULL, 0, -1);
+
+               /* Schedule sending next lagrq. */
+               iaxs[callno]->lagid = iax2_sched_add(sched, lagrq_time * 1000, send_lagrq, data);
        }
 
        ast_mutex_unlock(&iaxsl[callno]);
@@ -1664,13 +1777,6 @@ static void __send_lagrq(const void *data)
 
 static int send_lagrq(const void *data)
 {
-       int callno = (long) data;
-       ast_mutex_lock(&iaxsl[callno]);
-       if (iaxs[callno] && iaxs[callno]->lagid != DONT_RESCHEDULE) {
-               iaxs[callno]->lagid = -1;
-       }
-       ast_mutex_unlock(&iaxsl[callno]);
-
 #ifdef SCHED_MULTITHREADED
        if (schedule_action(__send_lagrq, data))
 #endif
@@ -1712,73 +1818,114 @@ static iax2_format uncompress_subclass(unsigned char csub)
                return csub;
 }
 
-static iax2_format iax2_codec_choose(struct ast_codec_pref *pref, iax2_format formats, int find_best)
+static struct ast_format *codec_choose_from_prefs(struct iax2_codec_pref *pref, struct ast_format_cap *cap)
 {
-       struct ast_format_cap *cap;
-       struct ast_format tmpfmt;
-       iax2_format format = 0;
-       if ((cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK))) {
-               ast_format_clear(&tmpfmt);
-               ast_format_cap_from_old_bitfield(cap, formats);
-               ast_codec_choose(pref, cap, find_best, &tmpfmt);
-               format = ast_format_to_old_bitfield(&tmpfmt);
-               cap = ast_format_cap_destroy(cap);
+       int x;
+       struct ast_format *found_format = NULL;
+
+       for (x = 0; x < ARRAY_LEN(pref->order); ++x) {
+               struct ast_format *pref_format;
+               uint64_t pref_bitfield;
+
+               pref_bitfield = iax2_codec_pref_order_value_to_format_bitfield(pref->order[x]);
+               if (!pref_bitfield) {
+                       break;
+               }
+
+               pref_format = ast_format_compatibility_bitfield2format(pref_bitfield);
+               if (!pref_format) {
+                       /* The bitfield is not associated with any format. */
+                       continue;
+               }
+               found_format = ast_format_cap_get_compatible_format(cap, pref_format);
+               if (found_format) {
+                       break;
+               }
        }
 
-       return format;
+       if (found_format && (ast_format_get_type(found_format) == AST_MEDIA_TYPE_AUDIO)) {
+               return found_format;
+       }
+
+       ast_debug(4, "Could not find preferred codec - Returning zero codec.\n");
+       ao2_cleanup(found_format);
+       return NULL;
 }
 
-static iax2_format iax2_best_codec(iax2_format formats)
+static iax2_format iax2_codec_choose(struct iax2_codec_pref *pref, iax2_format formats)
 {
-       struct ast_format_cap *cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK);
-       struct ast_format tmpfmt;
-       if (!cap) {
-               return 0;
+       struct ast_format_cap *cap;
+       struct ast_format *tmpfmt;
+       iax2_format format = 0;
+
+       if ((cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
+               iax2_format_compatibility_bitfield2cap(formats, cap);
+               tmpfmt = codec_choose_from_prefs(pref, cap);
+               if (!tmpfmt) {
+                       ao2_ref(cap, -1);
+                       return 0;
+               }
+
+               format = ast_format_compatibility_format2bitfield(tmpfmt);
+               ao2_ref(tmpfmt, -1);
+               ao2_ref(cap, -1);
        }
 
-       ast_format_clear(&tmpfmt);
-       ast_format_cap_from_old_bitfield(cap, formats);
-       ast_best_codec(cap, &tmpfmt);
-       cap = ast_format_cap_destroy(cap);
-       return ast_format_to_old_bitfield(&tmpfmt);
+       return format;
 }
 
 const char *iax2_getformatname(iax2_format format)
 {
-       struct ast_format tmpfmt;
-       if (!(ast_format_from_old_bitfield(&tmpfmt, format))) {
+       struct ast_format *tmpfmt;
+
+       tmpfmt = ast_format_compatibility_bitfield2format(format);
+       if (!tmpfmt) {
                return "Unknown";
        }
 
-       return ast_getformatname(&tmpfmt);
+       return ast_format_get_name(tmpfmt);
 }
 
-static char *iax2_getformatname_multiple(char *codec_buf, size_t len, iax2_format format)
+static const char *iax2_getformatname_multiple(iax2_format format, struct ast_str **codec_buf)
 {
-       struct ast_format_cap *cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK);
+       struct ast_format_cap *cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
 
        if (!cap) {
                return "(Nothing)";
        }
-       ast_format_cap_from_old_bitfield(cap, format);
-       ast_getformatname_multiple(codec_buf, len, cap);
-       cap = ast_format_cap_destroy(cap);
+       iax2_format_compatibility_bitfield2cap(format, cap);
+       ast_format_cap_get_names(cap, codec_buf);
+       ao2_ref(cap, -1);
 
-       return codec_buf;
+       return ast_str_buffer(*codec_buf);
 }
 
-static int iax2_parse_allow_disallow(struct ast_codec_pref *pref, iax2_format *formats, const char *list, int allowing)
+static int iax2_parse_allow_disallow(struct iax2_codec_pref *pref, iax2_format *formats, const char *list, int allowing)
 {
-       int res;
-       struct ast_format_cap *cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK);
-       if (!cap) {
+       int res, i;
+       struct ast_format_cap *cap;
+
+       /* We want to add the formats to the cap in the preferred order */
+       cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
+       if (!cap || iax2_codec_pref_to_cap(pref, cap)) {
+               ao2_cleanup(cap);
                return 1;
        }
 
-       ast_format_cap_from_old_bitfield(cap, *formats);
-       res = ast_parse_allow_disallow(pref, cap, list, allowing);
-       *formats = ast_format_cap_to_old_bitfield(cap);
-       cap = ast_format_cap_destroy(cap);
+       res = ast_format_cap_update_by_allow_disallow(cap, list, allowing);
+
+       /* Adjust formats bitfield and pref list to match. */
+       *formats = iax2_format_compatibility_cap2bitfield(cap);
+       iax2_codec_pref_remove_missing(pref, *formats);
+
+       for (i = 0; i < ast_format_cap_count(cap); i++) {
+               struct ast_format *fmt = ast_format_cap_get_format(cap, i);
+
+               iax2_codec_pref_append(pref, fmt, ast_format_cap_get_format_framing(cap, fmt));
+               ao2_ref(fmt, -1);
+       }
+
+       ao2_ref(cap, -1);
 
        return res;
 }
@@ -1786,13 +1933,13 @@ static int iax2_parse_allow_disallow(struct ast_codec_pref *pref, iax2_format *f
 static int iax2_data_add_codecs(struct ast_data *root, const char *node_name, iax2_format formats)
 {
        int res;
-       struct ast_format_cap *cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK);
+       struct ast_format_cap *cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
        if (!cap) {
                return -1;
        }
-       ast_format_cap_from_old_bitfield(cap, formats);
+       iax2_format_compatibility_bitfield2cap(formats, cap);
        res = ast_data_add_codecs(root, node_name, cap);
-       cap = ast_format_cap_destroy(cap);
+       ao2_ref(cap, -1);
        return res;
 }
 
@@ -1875,11 +2022,6 @@ static struct iax2_user *find_user(const char *name)
 {
        return ao2_find(users, name, OBJ_KEY);
 }
-static inline struct iax2_user *user_ref(struct iax2_user *user)
-{
-       ao2_ref(user, +1);
-       return user;
-}
 
 static inline struct iax2_user *user_unref(struct iax2_user *user)
 {
@@ -1918,6 +2060,16 @@ static int iax2_getpeername(struct ast_sockaddr addr, char *host, int len)
        return res;
 }
 
+/* Call AST_SCHED_DEL on a scheduled task if it is found in scheduler. */
+static int iax2_delete_from_sched(const void* data)
+{
+       int sched_id = (int)(long)data;
+
+       AST_SCHED_DEL(sched, sched_id);
+
+       return 0;
+}
+
 /*!\note Assumes the lock on the pvt is already held, when
  * iax2_destroy_helper() is called. */
 static void iax2_destroy_helper(struct chan_iax2_pvt *pvt)
@@ -1934,11 +2086,27 @@ static void iax2_destroy_helper(struct chan_iax2_pvt *pvt)
 
                ast_clear_flag64(pvt, IAX_MAXAUTHREQ);
        }
-       /* No more pings or lagrq's */
-       AST_SCHED_DEL_SPINLOCK(sched, pvt->pingid, &iaxsl[pvt->callno]);
-       pvt->pingid = DONT_RESCHEDULE;
-       AST_SCHED_DEL_SPINLOCK(sched, pvt->lagid, &iaxsl[pvt->callno]);
-       pvt->lagid = DONT_RESCHEDULE;
+
+
+       /* Mark call destroy initiated flag. */
+       pvt->destroy_initiated = 1;
+
+       /*
+        * Schedule deleting the scheduled (but didn't run yet) PINGs or LAGRQs.
+        * Already running tasks will be terminated because of destroy_initiated.
+        *
+        * Don't call AST_SCHED_DEL from this thread for pingid and lagid because
+        * it leads to a deadlock between the scheduler thread callback locking
+        * the callno mutex and this thread which holds the callno mutex one or
+        * more times.  It is better to have another thread delete the scheduled
+        * callbacks which doesn't lock the callno mutex.
+        */
+       iax2_sched_add(sched, 0, iax2_delete_from_sched, (void*)(long)pvt->pingid);
+       iax2_sched_add(sched, 0, iax2_delete_from_sched, (void*)(long)pvt->lagid);
+
+       pvt->pingid = -1;
+       pvt->lagid = -1;
+
        AST_SCHED_DEL(sched, pvt->autoid);
        AST_SCHED_DEL(sched, pvt->authid);
        AST_SCHED_DEL(sched, pvt->initid);
@@ -2057,11 +2225,6 @@ static void pvt_destructor(void *obj)
                jb_destroy(pvt->jb);
                ast_string_field_free_memory(pvt);
        }
-
-       if (pvt->callid) {
-               ast_callid_unref(pvt->callid);
-       }
-
 }
 
 static struct chan_iax2_pvt *new_iax(struct ast_sockaddr *addr, const char *host)
@@ -2079,7 +2242,7 @@ static struct chan_iax2_pvt *new_iax(struct ast_sockaddr *addr, const char *host
                return NULL;
        }
 
-       tmp->prefs = prefs;
+       tmp->prefs = prefs_global;
        tmp->pingid = -1;
        tmp->lagid = -1;
        tmp->autoid = -1;
@@ -2354,7 +2517,7 @@ static int calltoken_required(struct ast_sockaddr *addr, const char *name, int s
                user_unref(user);
        }
 
-       ast_debug(1, "Determining if address %s with username %s requires calltoken validation.  Optional = %d  calltoken_required = %d \n", ast_sockaddr_stringify_addr(addr), name, optional, calltoken_required);
+       ast_debug(1, "Determining if address %s with username %s requires calltoken validation.  Optional = %d  calltoken_required = %u \n", ast_sockaddr_stringify_addr(addr), name, optional, calltoken_required);
        if (((calltoken_required == CALLTOKEN_NO) || (calltoken_required == CALLTOKEN_AUTO)) ||
                (optional && (calltoken_required == CALLTOKEN_DEFAULT))) {
                res = 0;
@@ -2871,7 +3034,7 @@ static int create_callno_pools(void)
  * \brief Schedules delayed removal of iax2_pvt call number data
  *
  * \note After MIN_REUSE_TIME has passed for a destroyed iax2_pvt, the callno is
- * avaliable again, and the address from the previous connection must be decremented
+ * available again, and the address from the previous connection must be decremented
  * from the peercnts table.  This function schedules these operations to take place.
  */
 static void sched_delay_remove(struct ast_sockaddr *addr, callno_entry entry)
@@ -3032,7 +3195,7 @@ static int __find_callno(unsigned short callno, unsigned short dcallno, struct a
                        iaxs[x]->pingid = iax2_sched_add(sched, ping_time * 1000, send_ping, (void *)(long)x);
                        iaxs[x]->lagid = iax2_sched_add(sched, lagrq_time * 1000, send_lagrq, (void *)(long)x);
                        iaxs[x]->amaflags = amaflags;
-                       ast_copy_flags64(iaxs[x], &globalflags, IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE | IAX_FORCE_ENCRYPT);
+                       ast_copy_flags64(iaxs[x], &globalflags, IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE | IAX_FORCE_ENCRYPT);
                        ast_string_field_set(iaxs[x], accountcode, accountcode);
                        ast_string_field_set(iaxs[x], mohinterpret, mohinterpret);
                        ast_string_field_set(iaxs[x], mohsuggest, mohsuggest);
@@ -3233,7 +3396,7 @@ static int send_packet(struct iax_frame *f)
 
        /* Called with iaxsl held */
        if (iaxdebug) {
-               ast_debug(3, "Sending %d on %d/%d to %s\n", f->ts, callno, iaxs[callno]->peercallno, ast_sockaddr_stringify(&iaxs[callno]->addr));
+               ast_debug(3, "Sending %u on %d/%d to %s\n", f->ts, callno, iaxs[callno]->peercallno, ast_sockaddr_stringify(&iaxs[callno]->addr));
        }
        if (f->transfer) {
                iax_outputframe(f, NULL, 0, &iaxs[callno]->transfer, f->datalen - sizeof(struct ast_iax2_full_hdr));
@@ -3392,7 +3555,7 @@ static void __attempt_transmit(const void *data)
                                iax2_destroy(callno);
                        } else {
                                if (iaxs[callno]->owner) {
-                                       ast_log(LOG_WARNING, "Max retries exceeded to host %s on %s (type = %d, subclass = %u, ts=%d, seqno=%d)\n",
+                                       ast_log(LOG_WARNING, "Max retries exceeded to host %s on %s (type = %u, subclass = %d, ts=%u, seqno=%d)\n",
                                                ast_sockaddr_stringify_addr(&iaxs[f->callno]->addr),
                                                ast_channel_name(iaxs[f->callno]->owner),
                                                f->af.frametype,
@@ -3640,9 +3803,9 @@ static char *handle_cli_iax2_show_peer(struct ast_cli_entry *e, int cmd, struct
        char status[30];
        char cbuf[256];
        struct iax2_peer *peer;
-       char codec_buf[512];
+       struct ast_str *codec_buf = ast_str_alloca(256);
        struct ast_str *encmethods = ast_str_alloca(256);
-       int x = 0, load_realtime = 0;
+       int load_realtime = 0;
 
        switch (cmd) {
        case CLI_INIT:
@@ -3691,27 +3854,15 @@ static char *handle_cli_iax2_show_peer(struct ast_cli_entry *e, int cmd, struct
                ast_cli(a->fd, "  Addr->IP     : %s Port %s\n",  str_addr ? str_addr : "(Unspecified)", str_port);
                ast_cli(a->fd, "  Defaddr->IP  : %s Port %s\n", str_defaddr, str_defport);
                ast_cli(a->fd, "  Username     : %s\n", peer->username);
-               ast_cli(a->fd, "  Codecs       : ");
-               iax2_getformatname_multiple(codec_buf, sizeof(codec_buf) -1, peer->capability);
-               ast_cli(a->fd, "%s\n", codec_buf);
-
-               ast_cli(a->fd, "  Codec Order  : (");
-               for(x = 0; x < AST_CODEC_PREF_SIZE; x++) {
-                       struct ast_format tmpfmt;
-                       if(!(ast_codec_pref_index(&peer->prefs, x, &tmpfmt)))
-                               break;
-                       ast_cli(a->fd, "%s", ast_getformatname(&tmpfmt));
-                       if(x < 31 && ast_codec_pref_index(&peer->prefs, x+1, &tmpfmt))
-                               ast_cli(a->fd, "|");
-               }
+               ast_cli(a->fd, "  Codecs       : %s\n", iax2_getformatname_multiple(peer->capability, &codec_buf));
 
-               if (!x)
-                       ast_cli(a->fd, "none");
-               ast_cli(a->fd, ")\n");
+               if (iax2_codec_pref_string(&peer->prefs, cbuf, sizeof(cbuf)) < 0) {
+                       strcpy(cbuf, "Error"); /* Safe */
+               }
+               ast_cli(a->fd, "  Codec Order  : %s\n", cbuf);
 
-               ast_cli(a->fd, "  Status       : ");
                peer_status(peer, status, sizeof(status));
-               ast_cli(a->fd, "%s\n",status);
+               ast_cli(a->fd, "  Status       : %s\n", status);
                ast_cli(a->fd, "  Qualify      : every %dms when OK, every %dms when UNREACHABLE (sample smoothing %s)\n", peer->pokefreqok, peer->pokefreqnotok, peer->smoothing ? "On" : "Off");
                ast_cli(a->fd, "\n");
                peer_unref(peer);
@@ -3987,9 +4138,9 @@ static void __get_from_jb(const void *p)
        ms = ast_tvdiff_ms(now, pvt->rxcore);
 
        if(ms >= (next = jb_next(pvt->jb))) {
-               struct ast_format voicefmt;
-               ast_format_from_old_bitfield(&voicefmt, pvt->voiceformat);
-               ret = jb_get(pvt->jb, &frame, ms, ast_codec_interp_len(&voicefmt));
+               struct ast_format *voicefmt;
+               voicefmt = ast_format_compatibility_bitfield2format(pvt->voiceformat);
+               ret = jb_get(pvt->jb, &frame, ms, voicefmt ? ast_format_get_default_ms(voicefmt) : 20);
                switch(ret) {
                case JB_OK:
                        fr = frame.data;
@@ -4003,8 +4154,8 @@ static void __get_from_jb(const void *p)
 
                        /* create an interpolation frame */
                        af.frametype = AST_FRAME_VOICE;
-                       ast_format_copy(&af.subclass.format, &voicefmt);
-                       af.samples  = frame.ms * (ast_format_rate(&voicefmt) / 1000);
+                       af.subclass.format = voicefmt;
+                       af.samples  = frame.ms * (ast_format_get_sample_rate(voicefmt) / 1000);
                        af.src  = "IAX2 JB interpolation";
                        af.delivery = ast_tvadd(pvt->rxcore, ast_samp2tv(next, 1000));
                        af.offset = AST_FRIENDLY_OFFSET;
@@ -4055,8 +4206,6 @@ static int schedule_delivery(struct iax_frame *fr, int updatehistory, int fromtr
        int type, len;
        int ret;
        int needfree = 0;
-       struct ast_channel *owner = NULL;
-       RAII_VAR(struct ast_channel *, bridge, NULL, ast_channel_cleanup);
 
        /*
         * Clear fr->af.data if there is no data in the buffer.  Things
@@ -4085,7 +4234,7 @@ static int schedule_delivery(struct iax_frame *fr, int updatehistory, int fromtr
 
        if(fr->af.frametype == AST_FRAME_VOICE) {
                type = JB_TYPE_VOICE;
-               len = ast_codec_get_samples(&fr->af) / (ast_format_rate(&fr->af.subclass.format) / 1000);
+               len = ast_codec_samples_count(&fr->af) / (ast_format_get_sample_rate(fr->af.subclass.format) / 1000);
        } else if(fr->af.frametype == AST_FRAME_CNG) {
                type = JB_TYPE_SILENCE;
        }
@@ -4097,45 +4246,6 @@ static int schedule_delivery(struct iax_frame *fr, int updatehistory, int fromtr
                return -1;
        }
 
-       iax2_lock_owner(fr->callno);
-       if (!iaxs[fr->callno]) {
-               /* The call dissappeared so discard this frame that we could not send. */
-               iax2_frame_free(fr);
-               return -1;
-       }
-       if ((owner = iaxs[fr->callno]->owner)) {
-               bridge = ast_channel_bridge_peer(owner);
-       }
-
-       /* if the user hasn't requested we force the use of the jitterbuffer, and we're bridged to
-        * a channel that can accept jitter, then flush and suspend the jb, and send this frame straight through */
-       if ( (!ast_test_flag64(iaxs[fr->callno], IAX_FORCEJITTERBUF)) && owner && bridge && (ast_channel_tech(bridge)->properties & AST_CHAN_TP_WANTSJITTER) ) {
-               jb_frame frame;
-
-               ast_channel_unlock(owner);
-
-               /* deliver any frames in the jb */
-               while (jb_getall(iaxs[fr->callno]->jb, &frame) == JB_OK) {
-                       __do_deliver(frame.data);
-                       /* __do_deliver() can make the call disappear */
-                       if (!iaxs[fr->callno])
-                               return -1;
-               }
-
-               jb_reset(iaxs[fr->callno]->jb);
-
-               AST_SCHED_DEL(sched, iaxs[fr->callno]->jbid);
-
-               /* deliver this frame now */
-               if (tsout)
-                       *tsout = fr->ts;
-               __do_deliver(fr);
-               return -1;
-       }
-       if (owner) {
-               ast_channel_unlock(owner);
-       }
-
        /* insert into jitterbuffer */
        /* TODO: Perhaps we could act immediately if it's not droppable and late */
        ret = jb_put(iaxs[fr->callno]->jb, fr, type, len, fr->ts,
@@ -4270,7 +4380,7 @@ static struct iax2_peer *realtime_peer(const char *peername, struct ast_sockaddr
                if (var && !ast_sockaddr_isnull(addr)) {
                        for (tmp = var; tmp; tmp = tmp->next) {
                                if (!strcasecmp(tmp->name, "host")) {
-                                       struct ast_sockaddr *hostaddr;
+                                       struct ast_sockaddr *hostaddr = NULL;
 
                                        if (!ast_sockaddr_resolve(&hostaddr, tmp->value, PARSE_PORT_FORBID, AST_AF_UNSPEC)
                                                || ast_sockaddr_cmp_addr(hostaddr, addr)) {
@@ -4278,6 +4388,7 @@ static struct iax2_peer *realtime_peer(const char *peername, struct ast_sockaddr
                                                ast_variables_destroy(var);
                                                var = NULL;
                                        }
+                                       ast_free(hostaddr);
                                        break;
                                }
                        }
@@ -4392,7 +4503,7 @@ static struct iax2_user *realtime_user(const char *username, struct ast_sockaddr
                if (var) {
                        for (tmp = var; tmp; tmp = tmp->next) {
                                if (!strcasecmp(tmp->name, "host")) {
-                                       struct ast_sockaddr *hostaddr;
+                                       struct ast_sockaddr *hostaddr = NULL;
 
                                        if (!ast_sockaddr_resolve(&hostaddr, tmp->value, PARSE_PORT_FORBID, AST_AF_UNSPEC)
                                                || ast_sockaddr_cmp_addr(hostaddr, addr)) {
@@ -4400,6 +4511,7 @@ static struct iax2_user *realtime_user(const char *username, struct ast_sockaddr
                                                ast_variables_destroy(var);
                                                var = NULL;
                                        }
+                                       ast_free(hostaddr);
                                        break;
                                }
                        }
@@ -4460,6 +4572,7 @@ static void realtime_update_peer(const char *peername, struct ast_sockaddr *sock
 struct create_addr_info {
        iax2_format capability;
        uint64_t flags;
+       struct iax2_codec_pref prefs;
        int maxtime;
        int encmethods;
        int found;
@@ -4469,7 +4582,6 @@ struct create_addr_info {
        char secret[80];
        char outkey[80];
        char timezone[80];
-       char prefs[32];
        char cid_num[80];
        char cid_name[80];
        char context[AST_MAX_CONTEXT];
@@ -4482,7 +4594,6 @@ static int create_addr(const char *peername, struct ast_channel *c, struct ast_s
 {
        struct iax2_peer *peer;
        int res = -1;
-       struct ast_codec_pref ourprefs;
 
        ast_clear_flag64(cai, IAX_SENDANI | IAX_TRUNK);
        cai->sockfd = defaultsockfd;
@@ -4503,18 +4614,24 @@ static int create_addr(const char *peername, struct ast_channel *c, struct ast_s
                }
 
                ast_sockaddr_copy(addr, &peer_addr);
-               /* use global iax prefs for unknown peer/user */
-               /* But move the calling channel's native codec to the top of the preference list */
-               memcpy(&ourprefs, &prefs, sizeof(ourprefs));
+               /*
+                * Use The global iax prefs for unknown peer/user.
+                * However, move the calling channel's native codec to
+                * the top of the preference list.
+                */
+               cai->prefs = prefs_global;
                if (c) {
-                       struct ast_format tmpfmt;
-                       ast_format_cap_iter_start(ast_channel_nativeformats(c));
-                       while (!(ast_format_cap_iter_next(ast_channel_nativeformats(c), &tmpfmt))) {
-                               ast_codec_pref_prepend(&ourprefs, &tmpfmt, 1);
+                       int i;
+
+                       for (i = 0; i < ast_format_cap_count(ast_channel_nativeformats(c)); i++) {
+                               struct ast_format *format = ast_format_cap_get_format(
+                                       ast_channel_nativeformats(c), i);
+                               iax2_codec_pref_prepend(&cai->prefs, format,
+                                       ast_format_cap_get_format_framing(ast_channel_nativeformats(c), format),
+                                       1);
+                               ao2_ref(format, -1);
                        }
-                       ast_format_cap_iter_end(ast_channel_nativeformats(c));
                }
-               ast_codec_pref_convert(&ourprefs, cai->prefs, sizeof(cai->prefs), 1);
                return 0;
        }
 
@@ -4529,24 +4646,26 @@ static int create_addr(const char *peername, struct ast_channel *c, struct ast_s
        if (peer->maxms && ((peer->lastms > peer->maxms) || (peer->lastms < 0)))
                goto return_unref;
 
-       ast_copy_flags64(cai, peer, IAX_SENDANI | IAX_TRUNK | IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE | IAX_FORCE_ENCRYPT);
+       ast_copy_flags64(cai, peer, IAX_SENDANI | IAX_TRUNK | IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE | IAX_FORCE_ENCRYPT);
        cai->maxtime = peer->maxms;
        cai->capability = peer->capability;
        cai->encmethods = peer->encmethods;
        cai->sockfd = peer->sockfd;
        cai->adsi = peer->adsi;
-       memcpy(&ourprefs, &peer->prefs, sizeof(ourprefs));
+       cai->prefs = peer->prefs;
        /* Move the calling channel's native codec to the top of the preference list */
        if (c) {
-               struct ast_format tmpfmt;
-               ast_format_cap_iter_start(ast_channel_nativeformats(c));
-               while (!(ast_format_cap_iter_next(ast_channel_nativeformats(c), &tmpfmt))) {
-                       ast_debug(1, "prepending %s to prefs\n", ast_getformatname(&tmpfmt));
-                       ast_codec_pref_prepend(&ourprefs, &tmpfmt, 1);
+               int i;
+
+               for (i = 0; i < ast_format_cap_count(ast_channel_nativeformats(c)); i++) {
+                       struct ast_format *tmpfmt = ast_format_cap_get_format(
+                               ast_channel_nativeformats(c), i);
+                       iax2_codec_pref_prepend(&cai->prefs, tmpfmt,
+                               ast_format_cap_get_format_framing(ast_channel_nativeformats(c), tmpfmt),
+                               1);
+                       ao2_ref(tmpfmt, -1);
                }
-               ast_format_cap_iter_end(ast_channel_nativeformats(c));
        }
-       ast_codec_pref_convert(&ourprefs, cai->prefs, sizeof(cai->prefs), 1);
        ast_copy_string(cai->context, peer->context, sizeof(cai->context));
        ast_copy_string(cai->peercontext, peer->peercontext, sizeof(cai->peercontext));
        ast_copy_string(cai->username, peer->username, sizeof(cai->username));
@@ -4849,7 +4968,7 @@ static int handle_call_token(struct ast_iax2_full_hdr *fh, struct iax_ies *ies,
                if (strcmp(hash, rec_hash)) {
                        ast_log(LOG_WARNING, "Address %s failed CallToken hash inspection\n", ast_sockaddr_stringify(addr));
                        goto reject; /* received hash does not match ours, reject */
-               } else if ((t < rec_time) || ((t - rec_time) >= MAX_CALLTOKEN_DELAY)) {
+               } else if ((t < rec_time) || ((t - rec_time) >= max_calltoken_delay)) {
                        ast_log(LOG_WARNING, "Too much delay in IAX2 calltoken timestamp from address %s\n", ast_sockaddr_stringify(addr));
                        goto reject; /* too much delay, reject */
                }
@@ -4895,7 +5014,7 @@ reject:
  * password field will be set to NULL.
  *
  * \note The dial string format is:
- *       [username[:password]@]peer[:port][/exten[@@context]][/options]
+ *       [username[:password]@]peer[:port][/exten[@context]][/options]
  */
 static void parse_dial_string(char *data, struct parsed_dial_string *pds)
 {
@@ -4928,9 +5047,10 @@ static void parse_dial_string(char *data, struct parsed_dial_string *pds)
        pds->peer = strsep(&data, ":");
        pds->port = data;
 
-       /* check for a key name wrapped in [] in the secret position, if found,
-          move it to the key field instead
-       */
+       /*
+        * Check for a key name wrapped in [] in the password position.
+        * If found, move it to the key field instead.
+        */
        if (pds->password && (pds->password[0] == '[')) {
                pds->key = ast_strip_quoted(pds->password, "[", "]");
                pds->password = NULL;
@@ -4953,6 +5073,7 @@ static int iax2_call(struct ast_channel *c, const char *dest, int timeout)
        unsigned char osp_block_index;
        unsigned int osp_block_length;
        unsigned char osp_buffer[256];
+       char encoded_prefs[32];
        iax2_format iax2_tmpfmt;
 
        if ((ast_channel_state(c) != AST_STATE_DOWN) && (ast_channel_state(c) != AST_STATE_RESERVED)) {
@@ -5021,7 +5142,8 @@ static int iax2_call(struct ast_channel *c, const char *dest, int timeout)
        }
 
        /* WARNING: this breaks down at 190 bits! */
-       iax_ie_append_str(&ied, IAX_IE_CODEC_PREFS, cai.prefs);
+       iax2_codec_pref_convert(&cai.prefs, encoded_prefs, sizeof(encoded_prefs), 1);
+       iax_ie_append_str(&ied, IAX_IE_CODEC_PREFS, encoded_prefs);
 
        if (l) {
                iax_ie_append_str(&ied, IAX_IE_CALLING_NUMBER, l);
@@ -5084,7 +5206,7 @@ static int iax2_call(struct ast_channel *c, const char *dest, int timeout)
        if (pds.password)
                ast_string_field_set(iaxs[callno], secret, pds.password);
 
-       iax2_tmpfmt = ast_format_cap_to_old_bitfield(ast_channel_nativeformats(c));
+       iax2_tmpfmt = iax2_format_compatibility_cap2bitfield(ast_channel_nativeformats(c));
        iax_ie_append_int(&ied, IAX_IE_FORMAT, (int) iax2_tmpfmt);
        iax_ie_append_versioned_uint64(&ied, IAX_IE_FORMAT2, 0, iax2_tmpfmt);
 
@@ -5327,7 +5449,7 @@ static int iax2_key_rotate(const void *vpvt)
        ast_mutex_lock(&iaxsl[pvt->callno]);
        pvt->keyrotateid = ast_sched_add(sched, 120000 + (ast_random() % 180001), iax2_key_rotate, vpvt);
 
-       snprintf(key, sizeof(key), "%lX", ast_random());
+       snprintf(key, sizeof(key), "%lX", (unsigned long)ast_random());
 
        MD5Init(&md5);
        MD5Update(&md5, (unsigned char *) key, strlen(key));
@@ -5454,11 +5576,13 @@ static enum ast_bridge_result iax2_bridge(struct ast_channel *c0, struct ast_cha
                        return AST_BRIDGE_FAILED_NOWARN;
                }
                if (!(ast_format_cap_identical(ast_channel_nativeformats(c0), ast_channel_nativeformats(c1)))) {
-                       char buf0[256];
-                       char buf1[256];
-                       ast_getformatname_multiple(buf0, sizeof(buf0), ast_channel_nativeformats(c0));
-                       ast_getformatname_multiple(buf1, sizeof(buf1), ast_channel_nativeformats(c1));
-                       ast_verb(3, "Operating with different codecs [%s] [%s] , can't native bridge...\n", buf0, buf1);
+                       struct ast_str *c0_buf = ast_str_alloca(64);
+                       struct ast_str *c1_buf = ast_str_alloca(64);
+
+                       ast_verb(3, "Operating with different codecs [%s] [%s] , can't native bridge...\n",
+                               ast_format_cap_get_names(ast_channel_nativeformats(c0), &c0_buf),
+                               ast_format_cap_get_names(ast_channel_nativeformats(c1), &c1_buf));
+
                        /* Remove from native mode */
                        lock_both(callno0, callno1);
                        if (iaxs[callno0])
@@ -5468,7 +5592,7 @@ static enum ast_bridge_result iax2_bridge(struct ast_channel *c0, struct ast_cha
                        unlock_both(callno0, callno1);
                        return AST_BRIDGE_FAILED_NOWARN;
                }
-               /* check if transfered and if we really want native bridging */
+               /* check if transferred and if we really want native bridging */
                if (!transferstarted && !ast_test_flag64(iaxs[callno0], IAX_NOTRANSFER) && !ast_test_flag64(iaxs[callno1], IAX_NOTRANSFER)) {
                        /* Try the transfer */
                        if (iax2_start_transfer(callno0, callno1, (flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1)) ||
@@ -5615,10 +5739,16 @@ static int iax2_indicate(struct ast_channel *c, int condition, const void *data,
                }
                break;
        case AST_CONTROL_CONNECTED_LINE:
-               if (!ast_test_flag64(pvt, IAX_SENDCONNECTEDLINE))
+       case AST_CONTROL_REDIRECTING:
+               if (!ast_test_flag64(pvt, IAX_SENDCONNECTEDLINE)) {
+                       /* We are not configured to allow sending these updates. */
+                       ast_debug(2, "Callno %d: Config blocked sending control frame %d.\n",
+                               callno, condition);
                        goto done;
+               }
                break;
        case AST_CONTROL_PVT_CAUSE_CODE:
+       case AST_CONTROL_MASQUERADE_NOTIFY:
                res = -1;
                goto done;
        }
@@ -5673,33 +5803,80 @@ static int iax2_getpeertrunk(struct ast_sockaddr addr)
 }
 
 /*! \brief  Create new call, interface with the PBX core */
-static struct ast_channel *ast_iax2_new(int callno, int state, iax2_format capability, const char *linkedid, unsigned int cachable)
+static struct ast_channel *ast_iax2_new(int callno, int state, iax2_format capability,
+       struct iax2_codec_pref *prefs, const struct ast_assigned_ids *assignedids,
+       const struct ast_channel *requestor, unsigned int cachable)
 {
-       struct ast_channel *tmp;
+       struct ast_channel *tmp = NULL;
        struct chan_iax2_pvt *i;
+       struct iax2_peer *peer;
        struct ast_variable *v = NULL;
-       struct ast_format tmpfmt;
-       struct ast_callid *callid;
+       struct ast_format_cap *native;
+       struct ast_format *tmpfmt;
+       ast_callid callid;
+       char *peer_name = NULL;
 
        if (!(i = iaxs[callno])) {
                ast_log(LOG_WARNING, "No IAX2 pvt found for callno '%d' !\n", callno);
                return NULL;
        }
 
-       /* Don't hold call lock */
+       if (!capability) {
+               ast_log(LOG_WARNING, "No formats specified for call to: IAX2/%s-%d\n",
+                       i->host, i->callno);
+               return NULL;
+       }
+       native = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
+       if (!native) {
+               return NULL;
+       }
+       if (iax2_codec_pref_best_bitfield2cap(capability, prefs, native)
+               || !ast_format_cap_count(native)) {
+               ast_log(LOG_WARNING, "No requested formats available for call to: IAX2/%s-%d\n",
+                       i->host, i->callno);
+               ao2_ref(native, -1);
+               return NULL;
+       }
+
+       if (!ast_strlen_zero(i->peer)) {
+               peer_name = ast_strdupa(i->peer);
+       } else if (!ast_strlen_zero(i->host)) {
+               peer_name = ast_strdupa(i->host);
+       }
+
+       /* Don't hold call lock while making a channel or looking up a peer */
        ast_mutex_unlock(&iaxsl[callno]);
-       tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, i->accountcode, i->exten, i->context, linkedid, i->amaflags, "IAX2/%s-%d", i->host, i->callno);
+
+       if (!ast_strlen_zero(peer_name)) {
+               peer = find_peer(peer_name, 1);
+               if (peer && peer->endpoint) {
+                       tmp = ast_channel_alloc_with_endpoint(1, state, i->cid_num, i->cid_name,
+                               i->accountcode, i->exten, i->context, assignedids, requestor,
+                               i->amaflags, peer->endpoint, "IAX2/%s-%d", i->host, i->callno);
+               }
+               ao2_cleanup(peer);
+       }
+
+       if (!tmp) {
+               tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, i->accountcode,
+                       i->exten, i->context, assignedids, requestor, i->amaflags, "IAX2/%s-%d",
+                       i->host, i->callno);
+       }
+
        ast_mutex_lock(&iaxsl[callno]);
        if (i != iaxs[callno]) {
                if (tmp) {
                        /* unlock and relock iaxsl[callno] to preserve locking order */
                        ast_mutex_unlock(&iaxsl[callno]);
+                       ast_channel_unlock(tmp);
                        tmp = ast_channel_release(tmp);
                        ast_mutex_lock(&iaxsl[callno]);
                }
+               ao2_ref(native, -1);
                return NULL;
        }
        if (!tmp) {
+               ao2_ref(native, -1);
                return NULL;
        }
 
@@ -5710,14 +5887,18 @@ static struct ast_channel *ast_iax2_new(int callno, int state, iax2_format capab
        }
 
        ast_channel_tech_set(tmp, &iax2_tech);
+
        /* We can support any format by default, until we get restricted */
-       ast_format_cap_from_old_bitfield(ast_channel_nativeformats(tmp), capability);
-       ast_best_codec(ast_channel_nativeformats(tmp), &tmpfmt);
+       ast_channel_nativeformats_set(tmp, native);
+       tmpfmt = ast_format_cap_get_format(native, 0);
+
+       ast_channel_set_readformat(tmp, tmpfmt);
+       ast_channel_set_rawreadformat(tmp, tmpfmt);
+       ast_channel_set_writeformat(tmp, tmpfmt);
+       ast_channel_set_rawwriteformat(tmp, tmpfmt);
 
-       ast_format_copy(ast_channel_readformat(tmp), &tmpfmt);
-       ast_format_copy(ast_channel_rawreadformat(tmp), &tmpfmt);
-       ast_format_copy(ast_channel_writeformat(tmp), &tmpfmt);
-       ast_format_copy(ast_channel_rawwriteformat(tmp), &tmpfmt);
+       ao2_ref(tmpfmt, -1);
+       ao2_ref(native, -1);
 
        ast_channel_tech_pvt_set(tmp, CALLNO_TO_PTR(i->callno));
 
@@ -5803,12 +5984,15 @@ static struct ast_channel *ast_iax2_new(int callno, int state, iax2_format capab
        }
 
        ast_channel_stage_snapshot_done(tmp);
+       ast_channel_unlock(tmp);
 
        if (state != AST_STATE_DOWN) {
                if (ast_pbx_start(tmp)) {
                        ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp));
+                       /* unlock and relock iaxsl[callno] to preserve locking order */
+                       ast_mutex_unlock(&iaxsl[callno]);
                        ast_hangup(tmp);
-                       i->owner = NULL;
+                       ast_mutex_lock(&iaxsl[callno]);
                        return NULL;
                }
        }
@@ -5836,7 +6020,7 @@ static unsigned int calc_txpeerstamp(struct iax2_trunk_peer *tpeer, int sampms,
        ms = ast_tvdiff_ms(*now, tpeer->txtrunktime);
        /* Predict from last value */
        pred = tpeer->lastsent + sampms;
-       if (abs(ms - pred) < MAX_TIMESTAMP_SKEW)
+       if (labs(ms - pred) < MAX_TIMESTAMP_SKEW)
                ms = pred;
 
        /* We never send the same timestamp twice, so fudge a little if we must */
@@ -5867,7 +6051,7 @@ static unsigned int calc_timestamp(struct chan_iax2_pvt *p, unsigned int ts, str
        int voice = 0;
        int genuine = 0;
        int adjust;
-       int rate = ast_format_rate(&f->subclass.format) / 1000;
+       int rate = 0;
        struct timeval *delivery = NULL;
 
 
@@ -5879,6 +6063,7 @@ static unsigned int calc_timestamp(struct chan_iax2_pvt *p, unsigned int ts, str
        */
        if (f->frametype == AST_FRAME_VOICE) {
                voice = 1;
+               rate = ast_format_get_sample_rate(f->subclass.format) / 1000;
                delivery = &f->delivery;
        } else if (f->frametype == AST_FRAME_IAX) {
                genuine = 1;
@@ -5908,7 +6093,8 @@ static unsigned int calc_timestamp(struct chan_iax2_pvt *p, unsigned int ts, str
                        ms = 0;
                if (voice) {
                        /* On a voice frame, use predicted values if appropriate */
-                       if (p->notsilenttx && abs(ms - p->nextpred) <= MAX_TIMESTAMP_SKEW) {
+                       adjust = (ms - p->nextpred);
+                       if (p->notsilenttx && abs(adjust) <= MAX_TIMESTAMP_SKEW) {
                                /* Adjust our txcore, keeping voice and non-voice synchronized */
                                /* AN EXPLANATION:
                                   When we send voice, we usually send "calculated" timestamps worked out
@@ -5927,7 +6113,6 @@ static unsigned int calc_timestamp(struct chan_iax2_pvt *p, unsigned int ts, str
                                   changing at all.  But if a consistent different starts to develop it
                                   will be eliminated over the course of 10 frames (200-300msecs)
                                */
-                               adjust = (ms - p->nextpred);
                                if (adjust < 0)
                                        p->offset = ast_tvsub(p->offset, ast_samp2tv(abs(adjust), 10000));
                                else if (adjust > 0)
@@ -5949,9 +6134,9 @@ static unsigned int calc_timestamp(struct chan_iax2_pvt *p, unsigned int ts, str
                                * silent periods are multiples of
                                * frame size too) */
 
-                               if (iaxdebug && abs(ms - p->nextpred) > MAX_TIMESTAMP_SKEW )
-                                       ast_debug(1, "predicted timestamp skew (%u) > max (%u), using real ts instead.\n",
-                                               abs(ms - p->nextpred), MAX_TIMESTAMP_SKEW);
+                               if (iaxdebug && abs(adjust) > MAX_TIMESTAMP_SKEW )
+                                       ast_debug(1, "predicted timestamp skew (%d) > max (%d), using real ts instead.\n",
+                                               abs(adjust), MAX_TIMESTAMP_SKEW);
 
                                if (f->samples >= rate) /* check to make sure we don't core dump */
                                {
@@ -5977,19 +6162,21 @@ static unsigned int calc_timestamp(struct chan_iax2_pvt *p, unsigned int ts, str
                } else {
                        /* On a dataframe, use last value + 3 (to accomodate jitter buffer shrinking) if appropriate unless
                           it's a genuine frame */
+                       adjust = (ms - p->lastsent);
                        if (genuine) {
                                /* genuine (IAX LAGRQ etc) must keep their clock-based stamps */
                                if (ms <= p->lastsent)
                                        ms = p->lastsent + 3;
-                       } else if (abs(ms - p->lastsent) <= MAX_TIMESTAMP_SKEW) {
+                       } else if (abs(adjust) <= MAX_TIMESTAMP_SKEW) {
                                /* non-genuine frames (!?) (DTMF, CONTROL) should be pulled into the predicted stream stamps */
                                ms = p->lastsent + 3;
                        }
                }
        }
        p->lastsent = ms;
-       if (voice)
+       if (voice) {
                p->nextpred = p->nextpred + f->samples / rate;
+       }
        return ms;
 }
 
@@ -6005,7 +6192,7 @@ static unsigned int calc_rxstamp(struct chan_iax2_pvt *p, unsigned int offset)
        if (ast_tvzero(p->rxcore)) {
                p->rxcore = ast_tvnow();
                if (iaxdebug)
-                       ast_debug(1, "calc_rxstamp: call=%d: rxcore set to %d.%6.6d - %dms\n",
+                       ast_debug(1, "calc_rxstamp: call=%d: rxcore set to %d.%6.6d - %ums\n",
                                        p->callno, (int)(p->rxcore.tv_sec), (int)(p->rxcore.tv_usec), offset);
                p->rxcore = ast_tvsub(p->rxcore, ast_samp2tv(offset, 1000));
 #if 1
@@ -6092,7 +6279,7 @@ static int iax2_trunk_queue(struct chan_iax2_pvt *pvt, struct iax_frame *fr)
 
                                tpeer->trunkdataalloc += DEFAULT_TRUNKDATA;
                                tpeer->trunkdata = tmp;
-                               ast_debug(1, "Expanded trunk '%s' to %d bytes\n", ast_sockaddr_stringify(&tpeer->addr), tpeer->trunkdataalloc);
+                               ast_debug(1, "Expanded trunk '%s' to %u bytes\n", ast_sockaddr_stringify(&tpeer->addr), tpeer->trunkdataalloc);
                        } else {
                                ast_log(LOG_WARNING, "Maximum trunk data space exceeded to %s\n", ast_sockaddr_stringify(&tpeer->addr));
                                ast_mutex_unlock(&tpeer->lock);
@@ -6232,7 +6419,7 @@ static int decode_frame(ast_aes_decrypt_key *dcx, struct ast_iax2_full_hdr *fh,
 
                padding = 16 + (workspace[15] & 0x0f);
                if (iaxdebug)
-                       ast_debug(1, "Decoding full frame with length %d (padding = %d) (15=%02x)\n", *datalen, padding, workspace[15]);
+                       ast_debug(1, "Decoding full frame with length %d (padding = %d) (15=%02hhx)\n", *datalen, padding, workspace[15]);
                if (*datalen < padding + sizeof(struct ast_iax2_full_hdr))
                        return -1;
 
@@ -6240,9 +6427,9 @@ static int decode_frame(ast_aes_decrypt_key *dcx, struct ast_iax2_full_hdr *fh,
                memcpy(efh->encdata, workspace + padding, *datalen - sizeof(struct ast_iax2_full_enc_hdr));
                f->frametype = fh->type;
                if (f->frametype == AST_FRAME_VIDEO) {
-                       ast_format_from_old_bitfield(&f->subclass.format, (uncompress_subclass(fh->csub & ~0x40) | ((fh->csub >> 6) & 0x1)));
+                       f->subclass.format = ast_format_compatibility_bitfield2format(uncompress_subclass(fh->csub & ~0x40) | ((fh->csub >> 6) & 0x1));
                } else if (f->frametype == AST_FRAME_VOICE) {
-                       ast_format_from_old_bitfield(&f->subclass.format, uncompress_subclass(fh->csub));
+                       f->subclass.format = ast_format_compatibility_bitfield2format(uncompress_subclass(fh->csub));
                } else {
                        f->subclass.integer = uncompress_subclass(fh->csub);
                }
@@ -6279,7 +6466,7 @@ static int encrypt_frame(ast_aes_encrypt_key *ecx, struct ast_iax2_full_hdr *fh,
                workspace[15] &= 0xf0;
                workspace[15] |= (padding & 0xf);
                if (iaxdebug)
-                       ast_debug(1, "Encoding full frame %d/%d with length %d + %d padding (15=%02x)\n", fh->type, fh->csub, *datalen, padding, workspace[15]);
+                       ast_debug(1, "Encoding full frame %d/%d with length %d + %d padding (15=%02hhx)\n", fh->type, fh->csub, *datalen, padding, workspace[15]);
                *datalen += padding;
                memcpy_encrypt(efh->encdata, workspace, *datalen - sizeof(struct ast_iax2_full_enc_hdr), ecx);
                if (*datalen >= 32 + sizeof(struct ast_iax2_full_enc_hdr))
@@ -6383,7 +6570,8 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in
                /* High two bytes are the same on timestamp, or sending on a trunk */ &&
            (f->frametype == AST_FRAME_VOICE)
                /* is a voice frame */ &&
-               (f->subclass.format.id == ast_format_id_from_old_bitfield(pvt->svoiceformat))
+               (ast_format_cmp(f->subclass.format, ast_format_compatibility_bitfield2format(pvt->svoiceformat)) ==
+                       AST_FORMAT_CMP_EQUAL)
                /* is the same type */ ) {
                        /* Force immediate rather than delayed transmission */
                        now = 1;
@@ -6397,7 +6585,8 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in
                 * Otherwise send a mini video frame
                 */
                if (((fts & 0xFFFF8000L) == (pvt->lastvsent & 0xFFFF8000L)) &&
-                   ((f->subclass.format.id) == ast_format_id_from_old_bitfield(pvt->svideoformat))
+               (ast_format_cmp(f->subclass.format, ast_format_compatibility_bitfield2format(pvt->svideoformat)) ==
+                       AST_FORMAT_CMP_EQUAL)
                   ) {
                        now = 1;
                        sendmini = 1;
@@ -6452,11 +6641,11 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in
                fh->type = fr->af.frametype & 0xFF;
 
                if (fr->af.frametype == AST_FRAME_VIDEO) {
-                       iax2_format tmpfmt = ast_format_to_old_bitfield(&fr->af.subclass.format);
-                       tmpfmt |= ast_format_get_video_mark(&fr->af.subclass.format) ? 0x1LL : 0;
+                       iax2_format tmpfmt = ast_format_compatibility_format2bitfield(fr->af.subclass.format);
+                       tmpfmt |= fr->af.subclass.frame_ending ? 0x1LL : 0;
                        fh->csub = compress_subclass(tmpfmt | ((tmpfmt & 0x1LL) << 6));
                } else if (fr->af.frametype == AST_FRAME_VOICE) {
-                       fh->csub = compress_subclass(ast_format_to_old_bitfield(&fr->af.subclass.format));
+                       fh->csub = compress_subclass(ast_format_compatibility_format2bitfield(fr->af.subclass.format));
                } else {
                        fh->csub = compress_subclass(fr->af.subclass.integer);
                }
@@ -6479,9 +6668,9 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in
                if ((f->frametype == AST_FRAME_IAX) && (f->subclass.integer == IAX_COMMAND_ACK))
                        fr->retries = -1;
                else if (f->frametype == AST_FRAME_VOICE)
-                       pvt->svoiceformat = ast_format_to_old_bitfield(&f->subclass.format);
+                       pvt->svoiceformat = ast_format_compatibility_format2bitfield(f->subclass.format);
                else if (f->frametype == AST_FRAME_VIDEO)
-                       pvt->svideoformat = ast_format_to_old_bitfield(&f->subclass.format);
+                       pvt->svideoformat = ast_format_compatibility_format2bitfield(f->subclass.format);
                if (ast_test_flag64(pvt, IAX_ENCRYPTED)) {
                        if (ast_test_flag64(pvt, IAX_KEYPOPULATED)) {
                                if (fr->transfer)
@@ -6512,7 +6701,7 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in
                        vh = (struct ast_iax2_video_hdr *)(fr->af.data.ptr - sizeof(struct ast_iax2_video_hdr));
                        vh->zeros = 0;
                        vh->callno = htons(0x8000 | fr->callno);
-                       vh->ts = htons((fr->ts & 0x7FFF) | (ast_format_get_video_mark(&fr->af.subclass.format) ? 0x8000 : 0));
+                       vh->ts = htons((fr->ts & 0x7FFF) | (fr->af.subclass.frame_ending ? 0x8000 : 0));
                        fr->datalen = fr->af.datalen + sizeof(struct ast_iax2_video_hdr);
                        fr->data = vh;
                        fr->retries = -1;
@@ -6660,31 +6849,23 @@ static void _iax2_show_peers_one(int fd, struct mansession *s, struct show_peers
        }
 
        if (s) {
-
                if (cont->peerlist) { /* IAXpeerlist */
-
                        astman_append(s,
                                "Event: PeerEntry\r\n%s"
                                "Channeltype: IAX\r\n",
                                cont->idtext);
-
                        if (!ast_strlen_zero(peer->username)) {
-
                                astman_append(s,
                                        "ObjectName: %s\r\n"
                                        "ObjectUsername: %s\r\n",
                                        peer->name,
                                        peer->username);
-
                        } else {
-
                                astman_append(s,
                                        "ObjectName: %s\r\n",
                                        name);
                        }
-
                } else { /* IAXpeers */
-
                        astman_append(s,
                                "Event: PeerEntry\r\n%s"
                                "Channeltype: IAX2\r\n"
@@ -6692,28 +6873,21 @@ static void _iax2_show_peers_one(int fd, struct mansession *s, struct show_peers
                                cont->idtext,
                                name);
                }
-
                astman_append(s,
                        "ChanObjectType: peer\r\n"
                        "IPaddress: %s\r\n",
                        tmp_host);
-
                if (cont->peerlist) { /* IAXpeerlist */
-
                        astman_append(s,
                                "Mask: %s\r\n"
                                "Port: %s\r\n",
                                tmp_mask,
                                tmp_port);
-
                } else { /* IAXpeers */
-
                        astman_append(s,
                                "IPport: %s\r\n",
                                tmp_port);
-
                }
-
                astman_append(s,
                        "Dynamic: %s\r\n"
                        "Trunk: %s\r\n"
@@ -6723,19 +6897,13 @@ static void _iax2_show_peers_one(int fd, struct mansession *s, struct show_peers
                        ast_test_flag64(peer, IAX_TRUNK) ? "yes" : "no",
                        peer->encmethods ? ast_str_buffer(encmethods) : "no",
                        status);
-
                if (cont->peerlist) { /* IAXpeerlist */
-
                        astman_append(s, "\r\n");
-
                } else { /* IAXpeers */
-
                        astman_append(s,
                                "Description: %s\r\n\r\n",
                                peer->description);
-
                }
-
        } else {
                ast_cli(fd, PEERS_FORMAT,
                        name,
@@ -6750,7 +6918,6 @@ static void _iax2_show_peers_one(int fd, struct mansession *s, struct show_peers
        }
 
        cont->total_peers++;
-
 }
 
 static int __iax2_show_peers(int fd, int *total, struct mansession *s, const int argc, const char * const argv[])
@@ -6871,10 +7038,10 @@ static char *handle_cli_iax2_show_threads(struct ast_cli_entry *e, int cmd, stru
        AST_LIST_LOCK(&idle_list);
        AST_LIST_TRAVERSE(&idle_list, thread, list) {
 #ifdef DEBUG_SCHED_MULTITHREAD
-               ast_cli(a->fd, "Thread %d: state=%d, update=%d, actions=%d, func='%s'\n",
+               ast_cli(a->fd, "Thread %d: state=%u, update=%d, actions=%d, func='%s'\n",
                        thread->threadnum, thread->iostate, (int)(t - thread->checktime), thread->actions, thread->curfunc);
 #else
-               ast_cli(a->fd, "Thread %d: state=%d, update=%d, actions=%d\n",
+               ast_cli(a->fd, "Thread %d: state=%u, update=%d, actions=%d\n",
                        thread->threadnum, thread->iostate, (int)(t - thread->checktime), thread->actions);
 #endif
                threadcount++;
@@ -6888,10 +7055,10 @@ static char *handle_cli_iax2_show_threads(struct ast_cli_entry *e, int cmd, stru
                else
                        type = 'P';
 #ifdef DEBUG_SCHED_MULTITHREAD
-               ast_cli(a->fd, "Thread %c%d: state=%d, update=%d, actions=%d, func='%s'\n",
+               ast_cli(a->fd, "Thread %c%d: state=%u, update=%d, actions=%d, func='%s'\n",
                        type, thread->threadnum, thread->iostate, (int)(t - thread->checktime), thread->actions, thread->curfunc);
 #else
-               ast_cli(a->fd, "Thread %c%d: state=%d, update=%d, actions=%d\n",
+               ast_cli(a->fd, "Thread %c%d: state=%u, update=%d, actions=%d\n",
                        type, thread->threadnum, thread->iostate, (int)(t - thread->checktime), thread->actions);
 #endif
                threadcount++;
@@ -6901,10 +7068,10 @@ static char *handle_cli_iax2_show_threads(struct ast_cli_entry *e, int cmd, stru
        AST_LIST_LOCK(&dynamic_list);
        AST_LIST_TRAVERSE(&dynamic_list, thread, list) {
 #ifdef DEBUG_SCHED_MULTITHREAD
-               ast_cli(a->fd, "Thread %d: state=%d, update=%d, actions=%d, func='%s'\n",
+               ast_cli(a->fd, "Thread %d: state=%u, update=%d, actions=%d, func='%s'\n",
                        thread->threadnum, thread->iostate, (int)(t - thread->checktime), thread->actions, thread->curfunc);
 #else
-               ast_cli(a->fd, "Thread %d: state=%d, update=%d, actions=%d\n",
+               ast_cli(a->fd, "Thread %d: state=%u, update=%d, actions=%d\n",
                        thread->threadnum, thread->iostate, (int)(t - thread->checktime), thread->actions);
 #endif
                dynamiccount++;
@@ -7063,16 +7230,14 @@ static int manager_iax2_show_peers(struct mansession *s, const struct message *m
                snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id);
 
        astman_send_listack(s, m, "Peer status list will follow", "start");
-        /* List the peers in separate manager events */
+
+       /* List the peers in separate manager events */
        __iax2_show_peers(-1, &total, s, 3, a);
-        /* Send final confirmation */
-        astman_append(s,
-        "Event: PeerlistComplete\r\n"
-        "EventList: Complete\r\n"
-        "ListItems: %d\r\n"
-        "%s"
-        "\r\n", total, idtext);
-        return 0;
+
+       /* Send final confirmation */
+       astman_send_list_complete_start(s, m, "PeerlistComplete", total);
+       astman_send_list_complete_end(s);
+       return 0;
 }
 
 /*! \brief callback to display iax peers in manager format */
@@ -7100,25 +7265,16 @@ static int manager_iax2_show_peer_list(struct mansession *s, const struct messag
                snprintf(cont.idtext, sizeof(cont.idtext), "ActionID: %s\r\n", id);
        }
 
-       astman_append(s,
-               "Response: Success\r\n"
-               "%sMessage: IAX Peer status list will follow\r\n\r\n",
-               cont.idtext);
-
+       astman_send_listack(s, m, "IAX Peer status list will follow", "start");
 
        i = ao2_iterator_init(peers, 0);
        for (; (peer = ao2_iterator_next(&i)); peer_unref(peer)) {
-
                _iax2_show_peers_one(-1, s, &cont, peer);
-
        }
        ao2_iterator_destroy(&i);
 
-       astman_append(s,
-               "Event: PeerlistComplete\r\n"
-               "%sListItems: %d\r\n\r\n",
-               cont.idtext,
-               cont.total_peers);
+       astman_send_list_complete_start(s, m, "PeerlistComplete", cont.total_peers);
+       astman_send_list_complete_end(s);
 
        return RESULT_SUCCESS;
 }
@@ -7223,12 +7379,8 @@ static int manager_iax2_show_registry(struct mansession *s, const struct message
        }
        AST_LIST_UNLOCK(&registrations);
 
-       astman_append(s,
-               "Event: RegistrationsComplete\r\n"
-               "EventList: Complete\r\n"
-               "ListItems: %d\r\n"
-               "%s"
-               "\r\n", total, idtext);
+       astman_send_list_complete_start(s, m, "RegistrationsComplete", total);
+       astman_send_list_complete_end(s);
 
        return 0;
 }
@@ -7305,8 +7457,8 @@ static int ast_cli_netstats(struct mansession *s, int fd, int limit_fmt)
        int numchans = 0;
        char first_message[10] = { 0, };
        char last_message[10] = { 0, };
-#define ACN_FORMAT1 "%-20.25s %4d %4d %4d %5d %3d %5d %4d %6d %4d %4d %5d %3d %5d %4d %6d %s%s %4s%s\n"
-#define ACN_FORMAT2 "%s %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %s%s %s%s\n"
+#define ACN_FORMAT1 "%-20.25s %4u %4d %4d %5d %3d %5d %4d %6d %4d %4d %5d %3d %5d %4d %6d %s%s %4s%s\n"
+#define ACN_FORMAT2 "%s %u %d %d %d %d %d %d %d %d %d %d %d %d %d %d %s%s %s%s\n"
        for (x = 0; x < ARRAY_LEN(iaxs); x++) {
                ast_mutex_lock(&iaxsl[x]);
                if (iaxs[x]) {
@@ -7555,6 +7707,12 @@ static int __send_command(struct chan_iax2_pvt *i, char type, int command, unsig
 
 static int send_command(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, const unsigned char *data, int datalen, int seqno)
 {
+       if (type == AST_FRAME_CONTROL && !iax2_is_control_frame_allowed(command)) {
+               /* Control frame should not go out on the wire. */
+               ast_debug(2, "Callno %d: Blocked sending control frame %d.\n",
+                       i->callno, command);
+               return 0;
+       }
        return __send_command(i, type, command, ts, data, datalen, seqno, 0, 0, 0);
 }
 
@@ -7657,9 +7815,11 @@ static int check_access(int callno, struct ast_sockaddr *addr, struct iax_ies *i
 
        /* Use provided preferences until told otherwise for actual preferences */
        if (ies->codec_prefs) {
-               ast_codec_pref_convert(&iaxs[callno]->rprefs, ies->codec_prefs, 32, 0);
-               ast_codec_pref_convert(&iaxs[callno]->prefs, ies->codec_prefs, 32, 0);
+               iax2_codec_pref_convert(&iaxs[callno]->rprefs, ies->codec_prefs, 32, 0);
+       } else {
+               memset(&iaxs[callno]->rprefs, 0, sizeof(iaxs[callno]->rprefs));
        }
+       iaxs[callno]->prefs = iaxs[callno]->rprefs;
 
        if (!gotcapability) {
                iaxs[callno]->peercapability = iaxs[callno]->peerformat;
@@ -7794,7 +7954,7 @@ static int check_access(int callno, struct ast_sockaddr *addr, struct iax_ies *i
                        iaxs[callno]->amaflags = user->amaflags;
                if (!ast_strlen_zero(user->language))
                        ast_string_field_set(iaxs[callno], language, user->language);
-               ast_copy_flags64(iaxs[callno], user, IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE);
+               ast_copy_flags64(iaxs[callno], user, IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE);
                /* Keep this check last */
                if (!ast_strlen_zero(user->dbsecret)) {
                        char *family, *key=NULL;
@@ -7987,7 +8147,7 @@ static int authenticate_verify(struct chan_iax2_pvt *p, struct iax_ies *ies)
                        MD5Final(digest, &md5);
                        /* If they support md5, authenticate with it.  */
                        for (x=0;x<16;x++)
-                               sprintf(requeststr + (x << 1), "%2.2x", digest[x]); /* safe */
+                               sprintf(requeststr + (x << 1), "%02hhx", digest[x]); /* safe */
                        if (!strcasecmp(requeststr, md5secret)) {
                                res = 0;
                                break;
@@ -8119,7 +8279,7 @@ static int register_verify(int callno, struct ast_sockaddr *addr, struct iax_ies
                        MD5Update(&md5, (unsigned char *)tmppw, strlen(tmppw));
                        MD5Final(digest, &md5);
                        for (x=0;x<16;x++)
-                               sprintf(requeststr + (x << 1), "%2.2x", digest[x]); /* safe */
+                               sprintf(requeststr + (x << 1), "%02hhx", digest[x]); /* safe */
                        if (!strcasecmp(requeststr, md5secret))
                                break;
                }
@@ -8203,7 +8363,7 @@ static int authenticate(const char *challenge, const char *secret, const char *k
                        MD5Final(digest, &md5);
                        /* If they support md5, authenticate with it.  */
                        for (x=0;x<16;x++)
-                               sprintf(digres + (x << 1),  "%2.2x", digest[x]); /* safe */
+                               sprintf(digres + (x << 1),  "%02hhx", digest[x]); /* safe */
                        if (pvt) {
                                build_encryption_keys(digest, pvt);
                        }
@@ -8350,6 +8510,17 @@ static int iax2_do_register(struct iax2_registry *reg);
 static void __iax2_do_register_s(const void *data)
 {
        struct iax2_registry *reg = (struct iax2_registry *)data;
+
+       if (ast_sockaddr_isnull(&reg->addr)) {
+               reg->addr.ss.ss_family = AST_AF_UNSPEC;
+               ast_dnsmgr_lookup(reg->hostname, &reg->addr, &reg->dnsmgr, srvlookup ? "_iax._udp" : NULL);
+               if (!ast_sockaddr_port(&reg->addr)) {
+                       ast_sockaddr_set_port(&reg->addr, reg->port);
+               } else {
+                       reg->port = ast_sockaddr_port(&reg->addr);
+               }
+       }
+
        reg->expire = -1;
        iax2_do_register(reg);
 }
@@ -8582,8 +8753,9 @@ static int iax2_append_register(const char *hostname, const char *username,
 {
        struct iax2_registry *reg;
 
-       if (!(reg = ast_calloc(1, sizeof(*reg))))
+       if (!(reg = ast_calloc(1, sizeof(*reg) + strlen(hostname) + 1))) {
                return -1;
+       }
 
        reg->addr.ss.ss_family = AST_AF_UNSPEC;
        if (ast_dnsmgr_lookup(hostname, &reg->addr, &reg->dnsmgr, srvlookup ? "_iax._udp" : NULL) < 0) {
@@ -8592,13 +8764,24 @@ static int iax2_append_register(const char *hostname, const char *username,
        }
 
        ast_copy_string(reg->username, username, sizeof(reg->username));
+       strcpy(reg->hostname, hostname); /* Note: This is safe */
 
-       if (secret)
+       if (secret) {
                ast_copy_string(reg->secret, secret, sizeof(reg->secret));
+       }
 
        reg->expire = -1;
        reg->refresh = IAX_DEFAULT_REG_EXPIRE;
-       ast_sockaddr_set_port(&reg->addr, porta ? atoi(porta) : IAX_DEFAULT_PORTNO);
+
+       reg->port = ast_sockaddr_port(&reg->addr);
+
+       if (!porta && !reg->port) {
+               reg->port = IAX_DEFAULT_PORTNO;
+       } else if (porta) {
+               sscanf(porta, "%5d", &reg->port);
+       }
+
+       ast_sockaddr_set_port(&reg->addr, reg->port);
 
        AST_LIST_LOCK(&registrations);
        AST_LIST_INSERT_HEAD(&registrations, reg, entry);
@@ -8925,19 +9108,9 @@ static int update_registry(struct ast_sockaddr *addr, int callno, char *devtype,
                iax_ie_append_addr(&ied, IAX_IE_APPARENT_ADDR, &peer_addr);
                if (!ast_strlen_zero(p->mailbox)) {
                        int new, old;
-                       char *mailbox, *context;
                        RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-                       struct ast_str *uniqueid = ast_str_alloca(AST_MAX_MAILBOX_UNIQUEID);
-
-                       context = mailbox = ast_strdupa(p->mailbox);
-                       strsep(&context, "@");
-                       if (ast_strlen_zero(context)) {
-                               context = "default";
-                       }
-
-                       ast_str_set(&uniqueid, 0, "%s@%s", mailbox, context);
-                       msg = stasis_cache_get(ast_mwi_state_cache(), ast_mwi_state_type(), ast_str_buffer(uniqueid));
 
+                       msg = stasis_cache_get(ast_mwi_state_cache(), ast_mwi_state_type(), p->mailbox);
                        if (msg) {
                                struct ast_mwi_state *mwi_state = stasis_message_data(msg);
                                new = mwi_state->new_msgs;
@@ -9287,7 +9460,7 @@ static int timing_read(int *id, int fd, short events, void *cbdata)
                        res = send_trunk(tpeer, &now);
                        trunk_timed++;
                        if (iaxtrunkdebug) {
-                               ast_verbose(" - Trunk peer (%s) has %d call chunk%s in transit, %d bytes backloged and has hit a high water mark of %d bytes\n",
+                               ast_verbose(" - Trunk peer (%s) has %d call chunk%s in transit, %u bytes backloged and has hit a high water mark of %u bytes\n",
                                                        ast_sockaddr_stringify(&tpeer->addr),
                                                        res,
                                                        (res != 1) ? "s" : "",
@@ -9479,7 +9652,7 @@ static void log_jitterstats(unsigned short callno)
                        localooo = jbinfo.frames_ooo;
                        localpackets = jbinfo.frames_in;
                }
-               ast_debug(3, "JB STATS:%s ping=%d ljitterms=%d ljbdelayms=%d ltotlost=%d lrecentlosspct=%d ldropped=%d looo=%d lrecvd=%d rjitterms=%d rjbdelayms=%d rtotlost=%d rrecentlosspct=%d rdropped=%d rooo=%d rrecvd=%d\n",
+               ast_debug(3, "JB STATS:%s ping=%u ljitterms=%d ljbdelayms=%d ltotlost=%d lrecentlosspct=%d ldropped=%d looo=%d lrecvd=%d rjitterms=%d rjbdelayms=%d rtotlost=%d rrecentlosspct=%d rdropped=%d rooo=%d rrecvd=%d\n",
                        ast_channel_name(iaxs[callno]->owner),
                        iaxs[callno]->pingtime,
                        localjitter,
@@ -9727,7 +9900,7 @@ static int socket_process_meta(int packet_len, struct ast_iax2_meta_hdr *meta, s
                        ast_log(LOG_WARNING, "Received trunked frame before first full voice frame\n");
                        iax2_vnak(fr->callno);
                } else {
-                       ast_format_from_old_bitfield(&f.subclass.format, iaxs[fr->callno]->voiceformat);
+                       f.subclass.format = ast_format_compatibility_bitfield2format(iaxs[fr->callno]->voiceformat);
                        f.datalen = len;
                        if (f.datalen >= 0) {
                                if (f.datalen)
@@ -9747,7 +9920,7 @@ static int socket_process_meta(int packet_len, struct ast_iax2_meta_hdr *meta, s
                                        f.mallocd = 0;
                                        f.offset = 0;
                                        if (f.datalen && (f.frametype == AST_FRAME_VOICE))
-                                               f.samples = ast_codec_get_samples(&f);
+                                               f.samples = ast_codec_samples_count(&f);
                                        else
                                                f.samples = 0;
                                        fr->outoforder = 0;
@@ -9772,10 +9945,16 @@ static int socket_process_meta(int packet_len, struct ast_iax2_meta_hdr *meta, s
 
 static int acf_iaxvar_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 {
-       struct ast_datastore *variablestore = ast_channel_datastore_find(chan, &iax2_variable_datastore_info, NULL);
+       struct ast_datastore *variablestore;
        AST_LIST_HEAD(, ast_var_t) *varlist;
        struct ast_var_t *var;
 
+       if (!chan) {
+               ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
+               return -1;
+       }
+
+       variablestore = ast_channel_datastore_find(chan, &iax2_variable_datastore_info, NULL);
        if (!variablestore) {
                *buf = '\0';
                return 0;
@@ -9795,10 +9974,16 @@ static int acf_iaxvar_read(struct ast_channel *chan, const char *cmd, char *data
 
 static int acf_iaxvar_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
 {
-       struct ast_datastore *variablestore = ast_channel_datastore_find(chan, &iax2_variable_datastore_info, NULL);
+       struct ast_datastore *variablestore;
        AST_LIST_HEAD(, ast_var_t) *varlist;
        struct ast_var_t *var;
 
+       if (!chan) {
+               ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
+               return -1;
+       }
+
+       variablestore = ast_channel_datastore_find(chan, &iax2_variable_datastore_info, NULL);
        if (!variablestore) {
                variablestore = ast_datastore_alloc(&iax2_variable_datastore_info, NULL);
                if (!variablestore) {
@@ -9892,7 +10077,7 @@ static int socket_process_helper(struct iax2_thread *thread)
        struct iax_frame *duped_fr;
        char host_pref_buf[128];
        char caller_pref_buf[128];
-       struct ast_codec_pref pref;
+       struct iax2_codec_pref pref;
        char *using_prefs = "mine";
 
        /* allocate an iax_frame with 4096 bytes of data buffer */
@@ -9957,12 +10142,12 @@ static int socket_process_helper(struct iax2_thread *thread)
                /* Retrieve the type and subclass */
                f.frametype = fh->type;
                if (f.frametype == AST_FRAME_VIDEO) {
-                       ast_format_from_old_bitfield(&f.subclass.format, (uncompress_subclass(fh->csub & ~0x40)));
+                       f.subclass.format = ast_format_compatibility_bitfield2format(uncompress_subclass(fh->csub & ~0x40));
                        if ((fh->csub >> 6) & 0x1) {
-                               ast_format_set_video_mark(&f.subclass.format);
+                               f.subclass.frame_ending = 1;
                        }
                } else if (f.frametype == AST_FRAME_VOICE) {
-                       ast_format_from_old_bitfield(&f.subclass.format, uncompress_subclass(fh->csub));
+                       f.subclass.format = ast_format_compatibility_bitfield2format(uncompress_subclass(fh->csub));
                } else {
                        f.subclass.integer = uncompress_subclass(fh->csub);
                }
@@ -10050,12 +10235,11 @@ static int socket_process_helper(struct iax2_thread *thread)
        }
 
        if (fr->callno > 0) {
-               struct ast_callid *mount_callid;
+               ast_callid mount_callid;
                ast_mutex_lock(&iaxsl[fr->callno]);
                if (iaxs[fr->callno] && ((mount_callid = iax_pvt_callid_get(fr->callno)))) {
                        /* Bind to thread */
                        ast_callid_threadassoc_add(mount_callid);
-                       ast_callid_unref(mount_callid);
                }
        }
 
@@ -10158,7 +10342,7 @@ static int socket_process_helper(struct iax2_thread *thread)
        }
        if (ntohs(mh->callno) & IAX_FLAG_FULL) {
                if (iaxdebug)
-                       ast_debug(1, "Received packet %d, (%d, %u)\n", fh->oseqno, f.frametype, f.subclass.integer);
+                       ast_debug(1, "Received packet %d, (%u, %d)\n", fh->oseqno, f.frametype, f.subclass.integer);
                /* Check if it's out of order (and not an ACK or INVAL) */
                fr->oseqno = fh->oseqno;
                fr->iseqno = fh->iseqno;
@@ -10198,7 +10382,7 @@ static int socket_process_helper(struct iax2_thread *thread)
                          (f.subclass.integer != IAX_COMMAND_VNAK)) ||
                          (f.frametype != AST_FRAME_IAX)) {
                                /* If it's not an ACK packet, it's out of order. */
-                               ast_debug(1, "Packet arrived out of order (expecting %d, got %d) (frametype = %d, subclass = %d)\n",
+                               ast_debug(1, "Packet arrived out of order (expecting %d, got %d) (frametype = %u, subclass = %d)\n",
                                        iaxs[fr->callno]->iseqno, fr->oseqno, f.frametype, f.subclass.integer);
                                /* Check to see if we need to request retransmission,
                                 * and take sequence number wraparound into account */
@@ -10305,8 +10489,9 @@ static int socket_process_helper(struct iax2_thread *thread)
                    (f.frametype == AST_FRAME_IAX)) {
                        if (ast_test_flag64(iaxs[fr->callno], IAX_DELAYPBXSTART)) {
                                ast_clear_flag64(iaxs[fr->callno], IAX_DELAYPBXSTART);
-                               if (!ast_iax2_new(fr->callno, AST_STATE_RING, iaxs[fr->callno]->chosenformat, NULL,
-                                                 ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_AUTHENTICATED))) {
+                               if (!ast_iax2_new(fr->callno, AST_STATE_RING,
+                                       iaxs[fr->callno]->chosenformat, &iaxs[fr->callno]->rprefs, NULL, NULL,
+                                       ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_AUTHENTICATED))) {
                                        ast_variables_destroy(ies.vars);
                                        ast_mutex_unlock(&iaxsl[fr->callno]);
                                        return 1;
@@ -10386,22 +10571,21 @@ static int socket_process_helper(struct iax2_thread *thread)
                }
 
                if (f.frametype == AST_FRAME_VOICE) {
-                       if (ast_format_to_old_bitfield(&f.subclass.format) != iaxs[fr->callno]->voiceformat) {
-                                       iaxs[fr->callno]->voiceformat = ast_format_to_old_bitfield(&f.subclass.format);
-                                       ast_debug(1, "Ooh, voice format changed to '%s'\n", ast_getformatname(&f.subclass.format));
+                       if (ast_format_compatibility_format2bitfield(f.subclass.format) != iaxs[fr->callno]->voiceformat) {
+                                       iaxs[fr->callno]->voiceformat = ast_format_compatibility_format2bitfield(f.subclass.format);
+                                       ast_debug(1, "Ooh, voice format changed to '%s'\n", ast_format_get_name(f.subclass.format));
                                        if (iaxs[fr->callno]->owner) {
                                                iax2_lock_owner(fr->callno);
                                                if (iaxs[fr->callno]) {
                                                        if (iaxs[fr->callno]->owner) {
-                                                               struct ast_format_cap *orignative = ast_format_cap_dup(ast_channel_nativeformats(iaxs[fr->callno]->owner));
-                                                               struct ast_format_cap *native = ast_channel_nativeformats(iaxs[fr->callno]->owner);
-                                                               if (orignative) {
-                                                                       ast_format_cap_set(native, &f.subclass.format);
-                                                                       if (ast_channel_readformat(iaxs[fr->callno]->owner)->id) {
+                                                               struct ast_format_cap *native = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
+                                                               if (native) {
+                                                                       ast_format_cap_append(native, f.subclass.format, 0);
+                                                                       ast_channel_nativeformats_set(iaxs[fr->callno]->owner, native);
+                                                                       if (ast_channel_readformat(iaxs[fr->callno]->owner)) {
                                                                                ast_set_read_format(iaxs[fr->callno]->owner, ast_channel_readformat(iaxs[fr->callno]->owner));
                                                                        }
-                                                                       ast_format_cap_copy(native, orignative);
-                                                                       orignative = ast_format_cap_destroy(orignative);
+                                                                       ao2_ref(native, -1);
                                                                }
                                                                ast_channel_unlock(iaxs[fr->callno]->owner);
                                                        }
@@ -10420,16 +10604,9 @@ static int socket_process_helper(struct iax2_thread *thread)
                        }
                }
                if (f.frametype == AST_FRAME_VIDEO) {
-                       if (f.subclass.format.id != ast_format_id_from_old_bitfield(iaxs[fr->callno]->videoformat)) {
-                               ast_debug(1, "Ooh, video format changed to %s\n", ast_getformatname(&f.subclass.format));
-                               iaxs[fr->callno]->videoformat = ast_format_to_old_bitfield(&f.subclass.format);
-                       }
-               }
-               if (f.frametype == AST_FRAME_CONTROL && iaxs[fr->callno]->owner) {
-                       if (f.subclass.integer == AST_CONTROL_BUSY) {
-                               ast_channel_hangupcause_set(iaxs[fr->callno]->owner, AST_CAUSE_BUSY);
-                       } else if (f.subclass.integer == AST_CONTROL_CONGESTION) {
-                               ast_channel_hangupcause_set(iaxs[fr->callno]->owner, AST_CAUSE_CONGESTION);
+                       if (ast_format_compatibility_format2bitfield(f.subclass.format) != iaxs[fr->callno]->videoformat) {
+                               ast_debug(1, "Ooh, video format changed to %s\n", ast_format_get_name(f.subclass.format));
+                               iaxs[fr->callno]->videoformat = ast_format_compatibility_format2bitfield(f.subclass.format);
                        }
                }
                if (f.frametype == AST_FRAME_IAX) {
@@ -10445,7 +10622,7 @@ static int socket_process_helper(struct iax2_thread *thread)
                             f.subclass.integer != IAX_COMMAND_LAGRP) {
                                iaxs[fr->callno]->last = fr->ts;
                                if (iaxdebug)
-                                       ast_debug(1, "For call=%d, set last=%d\n", fr->callno, fr->ts);
+                                       ast_debug(1, "For call=%d, set last=%u\n", fr->callno, fr->ts);
                        }
                        iaxs[fr->callno]->last_iax_message = f.subclass.integer;
                        if (!iaxs[fr->callno]->first_iax_message) {
@@ -10592,12 +10769,12 @@ static int socket_process_helper(struct iax2_thread *thread)
                                                        strcpy(caller_pref_buf, "disabled");
                                                        strcpy(host_pref_buf, "disabled");
                                                } else {
-                                                       struct ast_format tmpfmt;
+                                                       struct ast_format *tmpfmt;
                                                        using_prefs = "mine";
                                                        /* If the information elements are in here... use them */
                                                        if (ies.codec_prefs)
-                                                               ast_codec_pref_convert(&iaxs[fr->callno]->rprefs, ies.codec_prefs, 32, 0);
-                                                       if (ast_codec_pref_index(&iaxs[fr->callno]->rprefs, 0, &tmpfmt)) {
+                                                               iax2_codec_pref_convert(&iaxs[fr->callno]->rprefs, ies.codec_prefs, 32, 0);
+                                                       if (iax2_codec_pref_index(&iaxs[fr->callno]->rprefs, 0, &tmpfmt)) {
                                                                /* If we are codec_first_choice we let the caller have the 1st shot at picking the codec.*/
                                                                if (ast_test_flag64(iaxs[fr->callno], IAX_CODEC_USER_FIRST)) {
                                                                        pref = iaxs[fr->callno]->rprefs;
@@ -10608,9 +10785,9 @@ static int socket_process_helper(struct iax2_thread *thread)
                                                        } else
                                                                pref = iaxs[fr->callno]->prefs;
 
-                                                       format = iax2_codec_choose(&pref, iaxs[fr->callno]->capability & iaxs[fr->callno]->peercapability, 0);
-                                                       ast_codec_pref_string(&iaxs[fr->callno]->rprefs, caller_pref_buf, sizeof(caller_pref_buf) - 1);
-                                                       ast_codec_pref_string(&iaxs[fr->callno]->prefs, host_pref_buf, sizeof(host_pref_buf) - 1);
+                                                       format = iax2_codec_choose(&pref, iaxs[fr->callno]->capability & iaxs[fr->callno]->peercapability);
+                                                       iax2_codec_pref_string(&iaxs[fr->callno]->rprefs, caller_pref_buf, sizeof(caller_pref_buf) - 1);
+                                                       iax2_codec_pref_string(&iaxs[fr->callno]->prefs, host_pref_buf, sizeof(host_pref_buf) - 1);
                                                }
                                                if (!format) {
                                                        if(!ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP))
@@ -10624,18 +10801,21 @@ static int socket_process_helper(struct iax2_thread *thread)
                                                                        break;
                                                                }
                                                                if (authdebug) {
-                                                                       char tmp[256], tmp2[256], tmp3[256];
+                                                                       struct ast_str *peer_buf = ast_str_alloca(64);
+                                                                       struct ast_str *cap_buf = ast_str_alloca(64);
+                                                                       struct ast_str *peer_form_buf = ast_str_alloca(64);
+
                                                                        if (ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP)) {
                                                                                ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested '%s' incompatible with our capability '%s'.\n",
                                                                                        ast_sockaddr_stringify(&addr),
-                                                                                       iax2_getformatname_multiple(tmp, sizeof(tmp), iaxs[fr->callno]->peerformat),
-                                                                                       iax2_getformatname_multiple(tmp2, sizeof(tmp2), iaxs[fr->callno]->capability));
+                                                                                       iax2_getformatname_multiple(iaxs[fr->callno]->peerformat, &peer_form_buf),
+                                                                                       iax2_getformatname_multiple(iaxs[fr->callno]->capability, &cap_buf));
                                                                        } else {
                                                                                ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability '%s'/'%s' incompatible with our capability '%s'.\n",
                                                                                        ast_sockaddr_stringify(&addr),
-                                                                                       iax2_getformatname_multiple(tmp, sizeof(tmp), iaxs[fr->callno]->peerformat),
-                                                                                       iax2_getformatname_multiple(tmp2, sizeof(tmp2), iaxs[fr->callno]->peercapability),
-                                                                                       iax2_getformatname_multiple(tmp3, sizeof(tmp3), iaxs[fr->callno]->capability));
+                                                                                       iax2_getformatname_multiple(iaxs[fr->callno]->peerformat, &peer_form_buf),
+                                                                                       iax2_getformatname_multiple(iaxs[fr->callno]->peercapability, &peer_buf),
+                                                                                       iax2_getformatname_multiple(iaxs[fr->callno]->capability, &cap_buf));
                                                                        }
                                                                }
                                                        } else {
@@ -10647,13 +10827,13 @@ static int socket_process_helper(struct iax2_thread *thread)
                                                                        if(ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOPREFS)) {
                                                                                using_prefs = ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP) ? "reqonly" : "disabled";
                                                                                memset(&pref, 0, sizeof(pref));
-                                                                               format = iax2_best_codec(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
+                                                                               format = iax2_format_compatibility_best(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
                                                                                strcpy(caller_pref_buf,"disabled");
                                                                                strcpy(host_pref_buf,"disabled");
                                                                        } else {
-                                                                               struct ast_format tmpfmt;
+                                                                               struct ast_format *tmpfmt;
                                                                                using_prefs = "mine";
-                                                                               if (ast_codec_pref_index(&iaxs[fr->callno]->rprefs, 0, &tmpfmt)) {
+                                                                               if (iax2_codec_pref_index(&iaxs[fr->callno]->rprefs, 0, &tmpfmt)) {
                                                                                        /* Do the opposite of what we tried above. */
                                                                                        if (ast_test_flag64(iaxs[fr->callno], IAX_CODEC_USER_FIRST)) {
                                                                                                pref = iaxs[fr->callno]->prefs;
@@ -10661,18 +10841,21 @@ static int socket_process_helper(struct iax2_thread *thread)
                                                                                                pref = iaxs[fr->callno]->rprefs;
                                                                                                using_prefs = "caller";
                                                                                        }
-                                                                                       format = iax2_codec_choose(&pref, iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability, 1);
+                                                                                       format = iax2_codec_choose(&pref, iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
                                                                                } else /* if no codec_prefs IE do it the old way */
-                                                                                       format = iax2_best_codec(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
+                                                                                       format = iax2_format_compatibility_best(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
                                                                        }
                                                                }
 
                                                                if (!format) {
-                                                                       char tmp[256], tmp2[256], tmp3[256];
+                                                                       struct ast_str *peer_buf = ast_str_alloca(64);
+                                                                       struct ast_str *cap_buf = ast_str_alloca(64);
+                                                                       struct ast_str *peer_form_buf = ast_str_alloca(64);
+
                                                                        memset(&ied0, 0, sizeof(ied0));
                                                                        iax_ie_append_str(&ied0, IAX_IE_CAUSE, "Unable to negotiate codec");
                                                                        iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
-                                                                       ast_log(LOG_ERROR, "No best format in '%s'???\n", iax2_getformatname_multiple(tmp, sizeof(tmp), iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability));
+                                                                       ast_log(LOG_ERROR, "No best format in '%s'???\n", iax2_getformatname_multiple(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability, &cap_buf));
                                                                        send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
                                                                        if (!iaxs[fr->callno]) {
                                                                                break;
@@ -10680,9 +10863,9 @@ static int socket_process_helper(struct iax2_thread *thread)
                                                                        if (authdebug) {
                                                                                ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability '%s'/'%s' incompatible with our capability '%s'.\n",
                                                                                        ast_sockaddr_stringify(&addr),
-                                                                                       iax2_getformatname_multiple(tmp, sizeof(tmp), iaxs[fr->callno]->peerformat),
-                                                                                       iax2_getformatname_multiple(tmp2, sizeof(tmp2), iaxs[fr->callno]->peercapability),
-                                                                                       iax2_getformatname_multiple(tmp3, sizeof(tmp3), iaxs[fr->callno]->capability));
+                                                                                       iax2_getformatname_multiple(iaxs[fr->callno]->peerformat, &peer_form_buf),
+                                                                                       iax2_getformatname_multiple(iaxs[fr->callno]->peercapability, &peer_buf),
+                                                                                       iax2_getformatname_multiple(iaxs[fr->callno]->capability, &cap_buf));
                                                                        }
                                                                        ast_set_flag64(iaxs[fr->callno], IAX_ALREADYGONE);
                                                                        break;
@@ -10830,7 +11013,7 @@ static int socket_process_helper(struct iax2_thread *thread)
                                        iaxs[fr->callno]->peerformat = ies.format;
                                } else {
                                        if (iaxs[fr->callno]->owner)
-                                               iaxs[fr->callno]->peerformat = ast_format_cap_to_old_bitfield(ast_channel_nativeformats(iaxs[fr->callno]->owner));
+                                               iaxs[fr->callno]->peerformat = iax2_format_compatibility_cap2bitfield(ast_channel_nativeformats(iaxs[fr->callno]->owner));
                                        else
                                                iaxs[fr->callno]->peerformat = iaxs[fr->callno]->capability;
                                }
@@ -10845,28 +11028,38 @@ static int socket_process_helper(struct iax2_thread *thread)
                                                break;
                                        }
                                        if (authdebug) {
-                                               char tmp1[256], tmp2[256];
+                                               struct ast_str *peer_buf = ast_str_alloca(64);
+                                               struct ast_str *cap_buf = ast_str_alloca(64);
+
                                                ast_log(LOG_NOTICE, "Rejected call to %s, format %s incompatible with our capability %s.\n",
                                                        ast_sockaddr_stringify(&addr),
-                                                       iax2_getformatname_multiple(tmp1, sizeof(tmp1), iaxs[fr->callno]->peerformat),
-                                                       iax2_getformatname_multiple(tmp2, sizeof(tmp2), iaxs[fr->callno]->capability));
+                                                       iax2_getformatname_multiple(iaxs[fr->callno]->peerformat, &peer_buf),
+                                                       iax2_getformatname_multiple(iaxs[fr->callno]->capability, &cap_buf));
                                        }
                                } else {
+                                       struct ast_format_cap *native = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
+
                                        ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED);
                                        iax2_lock_owner(fr->callno);
-                                       if (iaxs[fr->callno] && iaxs[fr->callno]->owner) {
-                                               char tmp[256];
+                                       if (iaxs[fr->callno] && iaxs[fr->callno]->owner && native) {
+                                               struct ast_str *cap_buf = ast_str_alloca(64);
+
                                                /* Switch us to use a compatible format */
-                                               ast_format_cap_from_old_bitfield(ast_channel_nativeformats(iaxs[fr->callno]->owner), iaxs[fr->callno]->peerformat);
-                                               ast_verb(3, "Format for call is %s\n", ast_getformatname_multiple(tmp, sizeof(tmp), ast_channel_nativeformats(iaxs[fr->callno]->owner)));
+                                               iax2_codec_pref_best_bitfield2cap(
+                                                       iaxs[fr->callno]->peerformat, &iaxs[fr->callno]->rprefs,
+                                                       native);
+                                               ast_channel_nativeformats_set(iaxs[fr->callno]->owner, native);
+                                               ast_verb(3, "Format for call is %s\n", ast_format_cap_get_names(ast_channel_nativeformats(iaxs[fr->callno]->owner), &cap_buf));
 
                                                /* Setup read/write formats properly. */
-                                               if (ast_channel_writeformat(iaxs[fr->callno]->owner)->id)
+                                               if (ast_channel_writeformat(iaxs[fr->callno]->owner))
                                                        ast_set_write_format(iaxs[fr->callno]->owner, ast_channel_writeformat(iaxs[fr->callno]->owner));
-                                               if (ast_channel_readformat(iaxs[fr->callno]->owner)->id)
+                                               if (ast_channel_readformat(iaxs[fr->callno]->owner))
                                                        ast_set_read_format(iaxs[fr->callno]->owner, ast_channel_readformat(iaxs[fr->callno]->owner));
                                                ast_channel_unlock(iaxs[fr->callno]->owner);
                                        }
+
+                                       ao2_cleanup(native);
                                }
                                if (iaxs[fr->callno]) {
                                        AST_LIST_LOCK(&dpcache);
@@ -10902,7 +11095,7 @@ static int socket_process_helper(struct iax2_thread *thread)
                                        peer = iaxs[fr->callno]->peerpoke;
                                        if ((peer->lastms < 0)  || (peer->historicms > peer->maxms)) {
                                                if (iaxs[fr->callno]->pingtime <= peer->maxms) {
-                                                       ast_log(LOG_NOTICE, "Peer '%s' is now REACHABLE! Time: %d\n", peer->name, iaxs[fr->callno]->pingtime);
+                                                       ast_log(LOG_NOTICE, "Peer '%s' is now REACHABLE! Time: %u\n", peer->name, iaxs[fr->callno]->pingtime);
                                                        ast_endpoint_set_state(peer->endpoint, AST_ENDPOINT_ONLINE);
                                                        blob = ast_json_pack("{s: s, s: i}",
                                                                "peer_status", "Reachable",
@@ -10911,7 +11104,7 @@ static int socket_process_helper(struct iax2_thread *thread)
                                                }
                                        } else if ((peer->historicms > 0) && (peer->historicms <= peer->maxms)) {
                                                if (iaxs[fr->callno]->pingtime > peer->maxms) {
-                                                       ast_log(LOG_NOTICE, "Peer '%s' is now TOO LAGGED (%d ms)!\n", peer->name, iaxs[fr->callno]->pingtime);
+                                                       ast_log(LOG_NOTICE, "Peer '%s' is now TOO LAGGED (%u ms)!\n", peer->name, iaxs[fr->callno]->pingtime);
                                                        ast_endpoint_set_state(peer->endpoint, AST_ENDPOINT_ONLINE);
                                                        blob = ast_json_pack("{s: s, s: i}",
                                                                "peer_status", "Lagged",
@@ -11035,11 +11228,11 @@ static int socket_process_helper(struct iax2_thread *thread)
                                                strcpy(caller_pref_buf, "disabled");
                                                strcpy(host_pref_buf, "disabled");
                                        } else {
-                                               struct ast_format tmpfmt;
+                                               struct ast_format *tmpfmt;
                                                using_prefs = "mine";
                                                if (ies.codec_prefs)
-                                                       ast_codec_pref_convert(&iaxs[fr->callno]->rprefs, ies.codec_prefs, 32, 0);
-                                               if (ast_codec_pref_index(&iaxs[fr->callno]->rprefs, 0, &tmpfmt)) {
+                                                       iax2_codec_pref_convert(&iaxs[fr->callno]->rprefs, ies.codec_prefs, 32, 0);
+                                               if (iax2_codec_pref_index(&iaxs[fr->callno]->rprefs, 0, &tmpfmt)) {
                                                        if (ast_test_flag64(iaxs[fr->callno], IAX_CODEC_USER_FIRST)) {
                                                                pref = iaxs[fr->callno]->rprefs;
                                                                using_prefs = "caller";
@@ -11048,16 +11241,19 @@ static int socket_process_helper(struct iax2_thread *thread)
                                                        }
                                                } else /* if no codec_prefs IE do it the old way */
                                                        pref = iaxs[fr->callno]->prefs;
-                                               format = iax2_codec_choose(&pref, iaxs[fr->callno]->capability & iaxs[fr->callno]->peercapability, 0);
-                                               ast_codec_pref_string(&iaxs[fr->callno]->rprefs, caller_pref_buf, sizeof(caller_pref_buf) - 1);
-                                               ast_codec_pref_string(&iaxs[fr->callno]->prefs, host_pref_buf, sizeof(host_pref_buf) - 1);
+                                               format = iax2_codec_choose(&pref, iaxs[fr->callno]->capability & iaxs[fr->callno]->peercapability);
+                                               iax2_codec_pref_string(&iaxs[fr->callno]->rprefs, caller_pref_buf, sizeof(caller_pref_buf) - 1);
+                                               iax2_codec_pref_string(&iaxs[fr->callno]->prefs, host_pref_buf, sizeof(host_pref_buf) - 1);
                                        }
                                        if (!format) {
-                                               char tmp1[256], tmp2[256], tmp3[256];
+                                               struct ast_str *cap_buf = ast_str_alloca(64);
+                                               struct ast_str *peer_buf = ast_str_alloca(64);
+                                               struct ast_str *peer_form_buf = ast_str_alloca(64);
+
                                                if(!ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP)) {
                                                        ast_debug(1, "We don't do requested format %s, falling back to peer capability '%s'\n",
                                                                iax2_getformatname(iaxs[fr->callno]->peerformat),
-                                                               iax2_getformatname_multiple(tmp1, sizeof(tmp1), iaxs[fr->callno]->peercapability));
+                                                               iax2_getformatname_multiple(iaxs[fr->callno]->peercapability, &peer_buf));
                                                        format = iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability;
                                                }
                                                if (!format) {
@@ -11065,14 +11261,14 @@ static int socket_process_helper(struct iax2_thread *thread)
                                                                if (ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP)) {
                                                                        ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested '%s' incompatible with our capability '%s'.\n",
                                                                                        ast_sockaddr_stringify(&addr),
-                                                                               iax2_getformatname_multiple(tmp1, sizeof(tmp1), iaxs[fr->callno]->peerformat),
-                                                                               iax2_getformatname_multiple(tmp2, sizeof(tmp2), iaxs[fr->callno]->capability));
+                                                                               iax2_getformatname_multiple(iaxs[fr->callno]->peerformat, &peer_form_buf),
+                                                                               iax2_getformatname_multiple(iaxs[fr->callno]->capability, &cap_buf));
                                                                } else {
                                                                        ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability '%s'/'%s' incompatible with our capability '%s'.\n",
                                                                                ast_sockaddr_stringify(&addr),
-                                                                               iax2_getformatname_multiple(tmp1, sizeof(tmp1), iaxs[fr->callno]->peerformat),
-                                                                               iax2_getformatname_multiple(tmp2, sizeof(tmp2), iaxs[fr->callno]->peercapability),
-                                                                               iax2_getformatname_multiple(tmp3, sizeof(tmp3), iaxs[fr->callno]->capability));
+                                                                               iax2_getformatname_multiple(iaxs[fr->callno]->peerformat, &peer_form_buf),
+                                                                               iax2_getformatname_multiple(iaxs[fr->callno]->peercapability, &peer_buf),
+                                                                               iax2_getformatname_multiple(iaxs[fr->callno]->capability, &cap_buf));
                                                                }
                                                        }
                                                        memset(&ied0, 0, sizeof(ied0));
@@ -11091,14 +11287,15 @@ static int socket_process_helper(struct iax2_thread *thread)
                                                                if(ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOPREFS)) {
                                                                        using_prefs = ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP) ? "reqonly" : "disabled";
                                                                        memset(&pref, 0, sizeof(pref));
-                                                                       format = ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP) ?
-                                                                               iaxs[fr->callno]->peerformat : iax2_best_codec(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
+                                                                       format = ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP)
+                                                                               ? iaxs[fr->callno]->peerformat
+                                                                               : iax2_format_compatibility_best(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
                                                                        strcpy(caller_pref_buf,"disabled");
                                                                        strcpy(host_pref_buf,"disabled");
                                                                } else {
-                                                                       struct ast_format tmpfmt;
+                                                                       struct ast_format *tmpfmt;
                                                                        using_prefs = "mine";
-                                                                       if (ast_codec_pref_index(&iaxs[fr->callno]->rprefs, 0, &tmpfmt)) {
+                                                                       if (iax2_codec_pref_index(&iaxs[fr->callno]->rprefs, 0, &tmpfmt)) {
                                                                                /* Do the opposite of what we tried above. */
                                                                                if (ast_test_flag64(iaxs[fr->callno], IAX_CODEC_USER_FIRST)) {
                                                                                        pref = iaxs[fr->callno]->prefs;
@@ -11106,27 +11303,30 @@ static int socket_process_helper(struct iax2_thread *thread)
                                                                                        pref = iaxs[fr->callno]->rprefs;
                                                                                        using_prefs = "caller";
                                                                                }
-                                                                               format = iax2_codec_choose(&pref, iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability, 1);
+                                                                               format = iax2_codec_choose(&pref, iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
                                                                        } else /* if no codec_prefs IE do it the old way */
-                                                                               format = iax2_best_codec(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
+                                                                               format = iax2_format_compatibility_best(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
                                                                }
                                                        }
                                                        if (!format) {
-                                                               char tmp1[256], tmp2[256], tmp3[256];
+                                                               struct ast_str *cap_buf = ast_str_alloca(64);
+                                                               struct ast_str *peer_buf = ast_str_alloca(64);
+                                                               struct ast_str *peer_form_buf = ast_str_alloca(64);
+
                                                                ast_log(LOG_ERROR, "No best format in %s???\n",
-                                                                       iax2_getformatname_multiple(tmp1, sizeof(tmp1), iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability));
+                                                                       iax2_getformatname_multiple(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability, &cap_buf));
                                                                if (authdebug) {
                                                                        if (ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP)) {
                                                                                ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested '%s' incompatible with our capability '%s'.\n",
                                                                                        ast_sockaddr_stringify(&addr),
-                                                                                       iax2_getformatname_multiple(tmp1, sizeof(tmp1), iaxs[fr->callno]->peerformat),
-                                                                                       iax2_getformatname_multiple(tmp2, sizeof(tmp2), iaxs[fr->callno]->capability));
+                                                                                       iax2_getformatname_multiple(iaxs[fr->callno]->peerformat, &peer_form_buf),
+                                                                                       iax2_getformatname_multiple(iaxs[fr->callno]->capability, &cap_buf));
                                                                        } else {
                                                                                ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability '%s'/'%s' incompatible with our capability '%s'.\n",
                                                                                        ast_sockaddr_stringify(&addr),
-                                                                                       iax2_getformatname_multiple(tmp1, sizeof(tmp1), iaxs[fr->callno]->peerformat),
-                                                                                       iax2_getformatname_multiple(tmp2, sizeof(tmp2), iaxs[fr->callno]->peercapability),
-                                                                                       iax2_getformatname_multiple(tmp3, sizeof(tmp3), iaxs[fr->callno]->capability));
+                                                                                       iax2_getformatname_multiple(iaxs[fr->callno]->peerformat, &peer_form_buf),
+                                                                                       iax2_getformatname_multiple(iaxs[fr->callno]->peercapability, &peer_buf),
+                                                                                       iax2_getformatname_multiple(iaxs[fr->callno]->capability, &cap_buf));
                                                                        }
                                                                }
                                                                memset(&ied0, 0, sizeof(ied0));
@@ -11166,9 +11366,11 @@ static int socket_process_helper(struct iax2_thread *thread)
                                                                                        using_prefs);
 
                                                        ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED);
-                                                       if (!(c = ast_iax2_new(fr->callno, AST_STATE_RING, format, NULL, 1)))
+                                                       c = ast_iax2_new(fr->callno, AST_STATE_RING, format,
+                                                               &iaxs[fr->callno]->rprefs, NULL, NULL, 1);
+                                                       if (!c) {
                                                                iax2_destroy(fr->callno);
-                                                       else if (ies.vars) {
+                                                       } else if (ies.vars) {
                                                                struct ast_datastore *variablestore;
                                                                struct ast_variable *var, *prev = NULL;
                                                                AST_LIST_HEAD(, ast_var_t) *varlist;
@@ -11233,16 +11435,19 @@ immediatedial:
                                                        break;
                                                }
                                        } else {
-                                               char tmp[256];
+                                               struct ast_str *cap_buf = ast_str_alloca(64);
                                                ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED);
                                                ast_verb(3, "Accepting DIAL from %s, formats = %s\n",
                                                                ast_sockaddr_stringify(&addr),
-                                                               iax2_getformatname_multiple(tmp, sizeof(tmp), iaxs[fr->callno]->peerformat));
+                                                               iax2_getformatname_multiple(iaxs[fr->callno]->peerformat, &cap_buf));
                                                ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED);
                                                send_command(iaxs[fr->callno], AST_FRAME_CONTROL, AST_CONTROL_PROGRESS, 0, NULL, 0, -1);
-                                               if (!(c = ast_iax2_new(fr->callno, AST_STATE_RING, iaxs[fr->callno]->peerformat, NULL, 1)))
+                                               c = ast_iax2_new(fr->callno, AST_STATE_RING,
+                                                       iaxs[fr->callno]->peerformat, &iaxs[fr->callno]->rprefs,
+                                                       NULL, NULL, 1);
+                                               if (!c) {
                                                        iax2_destroy(fr->callno);
-                                               else if (ies.vars) {
+                                               } else if (ies.vars) {
                                                        struct ast_datastore *variablestore;
                                                        struct ast_variable *var, *prev = NULL;
                                                        AST_LIST_HEAD(, ast_var_t) *varlist;
@@ -11557,9 +11762,9 @@ immediatedial:
                f.frametype = AST_FRAME_VIDEO;
                if (iaxs[fr->callno]->videoformat > 0) {
                        if (ntohs(vh->ts) & 0x8000LL) {
-                               ast_format_set_video_mark(&f.subclass.format);
+                               f.subclass.frame_ending = 1;
                        }
-                       ast_format_from_old_bitfield(&f.subclass.format, iaxs[fr->callno]->videoformat);
+                       f.subclass.format = ast_format_compatibility_bitfield2format(iaxs[fr->callno]->videoformat);
                } else {
                        ast_log(LOG_WARNING, "Received mini frame before first full video frame\n");
                        iax2_vnak(fr->callno);
@@ -11582,7 +11787,7 @@ immediatedial:
                /* A mini frame */
                f.frametype = AST_FRAME_VOICE;
                if (iaxs[fr->callno]->voiceformat > 0)
-                       ast_format_from_old_bitfield(&f.subclass.format, iaxs[fr->callno]->voiceformat);
+                       f.subclass.format = ast_format_compatibility_bitfield2format(iaxs[fr->callno]->voiceformat);
                else {
                        ast_debug(1, "Received mini frame before first full voice frame\n");
                        iax2_vnak(fr->callno);
@@ -11609,23 +11814,58 @@ immediatedial:
                fr->ts = (iaxs[fr->callno]->last & 0xFFFF0000L) | ntohs(mh->ts);
                /* FIXME? Surely right here would be the right place to undo timestamp wraparound? */
        }
+
        /* Don't pass any packets until we're started */
-       if (!ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED)) {
+       if (!iaxs[fr->callno]
+               || !ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED)) {
                ast_variables_destroy(ies.vars);
                ast_mutex_unlock(&iaxsl[fr->callno]);
                return 1;
        }
-       /* Don't allow connected line updates unless we are configured to */
-       if (f.frametype == AST_FRAME_CONTROL && f.subclass.integer == AST_CONTROL_CONNECTED_LINE) {
-               struct ast_party_connected_line connected;
 
-               if (!ast_test_flag64(iaxs[fr->callno], IAX_RECVCONNECTEDLINE)) {
+       if (f.frametype == AST_FRAME_CONTROL) {
+               if (!iax2_is_control_frame_allowed(f.subclass.integer)) {
+                       /* Control frame not allowed to come from the wire. */
+                       ast_debug(2, "Callno %d: Blocked receiving control frame %d.\n",
+                               fr->callno, f.subclass.integer);
                        ast_variables_destroy(ies.vars);
                        ast_mutex_unlock(&iaxsl[fr->callno]);
                        return 1;
                }
+               if (f.subclass.integer == AST_CONTROL_CONNECTED_LINE
+                       || f.subclass.integer == AST_CONTROL_REDIRECTING) {
+                       if (iaxs[fr->callno]
+                               && !ast_test_flag64(iaxs[fr->callno], IAX_RECVCONNECTEDLINE)) {
+                               /* We are not configured to allow receiving these updates. */
+                               ast_debug(2, "Callno %d: Config blocked receiving control frame %d.\n",
+                                       fr->callno, f.subclass.integer);
+                               ast_variables_destroy(ies.vars);
+                               ast_mutex_unlock(&iaxsl[fr->callno]);
+                               return 1;
+                       }
+               }
 
-               /* Initialize defaults */
+               iax2_lock_owner(fr->callno);
+               if (iaxs[fr->callno] && iaxs[fr->callno]->owner) {
+                       if (f.subclass.integer == AST_CONTROL_BUSY) {
+                               ast_channel_hangupcause_set(iaxs[fr->callno]->owner, AST_CAUSE_BUSY);
+                       } else if (f.subclass.integer == AST_CONTROL_CONGESTION) {
+                               ast_channel_hangupcause_set(iaxs[fr->callno]->owner, AST_CAUSE_CONGESTION);
+                       }
+                       ast_channel_unlock(iaxs[fr->callno]->owner);
+               }
+       }
+
+       if (f.frametype == AST_FRAME_CONTROL
+               && f.subclass.integer == AST_CONTROL_CONNECTED_LINE
+               && iaxs[fr->callno]) {
+               struct ast_party_connected_line connected;
+
+               /*
+                * Process a received connected line update.
+                *
+                * Initialize defaults.
+                */
                ast_party_connected_line_init(&connected);
                connected.id.number.presentation = iaxs[fr->callno]->calling_pres;
                connected.id.name.presentation = iaxs[fr->callno]->calling_pres;
@@ -11648,15 +11888,16 @@ immediatedial:
                }
                ast_party_connected_line_free(&connected);
        }
+
        /* Common things */
        f.src = "IAX2";
        f.mallocd = 0;
        f.offset = 0;
        f.len = 0;
        if (f.datalen && (f.frametype == AST_FRAME_VOICE)) {
-               f.samples = ast_codec_get_samples(&f);
+               f.samples = ast_codec_samples_count(&f);
                /* We need to byteswap incoming slinear samples from network byte order */
-               if (f.subclass.format.id == AST_FORMAT_SLINEAR)
+               if (ast_format_cmp(f.subclass.format, ast_format_slin) == AST_FORMAT_CMP_EQUAL)
                        ast_frame_byteswap_be(&f);
        } else
                f.samples = 0;
@@ -11668,20 +11909,22 @@ immediatedial:
                fr->outoforder = 0;
        } else {
                if (iaxdebug && iaxs[fr->callno]) {
-                       ast_debug(1, "Received out of order packet... (type=%d, subclass %d, ts = %d, last = %d)\n", f.frametype, f.subclass.integer, fr->ts, iaxs[fr->callno]->last);
+                       ast_debug(1, "Received out of order packet... (type=%u, subclass %d, ts = %u, last = %u)\n", f.frametype, f.subclass.integer, fr->ts, iaxs[fr->callno]->last);
                }
-               fr->outoforder = -1;
+               fr->outoforder = 1;
        }
        fr->cacheable = ((f.frametype == AST_FRAME_VOICE) || (f.frametype == AST_FRAME_VIDEO));
-       duped_fr = iaxfrdup2(fr);
-       if (duped_fr) {
-               schedule_delivery(duped_fr, updatehistory, 0, &fr->ts);
+       if (iaxs[fr->callno]) {
+               duped_fr = iaxfrdup2(fr);
+               if (duped_fr) {
+                       schedule_delivery(duped_fr, updatehistory, 0, &fr->ts);
+               }
        }
        if (iaxs[fr->callno] && iaxs[fr->callno]->last < fr->ts) {
                iaxs[fr->callno]->last = fr->ts;
 #if 1
                if (iaxdebug)
-                       ast_debug(1, "For call=%d, set last=%d\n", fr->callno, fr->ts);
+                       ast_debug(1, "For call=%d, set last=%u\n", fr->callno, fr->ts);
 #endif
        }
 
@@ -11693,11 +11936,9 @@ immediatedial:
 
 static int socket_process(struct iax2_thread *thread)
 {
-       struct ast_callid *callid;
        int res = socket_process_helper(thread);
-       if ((callid = ast_read_threadstorage_callid())) {
+       if (ast_read_threadstorage_callid()) {
                ast_callid_threadassoc_remove();
-               callid = ast_callid_unref(callid);
        }
        return res;
 }
@@ -11892,6 +12133,9 @@ static int iax2_do_register(struct iax2_registry *reg)
                        (5 * reg->refresh / 6) * 1000, iax2_do_register_s, reg);
                return -1;
        }
+       if (!ast_sockaddr_port(&reg->addr) && reg->port) {
+               ast_sockaddr_set_port(&reg->addr, reg->port);
+       }
 
        if (!reg->callno) {
 
@@ -12092,6 +12336,7 @@ static int iax2_poke_peer_cb(void *obj, void *arg, int flags)
 static int iax2_poke_peer(struct iax2_peer *peer, int heldcall)
 {
        int callno;
+       int poke_timeout;
 
        if (!peer->maxms || (ast_sockaddr_isnull(&peer->addr) && !peer->dnsmgr)) {
                /* IF we have no IP without dnsmgr, or this isn't to be monitored, return
@@ -12115,15 +12360,11 @@ static int iax2_poke_peer(struct iax2_peer *peer, int heldcall)
        callno = peer->callno = find_callno(0, 0, &peer->addr, NEW_FORCE, peer->sockfd, 0);
        if (heldcall)
                ast_mutex_lock(&iaxsl[heldcall]);
-       if (peer->callno < 1) {
+       if (callno < 1) {
                ast_log(LOG_WARNING, "Unable to allocate call for poking peer '%s'\n", peer->name);
                return -1;
        }
 
-       /* Speed up retransmission times for this qualify call */
-       iaxs[peer->callno]->pingtime = peer->maxms / 4 + 1;
-       iaxs[peer->callno]->peerpoke = peer;
-
        if (peer->pokeexpire > -1) {
                if (!AST_SCHED_DEL(sched, peer->pokeexpire)) {
                        peer->pokeexpire = -1;
@@ -12131,12 +12372,24 @@ static int iax2_poke_peer(struct iax2_peer *peer, int heldcall)
                }
        }
 
+       if (peer->lastms < 0){
+               /* If the host is already unreachable then use time less than the unreachable
+                * interval. 5/6 is arbitrary multiplier to get value less than
+                * peer->pokefreqnotok. Value less than peer->pokefreqnotok is used to expire
+                * current POKE before starting new POKE (which is scheduled after
+                * peer->pokefreqnotok). */
+               poke_timeout = peer->pokefreqnotok * 5  / 6;
+       } else {
+               /* If the host is reachable, use timeout large enough to allow for multiple
+                * POKE retries. Limit this value to less than peer->pokefreqok. 5/6 is arbitrary
+                * multiplier to get value less than peer->pokefreqok. Value less than
+                * peer->pokefreqok is used to expire current POKE before starting new POKE
+                * (which is scheduled after peer->pokefreqok). */
+               poke_timeout = MIN(MAX_RETRY_TIME * 2 + peer->maxms, peer->pokefreqok * 5  / 6);
+       }
+
        /* Queue up a new task to handle no reply */
-       /* If the host is already unreachable then use the unreachable interval instead */
-       if (peer->lastms < 0)
-               peer->pokeexpire = iax2_sched_add(sched, peer->pokefreqnotok, iax2_poke_noanswer, peer_ref(peer));
-       else
-               peer->pokeexpire = iax2_sched_add(sched, DEFAULT_MAXMS * 2, iax2_poke_noanswer, peer_ref(peer));
+       peer->pokeexpire = iax2_sched_add(sched, poke_timeout, iax2_poke_noanswer, peer_ref(peer));
 
        if (peer->pokeexpire == -1)
                peer_unref(peer);
@@ -12148,6 +12401,11 @@ static int iax2_poke_peer(struct iax2_peer *peer, int heldcall)
                        .buf = { 0 },
                        .pos = 0,
                };
+
+               /* Speed up retransmission times for this qualify call */
+               iaxs[callno]->pingtime = peer->maxms / 8;
+               iaxs[callno]->peerpoke = peer;
+
                add_empty_calltoken_ie(iaxs[callno], &ied); /* this _MUST_ be the last ie added */
                send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_POKE, 0, ied.buf, ied.pos, -1);
        }
@@ -12166,7 +12424,7 @@ static void free_context(struct iax2_context *con)
        }
 }
 
-static struct ast_channel *iax2_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause)
+static struct ast_channel *iax2_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
 {
        int callno;
        int res;
@@ -12175,7 +12433,7 @@ static struct ast_channel *iax2_request(const char *type, struct ast_format_cap
        struct parsed_dial_string pds;
        struct create_addr_info cai;
        char *tmpstr;
-       struct ast_callid *callid;
+       ast_callid callid;
 
        memset(&pds, 0, sizeof(pds));
        tmpstr = ast_strdupa(data);
@@ -12190,7 +12448,7 @@ static struct ast_channel *iax2_request(const char *type, struct ast_format_cap
        memset(&cai, 0, sizeof(cai));
        cai.capability = iax2_capability;
 
-       ast_copy_flags64(&cai, &globalflags, IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE);
+       ast_copy_flags64(&cai, &globalflags, IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE);
 
        /* Populate our address from the given */
        if (create_addr(pds.peer, NULL, &addr, &cai)) {
@@ -12212,7 +12470,7 @@ static struct ast_channel *iax2_request(const char *type, struct ast_format_cap
        }
 
        /* If this is a trunk, update it now */
-       ast_copy_flags64(iaxs[callno], &cai, IAX_TRUNK | IAX_SENDANI | IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE);
+       ast_copy_flags64(iaxs[callno], &cai, IAX_TRUNK | IAX_SENDANI | IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE);
        if (ast_test_flag64(&cai, IAX_TRUNK)) {
                int new_callno;
                if ((new_callno = make_trunk(callno, 1)) != -1)
@@ -12227,41 +12485,59 @@ static struct ast_channel *iax2_request(const char *type, struct ast_format_cap
                ast_string_field_set(iaxs[callno], host, pds.peer);
        }
 
-       c = ast_iax2_new(callno, AST_STATE_DOWN, cai.capability, requestor ? ast_channel_linkedid(requestor) : NULL, cai.found);
+       c = ast_iax2_new(callno, AST_STATE_DOWN, cai.capability, &cai.prefs, assignedids,
+               requestor, cai.found);
 
        ast_mutex_unlock(&iaxsl[callno]);
 
        if (c) {
                struct ast_format_cap *joint;
+               struct ast_format *format;
                if (callid) {
+                       ast_channel_lock(c);
                        ast_channel_callid_set(c, callid);
+                       ast_channel_unlock(c);
                }
 
-               /* Choose a format we can live with */
-               if ((joint = ast_format_cap_joint(ast_channel_nativeformats(c), cap))) {
-                       ast_format_cap_copy(ast_channel_nativeformats(c), joint);
-                       joint = ast_format_cap_destroy(joint);
-               } else {
-                       struct ast_format best_fmt_cap;
-                       struct ast_format best_fmt_native;
+               joint = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
+               if (!joint) {
+                       ast_hangup(c);
+                       return NULL;
+               }
+
+               ast_format_cap_get_compatible(ast_channel_nativeformats(c), cap, joint);
+
+               /* If there is no joint format find one through translation */
+               if (!ast_format_cap_count(joint)) {
+                       struct ast_format *best_fmt_cap = NULL;
+                       struct ast_format *best_fmt_native = NULL;
+
                        res = ast_translator_best_choice(cap, ast_channel_nativeformats(c), &best_fmt_cap, &best_fmt_native);
                        if (res < 0) {
-                               char tmp[256];
-                               char tmp2[256];
+                               struct ast_str *native_cap_buf = ast_str_alloca(256);
+                               struct ast_str *cap_buf = ast_str_alloca(256);
+
                                ast_log(LOG_WARNING, "Unable to create translator path for %s to %s on %s\n",
-                                       ast_getformatname_multiple(tmp, sizeof(tmp), ast_channel_nativeformats(c)), ast_getformatname_multiple(tmp2, sizeof(tmp2), cap), ast_channel_name(c));
+                                       ast_format_cap_get_names(ast_channel_nativeformats(c), &native_cap_buf),
+                                       ast_format_cap_get_names(cap, &cap_buf),
+                                       ast_channel_name(c));
                                ast_hangup(c);
+                               ao2_ref(joint, -1);
                                return NULL;
                        }
-                       ast_format_cap_set(ast_channel_nativeformats(c), &best_fmt_native);
+                       ast_format_cap_append(joint, best_fmt_native, 0);
+                       ao2_ref(best_fmt_cap, -1);
+                       ao2_ref(best_fmt_native, -1);
                }
-               ast_best_codec(ast_channel_nativeformats(c), ast_channel_readformat(c));
-               ast_format_copy(ast_channel_writeformat(c), ast_channel_readformat(c));
-       }
+               ast_channel_nativeformats_set(c, joint);
+               format = ast_format_cap_get_format(ast_channel_nativeformats(c), 0);
+               ast_channel_set_readformat(c, format);
+               ast_channel_set_writeformat(c, format);
 
-       if (callid) {
-               ast_callid_unref(callid);
+               ao2_ref(joint, -1);
+               ao2_ref(format, -1);
        }
+
        return c;
 }
 
@@ -12511,7 +12787,7 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, st
 
        if (peer) {
                if (firstpass) {
-                       ast_copy_flags64(peer, &globalflags, IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE | IAX_FORCE_ENCRYPT);
+                       ast_copy_flags64(peer, &globalflags, IAX_USEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE | IAX_FORCE_ENCRYPT);
                        peer->encmethods = iax2_encryption;
                        peer->adsi = adsi;
                        ast_string_field_set(peer, secret, "");
@@ -12521,7 +12797,7 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, st
                                ast_sockaddr_set_port(&peer->addr, IAX_DEFAULT_PORTNO);
                                peer->expiry = min_reg_expire;
                        }
-                       peer->prefs = prefs;
+                       peer->prefs = prefs_global;
                        peer->capability = iax2_capability;
                        peer->smoothing = 0;
                        peer->pokefreqok = DEFAULT_FREQ_OK;
@@ -12549,7 +12825,15 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, st
                                ast_string_field_set(peer, mailbox, v->value);
                        } else if (!strcasecmp(v->name, "hasvoicemail")) {
                                if (ast_true(v->value) && ast_strlen_zero(peer->mailbox)) {
-                                       ast_string_field_set(peer, mailbox, name);
+                                       /*
+                                        * hasvoicemail is a users.conf legacy voicemail enable method.
+                                        * hasvoicemail is only going to work for app_voicemail mailboxes.
+                                        */
+                                       if (strchr(name, '@')) {
+                                               ast_string_field_set(peer, mailbox, name);
+                                       } else {
+                                               ast_string_field_build(peer, mailbox, "%s@default", name);
+                                       }
                                }
                        } else if (!strcasecmp(v->name, "mohinterpret")) {
                                ast_string_field_set(peer, mohinterpret, v->value);
@@ -12590,8 +12874,6 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, st
                                        ast_set_flags_to64(peer, IAX_NOTRANSFER|IAX_TRANSFERMEDIA, IAX_NOTRANSFER);
                        } else if (!strcasecmp(v->name, "jitterbuffer")) {
                                ast_set2_flag64(peer, ast_true(v->value), IAX_USEJITTERBUF);
-                       } else if (!strcasecmp(v->name, "forcejitterbuffer")) {
-                               ast_set2_flag64(peer, ast_true(v->value), IAX_FORCEJITTERBUF);
                        } else if (!strcasecmp(v->name, "host")) {
                                if (!strcasecmp(v->value, "dynamic")) {
                                        /* They'll register with us */
@@ -12758,21 +13040,14 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, st
        }
 
        if (!ast_strlen_zero(peer->mailbox)) {
-               char *mailbox, *context;
-               struct ast_str *uniqueid = ast_str_alloca(AST_MAX_MAILBOX_UNIQUEID);
                struct stasis_topic *mailbox_specific_topic;
 
-               context = mailbox = ast_strdupa(peer->mailbox);
-               strsep(&context, "@");
-               if (ast_strlen_zero(context)) {
-                       context = "default";
-               }
-
-               ast_str_set(&uniqueid, 0, "%s@%s", mailbox, context);
-
-               mailbox_specific_topic = ast_mwi_topic(ast_str_buffer(uniqueid));
+               mailbox_specific_topic = ast_mwi_topic(peer->mailbox);
                if (mailbox_specific_topic) {
-                       peer->mwi_event_sub = stasis_subscribe(mailbox_specific_topic, mwi_event_cb, NULL);
+                       /* The MWI subscriptions exist just so the core knows we care about those
+                        * mailboxes.  However, we just grab the events out of the cache when it
+                        * is time to send MWI, since it is only sent with a REGACK. */
+                       peer->mwi_event_sub = stasis_subscribe_pool(mailbox_specific_topic, stasis_subscription_cb_noop, NULL);
                }
        }
 
@@ -12840,14 +13115,14 @@ static struct iax2_user *build_user(const char *name, struct ast_variable *v, st
                        }
                        user->maxauthreq = maxauthreq;
                        user->curauthreq = oldcurauthreq;
-                       user->prefs = prefs;
+                       user->prefs = prefs_global;
                        user->capability = iax2_capability;
                        user->encmethods = iax2_encryption;
                        user->adsi = adsi;
                        user->calltoken_required = CALLTOKEN_DEFAULT;
                        ast_string_field_set(user, name, name);
                        ast_string_field_set(user, language, language);
-                       ast_copy_flags64(user, &globalflags, IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_CODEC_USER_FIRST | IAX_CODEC_NOPREFS | IAX_CODEC_NOCAP | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE | IAX_FORCE_ENCRYPT);
+                       ast_copy_flags64(user, &globalflags, IAX_USEJITTERBUF | IAX_CODEC_USER_FIRST | IAX_CODEC_NOPREFS | IAX_CODEC_NOCAP | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE | IAX_FORCE_ENCRYPT);
                        ast_clear_flag64(user, IAX_HASCALLERID);
                        ast_string_field_set(user, cid_name, "");
                        ast_string_field_set(user, cid_num, "");
@@ -12929,8 +13204,6 @@ static struct iax2_user *build_user(const char *name, struct ast_variable *v, st
                                ast_set2_flag64(user, ast_true(v->value), IAX_IMMEDIATE);
                        } else if (!strcasecmp(v->name, "jitterbuffer")) {
                                ast_set2_flag64(user, ast_true(v->value), IAX_USEJITTERBUF);
-                       } else if (!strcasecmp(v->name, "forcejitterbuffer")) {
-                               ast_set2_flag64(user, ast_true(v->value), IAX_FORCEJITTERBUF);
                        } else if (!strcasecmp(v->name, "dbsecret")) {
                                ast_string_field_set(user, dbsecret, v->value);
                        } else if (!strcasecmp(v->name, "secret")) {
@@ -13143,7 +13416,7 @@ static void set_config_destroy(void)
        amaflags = 0;
        delayreject = 0;
        ast_clear_flag64((&globalflags), IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF |
-               IAX_FORCEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE);
+               IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE);
        delete_users();
        ao2_callback(callno_limits, OBJ_NODATA, addr_range_delme_cb, NULL);
        ao2_callback(calltoken_ignores, OBJ_NODATA, addr_range_delme_cb, NULL);
@@ -13153,7 +13426,7 @@ static void set_config_destroy(void)
 static int set_config(const char *config_file, int reload, int forced)
 {
        struct ast_config *cfg, *ucfg;
-       iax2_format capability = iax2_capability;
+       iax2_format capability;
        struct ast_variable *v;
        char *cat;
        const char *utype;
@@ -13168,9 +13441,7 @@ static int set_config(const char *config_file, int reload, int forced)
        struct ast_netsock *ns;
        struct ast_flags config_flags = { (reload && !forced) ? CONFIG_FLAG_FILEUNCHANGED : 0 };
        struct ast_sockaddr bindaddr;
-#if 0
-       static unsigned short int last_port=0;
-#endif
+       struct iax2_codec_pref prefs_new;
 
        cfg = ast_config_load(config_file, config_flags);
 
@@ -13211,8 +13482,8 @@ static int set_config(const char *config_file, int reload, int forced)
 
        ast_sockaddr_parse(&bindaddr, "0.0.0.0:0", 0);
 
-       /* Reset global codec prefs */
-       memset(&prefs, 0 , sizeof(struct ast_codec_pref));
+       /* Setup new codec prefs */
+       capability = iax2_codec_pref_from_bitfield(&prefs_new, IAX_CAPABILITY_FULLBANDWIDTH);
 
        /* Reset Global Flags */
        memset(&globalflags, 0, sizeof(globalflags));
@@ -13376,8 +13647,6 @@ static int set_config(const char *config_file, int reload, int forced)
                        }
                } else if (!strcasecmp(v->name, "jitterbuffer"))
                        ast_set2_flag64((&globalflags), ast_true(v->value), IAX_USEJITTERBUF);
-               else if (!strcasecmp(v->name, "forcejitterbuffer"))
-                       ast_set2_flag64((&globalflags), ast_true(v->value), IAX_FORCEJITTERBUF);
                else if (!strcasecmp(v->name, "delayreject"))
                        delayreject = ast_true(v->value);
                else if (!strcasecmp(v->name, "allowfwdownload"))
@@ -13437,17 +13706,21 @@ static int set_config(const char *config_file, int reload, int forced)
                        }
                } else if (!strcasecmp(v->name, "bandwidth")) {
                        if (!strcasecmp(v->value, "low")) {
-                               capability = IAX_CAPABILITY_LOWBANDWIDTH;
+                               capability = iax2_codec_pref_from_bitfield(&prefs_new,
+                                       IAX_CAPABILITY_LOWBANDWIDTH);
                        } else if (!strcasecmp(v->value, "medium")) {
-                               capability = IAX_CAPABILITY_MEDBANDWIDTH;
+                               capability = iax2_codec_pref_from_bitfield(&prefs_new,
+                                       IAX_CAPABILITY_MEDBANDWIDTH);
                        } else if (!strcasecmp(v->value, "high")) {
-                               capability = IAX_CAPABILITY_FULLBANDWIDTH;
-                       } else
+                               capability = iax2_codec_pref_from_bitfield(&prefs_new,
+                                       IAX_CAPABILITY_FULLBANDWIDTH);
+                       } else {
                                ast_log(LOG_WARNING, "bandwidth must be either low, medium, or high\n");
+                       }
                } else if (!strcasecmp(v->name, "allow")) {
-                       iax2_parse_allow_disallow(&prefs, &capability, v->value, 1);
+                       iax2_parse_allow_disallow(&prefs_new, &capability, v->value, 1);
                } else if (!strcasecmp(v->name, "disallow")) {
-                       iax2_parse_allow_disallow(&prefs, &capability, v->value, 0);
+                       iax2_parse_allow_disallow(&prefs_new, &capability, v->value, 0);
                } else if (!strcasecmp(v->name, "register")) {
                        iax2_register(v->value, v->lineno);
                } else if (!strcasecmp(v->name, "iaxcompat")) {
@@ -13510,8 +13783,17 @@ static int set_config(const char *config_file, int reload, int forced)
                } else if (!strcasecmp(v->name, "calltokenoptional")) {
                        if (add_calltoken_ignore(v->value)) {
                                ast_log(LOG_WARNING, "Invalid calltokenoptional address range - '%s' line %d\n", v->value, v->lineno);
+                               return -1;
                        }
-               } else if (!strcasecmp(v->name, "subscribe_network_change_event")) {
+               } else if (!strcasecmp(v->name, "calltokenexpiration")) {
+                       int temp = -1;
+                       sscanf(v->value, "%u", &temp);
+                       if( temp <= 0 ){
+                               ast_log(LOG_WARNING, "Invalid calltokenexpiration value %s. Should be integer greater than 0.\n", v->value);
+                       } else {
+                               max_calltoken_delay = temp;
+                       }
+               }  else if (!strcasecmp(v->name, "subscribe_network_change_event")) {
                        if (ast_true(v->value)) {
                                subscribe_network_change = 1;
                        } else if (ast_false(v->value)) {
@@ -13565,6 +13847,7 @@ static int set_config(const char *config_file, int reload, int forced)
                        min_reg_expire, max_reg_expire, max_reg_expire);
                min_reg_expire = max_reg_expire;
        }
+       prefs_global = prefs_new;
        iax2_capability = capability;
 
        if (ucfg) {
@@ -14058,8 +14341,9 @@ static int function_iaxpeer(struct ast_channel *chan, const char *cmd, char *dat
        /* if our channel, return the IP address of the endpoint of current channel */
        if (!strcmp(peername,"CURRENTCHANNEL")) {
                unsigned short callno;
-               if (ast_channel_tech(chan) != &iax2_tech)
+               if (!chan || ast_channel_tech(chan) != &iax2_tech) {
                        return -1;
+               }
                callno = PTR_TO_CALLNO(ast_channel_tech_pvt(chan));
                ast_copy_string(buf, !ast_sockaddr_isnull(&iaxs[callno]->addr) ? ast_sockaddr_stringify_addr(&iaxs[callno]->addr) : "", len);
                return 0;
@@ -14090,10 +14374,13 @@ static int function_iaxpeer(struct ast_channel *chan, const char *cmd, char *dat
        } else  if (!strcasecmp(colname, "callerid_num")) {
                ast_copy_string(buf, peer->cid_num, len);
        } else  if (!strcasecmp(colname, "codecs")) {
-               iax2_getformatname_multiple(buf, len -1, peer->capability);
+               struct ast_str *codec_buf = ast_str_alloca(256);
+
+               iax2_getformatname_multiple(peer->capability, &codec_buf);
+               ast_copy_string(buf, ast_str_buffer(codec_buf), len);
        } else  if (!strncasecmp(colname, "codec[", 6)) {
                char *codecnum, *ptr;
-               struct ast_format tmpfmt;
+               struct ast_format *tmpfmt;
 
                /* skip over "codec" to the '[' */
                codecnum = colname + 5;
@@ -14102,8 +14389,8 @@ static int function_iaxpeer(struct ast_channel *chan, const char *cmd, char *dat
                if ((ptr = strchr(codecnum, ']'))) {
                        *ptr = '\0';
                }
-               if((ast_codec_pref_index(&peer->prefs, atoi(codecnum), &tmpfmt))) {
-                       ast_copy_string(buf, ast_getformatname(&tmpfmt), len);
+               if((iax2_codec_pref_index(&peer->prefs, atoi(codecnum), &tmpfmt))) {
+                       ast_copy_string(buf, ast_format_get_name(tmpfmt), len);
                } else {
                        buf[0] = '\0';
                }
@@ -14380,7 +14667,6 @@ static void cleanup_thread_list(void *head)
 
 static int __unload_module(void)
 {
-       struct ast_context *con;
        int x;
 
        network_change_stasis_unsubscribe();
@@ -14444,7 +14730,6 @@ static int __unload_module(void)
        ao2_ref(users, -1);
        ao2_ref(iax_peercallno_pvts, -1);
        ao2_ref(iax_transfercallno_pvts, -1);
-       ao2_ref(peercnts, -1);
        ao2_ref(callno_limits, -1);
        ao2_ref(calltoken_ignores, -1);
        if (timer) {
@@ -14452,15 +14737,17 @@ static int __unload_module(void)
                timer = NULL;
        }
        transmit_processor = ast_taskprocessor_unreference(transmit_processor);
+
+       ast_sched_clean_by_callback(sched, peercnt_remove_cb, peercnt_remove_cb);
        ast_sched_context_destroy(sched);
        sched = NULL;
+       ao2_ref(peercnts, -1);
 
-       con = ast_context_find(regcontext);
-       if (con)
-               ast_context_destroy(con, "IAX2");
+       ast_context_destroy_by_name(regcontext, "IAX2");
        ast_unload_realtime("iaxpeers");
 
-       iax2_tech.capabilities = ast_format_cap_destroy(iax2_tech.capabilities);
+       ao2_ref(iax2_tech.capabilities, -1);
+       iax2_tech.capabilities = NULL;
        return 0;
 }
 
@@ -14770,10 +15057,10 @@ static int load_module(void)
        int x = 0;
        struct iax2_registry *reg = NULL;
 
-       if (!(iax2_tech.capabilities = ast_format_cap_alloc(0))) {
+       if (!(iax2_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
                return AST_MODULE_LOAD_FAILURE;
        }
-       ast_format_cap_add_all(iax2_tech.capabilities);
+       ast_format_cap_append_by_type(iax2_tech.capabilities, AST_MEDIA_TYPE_UNKNOWN);
 
        if (load_objects()) {
                return AST_MODULE_LOAD_FAILURE;
@@ -14897,9 +15184,10 @@ static int load_module(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Inter Asterisk eXchange (Ver 2)",
-               .load = load_module,
-               .unload = unload_module,
-               .reload = reload,
-               .load_pri = AST_MODPRI_CHANNEL_DRIVER,
-               .nonoptreq = "res_crypto",
-               );
+       .support_level = AST_MODULE_SUPPORT_CORE,
+       .load = load_module,
+       .unload = unload_module,
+       .reload = reload,
+       .load_pri = AST_MODPRI_CHANNEL_DRIVER,
+       .nonoptreq = "res_crypto",
+);