loader: Correct overly strict startup checks.
[asterisk/asterisk.git] / main / channel.c
index 50b9e87..7eb40d1 100644 (file)
@@ -29,8 +29,6 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
 #include "asterisk/_private.h"
 
 #include <sys/time.h>
@@ -53,7 +51,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/chanvars.h"
 #include "asterisk/linkedlists.h"
 #include "asterisk/indications.h"
-#include "asterisk/monitor.h"
 #include "asterisk/causes.h"
 #include "asterisk/callerid.h"
 #include "asterisk/utils.h"
@@ -69,40 +66,29 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/autochan.h"
 #include "asterisk/stringfields.h"
 #include "asterisk/global_datastores.h"
-#include "asterisk/data.h"
 #include "asterisk/channel_internal.h"
 #include "asterisk/features.h"
 #include "asterisk/bridge.h"
 #include "asterisk/test.h"
 #include "asterisk/stasis_channels.h"
+#include "asterisk/max_forwards.h"
+#include "asterisk/stream.h"
 
 /*** DOCUMENTATION
  ***/
 
-#ifdef HAVE_EPOLL
-#include <sys/epoll.h>
-#endif
-
 #if defined(KEEP_TILL_CHANNEL_PARTY_NUMBER_INFO_NEEDED)
 #if defined(HAVE_PRI)
 #include "libpri.h"
 #endif /* defined(HAVE_PRI) */
 #endif /* defined(KEEP_TILL_CHANNEL_PARTY_NUMBER_INFO_NEEDED) */
 
-struct ast_epoll_data {
-       struct ast_channel *chan;
-       int which;
-};
-
 /* uncomment if you have problems with 'monitoring' synchronized files */
 #if 0
 #define MONITOR_CONSTANT_DELAY
 #define MONITOR_DELAY  150 * 8         /*!< 150 ms of MONITORING DELAY */
 #endif
 
-/*! \brief Prevent new channel allocation if shutting down. */
-static int shutting_down;
-
 static int chancount;
 
 unsigned long global_fin, global_fout;
@@ -275,7 +261,7 @@ static const char *party_number_plan2str(int plan)
 /*! \brief Show channel types - CLI command */
 static char *handle_cli_core_show_channeltypes(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-#define FORMAT  "%-15.15s  %-40.40s %-12.12s %-12.12s %-12.12s\n"
+#define FORMAT  "%-15.15s  %-40.40s %-13.13s %-13.13s %-13.13s %-13.13s\n"
        struct chanlist *cl;
        int count_chan = 0;
 
@@ -294,13 +280,14 @@ static char *handle_cli_core_show_channeltypes(struct ast_cli_entry *e, int cmd,
        if (a->argc != 3)
                return CLI_SHOWUSAGE;
 
-       ast_cli(a->fd, FORMAT, "Type", "Description",       "Devicestate", "Indications", "Transfer");
-       ast_cli(a->fd, FORMAT, "-----------", "-----------", "-----------", "-----------", "-----------");
+       ast_cli(a->fd, FORMAT, "Type", "Description", "Devicestate", "Presencestate", "Indications", "Transfer");
+       ast_cli(a->fd, FORMAT, "-------------", "-------------", "-------------", "-------------", "-------------", "-------------");
 
        AST_RWLIST_RDLOCK(&backends);
        AST_RWLIST_TRAVERSE(&backends, cl, list) {
                ast_cli(a->fd, FORMAT, cl->tech->type, cl->tech->description,
                        (cl->tech->devicestate) ? "yes" : "no",
+                       (cl->tech->presencestate) ? "yes" : "no",
                        (cl->tech->indicate) ? "yes" : "no",
                        (cl->tech->transfer) ? "yes" : "no");
                count_chan++;
@@ -342,7 +329,7 @@ static char *complete_channeltypes(struct ast_cli_args *a)
 static char *handle_cli_core_show_channeltype(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
        struct chanlist *cl = NULL;
-       struct ast_str *codec_buf = ast_str_alloca(64);
+       struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
 
        switch (cmd) {
        case CLI_INIT:
@@ -375,6 +362,7 @@ static char *handle_cli_core_show_channeltype(struct ast_cli_entry *e, int cmd,
        ast_cli(a->fd,
                "-- Info about channel driver: %s --\n"
                "  Device State: %s\n"
+               "Presence State: %s\n"
                "    Indication: %s\n"
                "     Transfer : %s\n"
                "  Capabilities: %s\n"
@@ -385,6 +373,7 @@ static char *handle_cli_core_show_channeltype(struct ast_cli_entry *e, int cmd,
                "  Text Support: %s\n",
                cl->tech->type,
                (cl->tech->devicestate) ? "yes" : "no",
+               (cl->tech->presencestate) ? "yes" : "no",
                (cl->tech->indicate) ? "yes" : "no",
                (cl->tech->transfer) ? "yes" : "no",
                ast_format_cap_get_names(cl->tech->capabilities, &codec_buf),
@@ -504,13 +493,9 @@ static int ast_channel_softhangup_cb(void *obj, void *arg, int flags)
        return 0;
 }
 
-void ast_begin_shutdown(int hangup)
+void ast_softhangup_all(void)
 {
-       shutting_down = 1;
-
-       if (hangup) {
-               ao2_callback(channels, OBJ_NODATA | OBJ_MULTIPLE, ast_channel_softhangup_cb, NULL);
-       }
+       ao2_callback(channels, OBJ_NODATA | OBJ_MULTIPLE, ast_channel_softhangup_cb, NULL);
 }
 
 /*! \brief returns number of active/allocated channels */
@@ -524,18 +509,6 @@ int ast_undestroyed_channels(void)
        return ast_atomic_fetchadd_int(&chancount, 0);
 }
 
-/*! \brief Cancel a shutdown in progress */
-void ast_cancel_shutdown(void)
-{
-       shutting_down = 0;
-}
-
-/*! \brief Returns non-zero if Asterisk is being shut down */
-int ast_shutting_down(void)
-{
-       return shutting_down;
-}
-
 /*! \brief Set when to hangup channel */
 void ast_channel_setwhentohangup_tv(struct ast_channel *chan, struct timeval offset)
 {
@@ -786,6 +759,27 @@ static const struct ast_channel_tech null_tech = {
 
 static void ast_channel_destructor(void *obj);
 static void ast_dummy_channel_destructor(void *obj);
+static int ast_channel_by_uniqueid_cb(void *obj, void *arg, void *data, int flags);
+
+static int does_id_conflict(const char *uniqueid)
+{
+       struct ast_channel *conflict;
+       int length = 0;
+
+       if (ast_strlen_zero(uniqueid)) {
+               return 0;
+       }
+
+       conflict = ast_channel_callback(ast_channel_by_uniqueid_cb, (char *) uniqueid, &length, OBJ_NOLOCK);
+       if (conflict) {
+               ast_log(LOG_ERROR, "Channel Unique ID '%s' already in use by channel %s(%p)\n",
+                       uniqueid, ast_channel_name(conflict), conflict);
+               ast_channel_unref(conflict);
+               return 1;
+       }
+
+       return 0;
+}
 
 /*! \brief Create a new channel structure */
 static struct ast_channel * attribute_malloc __attribute__((format(printf, 15, 0)))
@@ -803,6 +797,7 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char
        struct ast_timer *timer;
        struct timeval now;
        const struct ast_channel_tech *channel_tech;
+       struct ast_stream_topology *topology;
 
        /* If shutting down, don't allocate any new channels */
        if (ast_shutting_down()) {
@@ -810,7 +805,9 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char
                return NULL;
        }
 
-       if (!(tmp = ast_channel_internal_alloc(ast_channel_destructor, assignedids, requestor))) {
+       tmp = __ast_channel_internal_alloc(ast_channel_destructor, assignedids, requestor,
+               file, line, function);
+       if (!tmp) {
                /* Channel structure allocation failure. */
                return NULL;
        }
@@ -818,7 +815,12 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char
        ast_channel_stage_snapshot(tmp);
 
        if (!(nativeformats = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
-               /* format capabilities structure allocation failure */
+               /*
+                * Aborting the channel creation.  We do not need to complete staging
+                * the channel snapshot because the channel has not been finalized or
+                * linked into the channels container yet.  Nobody else knows about
+                * this channel nor will anybody ever know about it.
+                */
                return ast_channel_unref(tmp);
        }
        ast_format_cap_append(nativeformats, ast_format_none, 0);
@@ -838,12 +840,9 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char
        ast_channel_internal_alertpipe_clear(tmp);
        ast_channel_internal_fd_clear_all(tmp);
 
-#ifdef HAVE_EPOLL
-       ast_channel_epfd_set(tmp, epoll_create(25));
-#endif
-
        if (!(schedctx = ast_sched_context_create())) {
                ast_log(LOG_WARNING, "Channel allocation failed: Unable to create schedule context\n");
+               /* See earlier channel creation abort comment above. */
                return ast_channel_unref(tmp);
        }
        ast_channel_sched_set(tmp, schedctx);
@@ -858,6 +857,7 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char
                ast_channel_caller(tmp)->id.name.valid = 1;
                ast_channel_caller(tmp)->id.name.str = ast_strdup(cid_name);
                if (!ast_channel_caller(tmp)->id.name.str) {
+                       /* See earlier channel creation abort comment above. */
                        return ast_channel_unref(tmp);
                }
        }
@@ -865,6 +865,7 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char
                ast_channel_caller(tmp)->id.number.valid = 1;
                ast_channel_caller(tmp)->id.number.str = ast_strdup(cid_num);
                if (!ast_channel_caller(tmp)->id.number.str) {
+                       /* See earlier channel creation abort comment above. */
                        return ast_channel_unref(tmp);
                }
        }
@@ -878,8 +879,14 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char
        }
 
        if (needqueue && ast_channel_internal_alertpipe_init(tmp)) {
+               /* See earlier channel creation abort comment above. */
+               return ast_channel_unref(tmp);
+       }
+
+       if (!(topology = ast_stream_topology_alloc())) {
                return ast_channel_unref(tmp);
        }
+       ast_channel_internal_set_stream_topology(tmp, topology);
 
        /* Always watch the alertpipe */
        ast_channel_set_fd(tmp, AST_ALERT_FD, ast_channel_internal_alert_readfd(tmp));
@@ -891,6 +898,7 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char
        ast_channel_hold_state_set(tmp, AST_CONTROL_UNHOLD);
 
        ast_channel_streamid_set(tmp, -1);
+       ast_channel_vstreamid_set(tmp, -1);
 
        ast_channel_fin_set(tmp, global_fin);
        ast_channel_fout_set(tmp, global_fout);
@@ -958,16 +966,27 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char
                ast_channel_tech_set(tmp, &null_tech);
        }
 
-       ast_channel_internal_finalize(tmp);
-
-       ast_atomic_fetchadd_int(&chancount, +1);
-
        /* You might scream "locking inversion" at seeing this but it is actually perfectly fine.
         * Since the channel was just created nothing can know about it yet or even acquire it.
         */
        ast_channel_lock(tmp);
 
-       ao2_link(channels, tmp);
+       ao2_lock(channels);
+
+       if (assignedids && (does_id_conflict(assignedids->uniqueid) || does_id_conflict(assignedids->uniqueid2))) {
+               ast_channel_internal_errno_set(AST_CHANNEL_ERROR_ID_EXISTS);
+               ao2_unlock(channels);
+               ast_channel_unlock(tmp);
+               /* See earlier channel creation abort comment above. */
+               return ast_channel_unref(tmp);
+       }
+
+       /* Finalize and link into the channels container. */
+       ast_channel_internal_finalize(tmp);
+       ast_atomic_fetchadd_int(&chancount, +1);
+       ao2_link_flags(channels, tmp, OBJ_NOLOCK);
+
+       ao2_unlock(channels);
 
        if (endpoint) {
                ast_endpoint_add_channel(endpoint, tmp);
@@ -978,6 +997,9 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char
         * the world know of its existance
         */
        ast_channel_stage_snapshot_done(tmp);
+
+       ast_debug(1, "Channel %p '%s' allocated\n", tmp, ast_channel_name(tmp));
+
        return tmp;
 }
 
@@ -1002,16 +1024,14 @@ struct ast_channel *__ast_channel_alloc(int needqueue, int state, const char *ci
 
 /* only do the minimum amount of work needed here to make a channel
  * structure that can be used to expand channel vars */
-#if defined(REF_DEBUG) || defined(__AST_DEBUG_MALLOC)
 struct ast_channel *__ast_dummy_channel_alloc(const char *file, int line, const char *function)
-#else
-struct ast_channel *ast_dummy_channel_alloc(void)
-#endif
 {
        struct ast_channel *tmp;
        struct varshead *headp;
 
-       if (!(tmp = ast_channel_internal_alloc(ast_dummy_channel_destructor, NULL, NULL))) {
+       tmp = __ast_channel_internal_alloc(ast_dummy_channel_destructor, NULL, NULL,
+               file, line, function);
+       if (!tmp) {
                /* Dummy channel structure allocation failure. */
                return NULL;
        }
@@ -1027,9 +1047,6 @@ struct ast_channel *ast_dummy_channel_alloc(void)
        ast_channel_timingfd_set(tmp, -1);
        ast_channel_internal_alertpipe_clear(tmp);
        ast_channel_internal_fd_clear_all(tmp);
-#ifdef HAVE_EPOLL
-       ast_channel_epfd_set(tmp, -1);
-#endif
 
        ast_channel_hold_state_set(tmp, AST_CONTROL_UNHOLD);
 
@@ -1127,6 +1144,9 @@ static int __ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin, in
                                }
                                AST_LIST_REMOVE_CURRENT(frame_list);
                                ast_frfree(cur);
+
+                               /* Read from the alert pipe for each flushed frame. */
+                               ast_channel_internal_alert_read(chan);
                        }
                }
                AST_LIST_TRAVERSE_SAFE_END;
@@ -1143,9 +1163,13 @@ static int __ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin, in
        }
 
        if (ast_channel_alert_writable(chan)) {
-               if (ast_channel_alert_write(chan)) {
-                       ast_log(LOG_WARNING, "Unable to write to alert pipe on %s (qlen = %u): %s!\n",
-                               ast_channel_name(chan), queued_frames, strerror(errno));
+               /* Write to the alert pipe for each added frame */
+               while (new_frames--) {
+                       if (ast_channel_alert_write(chan)) {
+                               ast_log(LOG_WARNING, "Unable to write to alert pipe on %s (qlen = %u): %s!\n",
+                                       ast_channel_name(chan), queued_frames, strerror(errno));
+                               break;
+                       }
                }
        } else if (ast_channel_timingfd(chan) > -1) {
                ast_timer_enable_continuous(ast_channel_timer(chan));
@@ -1212,8 +1236,8 @@ int ast_queue_hangup_with_cause(struct ast_channel *chan, int cause)
 
 int ast_queue_hold(struct ast_channel *chan, const char *musicclass)
 {
-       RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
        struct ast_frame f = { AST_FRAME_CONTROL, .subclass.integer = AST_CONTROL_HOLD };
+       struct ast_json *blob = NULL;
        int res;
 
        if (!ast_strlen_zero(musicclass)) {
@@ -1228,6 +1252,8 @@ int ast_queue_hold(struct ast_channel *chan, const char *musicclass)
 
        res = ast_queue_frame(chan, &f);
 
+       ast_json_unref(blob);
+
        return res;
 }
 
@@ -1264,8 +1290,10 @@ int ast_channel_defer_dtmf(struct ast_channel *chan)
        int pre = 0;
 
        if (chan) {
+               ast_channel_lock(chan);
                pre = ast_test_flag(ast_channel_flags(chan), AST_FLAG_DEFER_DTMF);
                ast_set_flag(ast_channel_flags(chan), AST_FLAG_DEFER_DTMF);
+               ast_channel_unlock(chan);
        }
        return pre;
 }
@@ -1273,8 +1301,9 @@ int ast_channel_defer_dtmf(struct ast_channel *chan)
 /*! \brief Unset defer DTMF flag on channel */
 void ast_channel_undefer_dtmf(struct ast_channel *chan)
 {
-       if (chan)
-               ast_clear_flag(ast_channel_flags(chan), AST_FLAG_DEFER_DTMF);
+       if (chan) {
+               ast_channel_clear_flag(chan, AST_FLAG_DEFER_DTMF);
+       }
 }
 
 struct ast_channel *ast_channel_callback(ao2_callback_data_fn *cb_fn, void *arg,
@@ -1489,6 +1518,7 @@ int ast_is_deferrable_frame(const struct ast_frame *frame)
        case AST_FRAME_IAX:
        case AST_FRAME_CNG:
        case AST_FRAME_MODEM:
+       case AST_FRAME_RTCP:
                return 0;
        }
        return 0;
@@ -2182,15 +2212,14 @@ void ast_party_redirecting_free(struct ast_party_redirecting *doomed)
 static void ast_channel_destructor(void *obj)
 {
        struct ast_channel *chan = obj;
-#ifdef HAVE_EPOLL
-       int i;
-#endif
        struct ast_var_t *vardata;
        struct ast_frame *f;
        struct varshead *headp;
        struct ast_datastore *datastore;
        char device_name[AST_CHANNEL_NAME];
-       struct ast_callid *callid;
+       ast_callid callid;
+
+       ast_debug(1, "Channel %p '%s' destroying\n", chan, ast_channel_name(chan));
 
        /* Stop monitoring */
        if (ast_channel_monitor(chan)) {
@@ -2282,14 +2311,6 @@ static void ast_channel_destructor(void *obj)
                ast_timer_close(ast_channel_timer(chan));
                ast_channel_timer_set(chan, NULL);
        }
-#ifdef HAVE_EPOLL
-       for (i = 0; i < AST_MAX_FDS; i++) {
-               if (ast_channel_internal_epfd_data(chan, i)) {
-                       ast_free(ast_channel_internal_epfd_data(chan, i));
-               }
-       }
-       close(ast_channel_epfd(chan));
-#endif
        while ((f = AST_LIST_REMOVE_HEAD(ast_channel_readq(chan), frame_list)))
                ast_frfree(f);
 
@@ -2327,9 +2348,6 @@ static void ast_channel_destructor(void *obj)
        }
 
        ast_channel_nativeformats_set(chan, NULL);
-       if (callid) {
-               ast_callid_unref(callid);
-       }
 
        ast_channel_named_callgroups_set(chan, NULL);
        ast_channel_named_pickupgroups_set(chan, NULL);
@@ -2443,82 +2461,10 @@ struct ast_datastore *ast_channel_datastore_find(struct ast_channel *chan, const
 /*! Set the file descriptor on the channel */
 void ast_channel_set_fd(struct ast_channel *chan, int which, int fd)
 {
-#ifdef HAVE_EPOLL
-       struct epoll_event ev;
-       struct ast_epoll_data *aed = NULL;
-
-       if (ast_channel_fd_isset(chan, which)) {
-               epoll_ctl(ast_channel_epfd(chan), EPOLL_CTL_DEL, ast_channel_fd(chan, which), &ev);
-               aed = ast_channel_internal_epfd_data(chan, which);
-       }
-
-       /* If this new fd is valid, add it to the epoll */
-       if (fd > -1) {
-               if (!aed && (!(aed = ast_calloc(1, sizeof(*aed)))))
-                       return;
-
-               ast_channel_internal_epfd_data_set(chan, which, aed);
-               aed->chan = chan;
-               aed->which = which;
-
-               ev.events = EPOLLIN | EPOLLPRI | EPOLLERR | EPOLLHUP;
-               ev.data.ptr = aed;
-               epoll_ctl(ast_channel_epfd(chan), EPOLL_CTL_ADD, fd, &ev);
-       } else if (aed) {
-               /* We don't have to keep around this epoll data structure now */
-               ast_free(aed);
-               ast_channel_epfd_data_set(chan, which, NULL);
-       }
-#endif
        ast_channel_internal_fd_set(chan, which, fd);
        return;
 }
 
-/*! Add a channel to an optimized waitfor */
-void ast_poll_channel_add(struct ast_channel *chan0, struct ast_channel *chan1)
-{
-#ifdef HAVE_EPOLL
-       struct epoll_event ev;
-       int i = 0;
-
-       if (ast_channel_epfd(chan0) == -1)
-               return;
-
-       /* Iterate through the file descriptors on chan1, adding them to chan0 */
-       for (i = 0; i < AST_MAX_FDS; i++) {
-               if (!ast_channel_fd_isset(chan1, i)) {
-                       continue;
-               }
-               ev.events = EPOLLIN | EPOLLPRI | EPOLLERR | EPOLLHUP;
-               ev.data.ptr = ast_channel_internal_epfd_data(chan1, i);
-               epoll_ctl(ast_channel_epfd(chan0), EPOLL_CTL_ADD, ast_channel_fd(chan1, i), &ev);
-       }
-
-#endif
-       return;
-}
-
-/*! Delete a channel from an optimized waitfor */
-void ast_poll_channel_del(struct ast_channel *chan0, struct ast_channel *chan1)
-{
-#ifdef HAVE_EPOLL
-       struct epoll_event ev;
-       int i = 0;
-
-       if (ast_channel_epfd(chan0) == -1)
-               return;
-
-       for (i = 0; i < AST_MAX_FDS; i++) {
-               if (!ast_channel_fd_isset(chan1, i)) {
-                       continue;
-               }
-               epoll_ctl(ast_channel_epfd(chan0), EPOLL_CTL_DEL, ast_channel_fd(chan1, i), &ev);
-       }
-
-#endif
-       return;
-}
-
 void ast_channel_clear_softhangup(struct ast_channel *chan, int flag)
 {
        ast_channel_lock(chan);
@@ -2637,6 +2583,9 @@ void ast_hangup(struct ast_channel *chan)
                return;
        }
 
+       ast_debug(1, "Channel %p '%s' hanging up.  Refs: %d\n", chan, ast_channel_name(chan),
+               ao2_ref(chan, 0));
+
        ast_autoservice_stop(chan);
 
        ast_channel_lock(chan);
@@ -2696,7 +2645,6 @@ void ast_hangup(struct ast_channel *chan)
                ast_assert(ast_test_flag(ast_channel_flags(chan), AST_FLAG_BLOCKING) == 0);
        }
 
-       ast_debug(1, "Hanging up channel '%s'\n", ast_channel_name(chan));
        if (ast_channel_tech(chan)->hangup) {
                ast_channel_tech(chan)->hangup(chan);
        }
@@ -2708,10 +2656,28 @@ void ast_hangup(struct ast_channel *chan)
        ast_channel_unref(chan);
 }
 
+/*!
+ * \internal
+ * \brief Set channel answered time if not already set.
+ * \since 13.11.0
+ *
+ * \param chan Channel to set answered time.
+ *
+ * \return Nothing
+ */
+static void set_channel_answer_time(struct ast_channel *chan)
+{
+       if (ast_tvzero(ast_channel_answertime(chan))) {
+               struct timeval answertime;
+
+               answertime = ast_tvnow();
+               ast_channel_answertime_set(chan, &answertime);
+       }
+}
+
 int ast_raw_answer(struct ast_channel *chan)
 {
        int res = 0;
-       struct timeval answertime;
 
        ast_channel_lock(chan);
 
@@ -2727,8 +2693,11 @@ int ast_raw_answer(struct ast_channel *chan)
                return -1;
        }
 
-       answertime = ast_tvnow();
-       ast_channel_answertime_set(chan, &answertime);
+       /*
+        * Mark when incoming channel answered so we can know how
+        * long the channel has been up.
+        */
+       set_channel_answer_time(chan);
 
        ast_channel_unlock(chan);
 
@@ -2827,6 +2796,7 @@ int __ast_answer(struct ast_channel *chan, unsigned int delay)
                                case AST_FRAME_IMAGE:
                                case AST_FRAME_HTML:
                                case AST_FRAME_MODEM:
+                               case AST_FRAME_RTCP:
                                        done = 1;
                                        break;
                                case AST_FRAME_CONTROL:
@@ -2843,14 +2813,14 @@ int __ast_answer(struct ast_channel *chan, unsigned int delay)
                                }
                        }
 
-                       if (res == 0) {
-                               ast_channel_lock(chan);
-                               while ((cur = AST_LIST_REMOVE_HEAD(&frames, frame_list))) {
+                       ast_channel_lock(chan);
+                       while ((cur = AST_LIST_REMOVE_HEAD(&frames, frame_list))) {
+                               if (res == 0) {
                                        ast_queue_frame_head(chan, cur);
-                                       ast_frfree(cur);
                                }
-                               ast_channel_unlock(chan);
+                               ast_frfree(cur);
                        }
+                       ast_channel_unlock(chan);
                } while (0);
                break;
        default:
@@ -3001,20 +2971,15 @@ int ast_waitfor_n_fd(int *fds, int n, int *ms, int *exception)
 }
 
 /*! \brief Wait for x amount of time on a file descriptor to have input.  */
-#ifdef HAVE_EPOLL
-static struct ast_channel *ast_waitfor_nandfds_classic(struct ast_channel **c, int n, int *fds, int nfds,
-                                       int *exception, int *outfd, int *ms)
-#else
 struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds, int nfds,
                                        int *exception, int *outfd, int *ms)
-#endif
 {
        struct timeval start = { 0 , 0 };
        struct pollfd *pfds = NULL;
        int res;
        long rms;
        int x, y, max;
-       int sz;
+       int sz = nfds;
        struct timeval now = { 0, 0 };
        struct timeval whentohangup = { 0, 0 }, diff;
        struct ast_channel *winner = NULL;
@@ -3030,14 +2995,6 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds,
                *exception = 0;
        }
 
-       if ((sz = n * AST_MAX_FDS + nfds)) {
-               pfds = ast_alloca(sizeof(*pfds) * sz);
-               fdmap = ast_alloca(sizeof(*fdmap) * sz);
-       } else {
-               /* nothing to allocate and no FDs to check */
-               return NULL;
-       }
-
        for (x = 0; x < n; x++) {
                ast_channel_lock(c[x]);
                if (!ast_tvzero(*ast_channel_whentohangup(c[x]))) {
@@ -3054,8 +3011,17 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds,
                        if (ast_tvzero(whentohangup) || ast_tvcmp(diff, whentohangup) < 0)
                                whentohangup = diff;
                }
+               sz += ast_channel_fd_count(c[x]);
                ast_channel_unlock(c[x]);
        }
+
+       if (!sz) {
+               return NULL;
+       }
+
+       pfds = ast_alloca(sizeof(*pfds) * sz);
+       fdmap = ast_alloca(sizeof(*fdmap) * sz);
+
        /* Wait full interval */
        rms = *ms;
        /* INT_MAX, not LONG_MAX, because it matters on 64-bit */
@@ -3075,12 +3041,14 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds,
         */
        max = 0;
        for (x = 0; x < n; x++) {
-               for (y = 0; y < AST_MAX_FDS; y++) {
+               ast_channel_lock(c[x]);
+               for (y = 0; y < ast_channel_fd_count(c[x]); y++) {
                        fdmap[max].fdno = y;  /* fd y is linked to this pfds */
                        fdmap[max].chan = x;  /* channel x is linked to this pfds */
                        max += ast_add_fd(&pfds[max], ast_channel_fd(c[x], y));
                }
                CHECK_BLOCKING(c[x]);
+               ast_channel_unlock(c[x]);
        }
        /* Add the individual fds */
        for (x = 0; x < nfds; x++) {
@@ -3107,7 +3075,9 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds,
                res = ast_poll(pfds, max, rms);
        }
        for (x = 0; x < n; x++) {
+               ast_channel_lock(c[x]);
                ast_clear_flag(ast_channel_flags(c[x]), AST_FLAG_BLOCKING);
+               ast_channel_unlock(c[x]);
        }
        if (res < 0) { /* Simulate a timeout if we were interrupted */
                if (errno != EINTR) {
@@ -3143,12 +3113,14 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds,
                }
                if (fdmap[x].chan >= 0) {       /* this is a channel */
                        winner = c[fdmap[x].chan];      /* override previous winners */
+                       ast_channel_lock(winner);
                        if (res & POLLPRI) {
                                ast_set_flag(ast_channel_flags(winner), AST_FLAG_EXCEPTION);
                        } else {
                                ast_clear_flag(ast_channel_flags(winner), AST_FLAG_EXCEPTION);
                        }
                        ast_channel_fdno_set(winner, fdmap[x].fdno);
+                       ast_channel_unlock(winner);
                } else {                        /* this is an fd */
                        if (outfd) {
                                *outfd = pfds[x].fd;
@@ -3168,305 +3140,106 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds,
        return winner;
 }
 
-#ifdef HAVE_EPOLL
-static struct ast_channel *ast_waitfor_nandfds_simple(struct ast_channel *chan, int *ms)
+struct ast_channel *ast_waitfor_n(struct ast_channel **c, int n, int *ms)
 {
-       struct timeval start = { 0 , 0 };
-       int res = 0;
-       struct epoll_event ev[1];
-       long diff, rms = *ms;
-       struct ast_channel *winner = NULL;
-       struct ast_epoll_data *aed = NULL;
+       return ast_waitfor_nandfds(c, n, NULL, 0, NULL, NULL, ms);
+}
 
-       ast_channel_lock(chan);
-       /* Figure out their timeout */
-       if (!ast_tvzero(*ast_channel_whentohangup(chan))) {
-               if ((diff = ast_tvdiff_ms(*ast_channel_whentohangup(chan), ast_tvnow())) < 0) {
-                       /* They should already be hungup! */
-                       ast_channel_softhangup_internal_flag_add(chan, AST_SOFTHANGUP_TIMEOUT);
-                       ast_channel_unlock(chan);
-                       return NULL;
-               }
-               /* If this value is smaller then the current one... make it priority */
-               if (rms > diff) {
-                       rms = diff;
-               }
+int ast_waitfor(struct ast_channel *c, int ms)
+{
+       if (ms < 0) {
+               do {
+                       ms = 100000;
+                       ast_waitfor_nandfds(&c, 1, NULL, 0, NULL, NULL, &ms);
+               } while (!ms);
+       } else {
+               ast_waitfor_nandfds(&c, 1, NULL, 0, NULL, NULL, &ms);
        }
+       return ms;
+}
 
-       ast_channel_unlock(chan);
+int ast_waitfordigit(struct ast_channel *c, int ms)
+{
+       return ast_waitfordigit_full(c, ms, NULL, -1, -1);
+}
 
-       /* Time to make this channel block... */
-       CHECK_BLOCKING(chan);
+int ast_settimeout(struct ast_channel *c, unsigned int rate, int (*func)(const void *data), void *data)
+{
+       return ast_settimeout_full(c, rate, func, data, 0);
+}
 
-       if (*ms > 0) {
-               start = ast_tvnow();
-       }
+int ast_settimeout_full(struct ast_channel *c, unsigned int rate, int (*func)(const void *data), void *data, unsigned int is_ao2_obj)
+{
+       int res;
+       unsigned int real_rate = rate, max_rate;
 
-       /* We don't have to add any file descriptors... they are already added, we just have to wait! */
-       res = epoll_wait(ast_channel_epfd(chan), ev, 1, rms);
+       ast_channel_lock(c);
 
-       /* Stop blocking */
-       ast_clear_flag(ast_channel_flags(chan), AST_FLAG_BLOCKING);
+       if (ast_channel_timingfd(c) == -1) {
+               ast_channel_unlock(c);
+               return -1;
+       }
 
-       /* Simulate a timeout if we were interrupted */
-       if (res < 0) {
-               if (errno != EINTR) {
-                       *ms = -1;
-               }
-               return NULL;
+       if (!func) {
+               rate = 0;
+               data = NULL;
        }
 
-       /* If this channel has a timeout see if it expired */
-       if (!ast_tvzero(*ast_channel_whentohangup(chan))) {
-               if (ast_tvdiff_ms(ast_tvnow(), *ast_channel_whentohangup(chan)) >= 0) {
-                       ast_channel_softhangup_internal_flag_add(chan, AST_SOFTHANGUP_TIMEOUT);
-                       winner = chan;
-               }
+       if (rate && rate > (max_rate = ast_timer_get_max_rate(ast_channel_timer(c)))) {
+               real_rate = max_rate;
        }
 
-       /* No fd ready, reset timeout and be done for now */
-       if (!res) {
-               *ms = 0;
-               return winner;
+       ast_debug(1, "Scheduling timer at (%u requested / %u actual) timer ticks per second\n", rate, real_rate);
+
+       res = ast_timer_set_rate(ast_channel_timer(c), real_rate);
+
+       if (ast_channel_timingdata(c) && ast_test_flag(ast_channel_flags(c), AST_FLAG_TIMINGDATA_IS_AO2_OBJ)) {
+               ao2_ref(ast_channel_timingdata(c), -1);
        }
 
-       /* See what events are pending */
-       aed = ev[0].data.ptr;
-       ast_channel_fdno_set(chan, aed->which);
-       if (ev[0].events & EPOLLPRI) {
-               ast_set_flag(ast_channel_flags(chan), AST_FLAG_EXCEPTION);
+       ast_channel_timingfunc_set(c, func);
+       ast_channel_timingdata_set(c, data);
+
+       if (data && is_ao2_obj) {
+               ao2_ref(data, 1);
+               ast_set_flag(ast_channel_flags(c), AST_FLAG_TIMINGDATA_IS_AO2_OBJ);
        } else {
-               ast_clear_flag(ast_channel_flags(chan), AST_FLAG_EXCEPTION);
+               ast_clear_flag(ast_channel_flags(c), AST_FLAG_TIMINGDATA_IS_AO2_OBJ);
        }
 
-       if (*ms > 0) {
-               *ms -= ast_tvdiff_ms(ast_tvnow(), start);
-               if (*ms < 0) {
-                       *ms = 0;
-               }
+       if (func == NULL && rate == 0 && ast_channel_fdno(c) == AST_TIMING_FD) {
+               /* Clearing the timing func and setting the rate to 0
+                * means that we don't want to be reading from the timingfd
+                * any more. Setting c->fdno to -1 means we won't have any
+                * errant reads from the timingfd, meaning we won't potentially
+                * miss any important frames.
+                */
+               ast_channel_fdno_set(c, -1);
        }
 
-       return chan;
+       ast_channel_unlock(c);
+
+       return res;
 }
 
-static struct ast_channel *ast_waitfor_nandfds_complex(struct ast_channel **c, int n, int *ms)
+int ast_waitfordigit_full(struct ast_channel *c, int timeout_ms, const char *breakon, int audiofd, int cmdfd)
 {
-       struct timeval start = { 0 , 0 };
-       int res = 0, i;
-       struct epoll_event ev[25] = { { 0, } };
-       struct timeval now = { 0, 0 };
-       long whentohangup = 0, diff = 0, rms = *ms;
-       struct ast_channel *winner = NULL;
-
-       for (i = 0; i < n; i++) {
-               ast_channel_lock(c[i]);
-               if (!ast_tvzero(*ast_channel_whentohangup(c[i]))) {
-                       if (whentohangup == 0) {
-                               now = ast_tvnow();
-                       }
-                       if ((diff = ast_tvdiff_ms(*ast_channel_whentohangup(c[i]), now)) < 0) {
-                               ast_channel_softhangup_internal_flag_add(c[i], AST_SOFTHANGUP_TIMEOUT);
-                               ast_channel_unlock(c[i]);
-                               return c[i];
-                       }
-                       if (!whentohangup || whentohangup > diff) {
-                               whentohangup = diff;
-                       }
-               }
-               ast_channel_unlock(c[i]);
-               CHECK_BLOCKING(c[i]);
-       }
-
-       rms = *ms;
-       if (whentohangup) {
-               rms = whentohangup;
-               if (*ms >= 0 && *ms < rms) {
-                       rms = *ms;
-               }
-       }
+       struct timeval start = ast_tvnow();
+       int ms;
 
-       if (*ms > 0) {
-               start = ast_tvnow();
-       }
+       /* Stop if we're a zombie or need a soft hangup */
+       if (ast_test_flag(ast_channel_flags(c), AST_FLAG_ZOMBIE) || ast_check_hangup(c))
+               return -1;
 
-       res = epoll_wait(ast_channel_epfd(c[0]), ev, 25, rms);
+       /* Only look for the end of DTMF, don't bother with the beginning and don't emulate things */
+       ast_channel_set_flag(c, AST_FLAG_END_DTMF_ONLY);
 
-       for (i = 0; i < n; i++) {
-               ast_clear_flag(ast_channel_flags(c[i]), AST_FLAG_BLOCKING);
-       }
-
-       if (res < 0) {
-               if (errno != EINTR) {
-                       *ms = -1;
-               }
-               return NULL;
-       }
-
-       if (whentohangup) {
-               now = ast_tvnow();
-               for (i = 0; i < n; i++) {
-                       if (!ast_tvzero(*ast_channel_whentohangup(c[i])) && ast_tvdiff_ms(now, *ast_channel_whentohangup(c[i])) >= 0) {
-                               ast_channel_softhangup_internal_flag_add(c[i], AST_SOFTHANGUP_TIMEOUT);
-                               if (!winner) {
-                                       winner = c[i];
-                               }
-                       }
-               }
-       }
-
-       if (!res) {
-               *ms = 0;
-               return winner;
-       }
-
-       for (i = 0; i < res; i++) {
-               struct ast_epoll_data *aed = ev[i].data.ptr;
-
-               if (!ev[i].events || !aed) {
-                       continue;
-               }
-
-               winner = aed->chan;
-               if (ev[i].events & EPOLLPRI) {
-                       ast_set_flag(ast_channel_flags(winner), AST_FLAG_EXCEPTION);
-               } else {
-                       ast_clear_flag(ast_channel_flags(winner), AST_FLAG_EXCEPTION);
-               }
-               ast_channel_fdno_set(winner, aed->which);
-       }
-
-       if (*ms > 0) {
-               *ms -= ast_tvdiff_ms(ast_tvnow(), start);
-               if (*ms < 0) {
-                       *ms = 0;
-               }
-       }
-
-       return winner;
-}
-
-struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds, int nfds,
-                                       int *exception, int *outfd, int *ms)
-{
-       /* Clear all provided values in one place. */
-       if (outfd) {
-               *outfd = -99999;
-       }
-       if (exception) {
-               *exception = 0;
-       }
-
-       /* If no epoll file descriptor is available resort to classic nandfds */
-       if (!n || nfds || ast_channel_epfd(c[0]) == -1) {
-               return ast_waitfor_nandfds_classic(c, n, fds, nfds, exception, outfd, ms);
-       } else if (!nfds && n == 1) {
-               return ast_waitfor_nandfds_simple(c[0], ms);
-       } else {
-               return ast_waitfor_nandfds_complex(c, n, ms);
-       }
-}
-#endif
-
-struct ast_channel *ast_waitfor_n(struct ast_channel **c, int n, int *ms)
-{
-       return ast_waitfor_nandfds(c, n, NULL, 0, NULL, NULL, ms);
-}
-
-int ast_waitfor(struct ast_channel *c, int ms)
-{
-       if (ms < 0) {
-               do {
-                       ms = 100000;
-                       ast_waitfor_nandfds(&c, 1, NULL, 0, NULL, NULL, &ms);
-               } while (!ms);
-       } else {
-               ast_waitfor_nandfds(&c, 1, NULL, 0, NULL, NULL, &ms);
-       }
-       return ms;
-}
-
-int ast_waitfordigit(struct ast_channel *c, int ms)
-{
-       return ast_waitfordigit_full(c, ms, -1, -1);
-}
-
-int ast_settimeout(struct ast_channel *c, unsigned int rate, int (*func)(const void *data), void *data)
-{
-       return ast_settimeout_full(c, rate, func, data, 0);
-}
-
-int ast_settimeout_full(struct ast_channel *c, unsigned int rate, int (*func)(const void *data), void *data, unsigned int is_ao2_obj)
-{
-       int res;
-       unsigned int real_rate = rate, max_rate;
-
-       ast_channel_lock(c);
-
-       if (ast_channel_timingfd(c) == -1) {
-               ast_channel_unlock(c);
-               return -1;
-       }
-
-       if (!func) {
-               rate = 0;
-               data = NULL;
-       }
-
-       if (rate && rate > (max_rate = ast_timer_get_max_rate(ast_channel_timer(c)))) {
-               real_rate = max_rate;
-       }
-
-       ast_debug(1, "Scheduling timer at (%u requested / %u actual) timer ticks per second\n", rate, real_rate);
-
-       res = ast_timer_set_rate(ast_channel_timer(c), real_rate);
-
-       if (ast_channel_timingdata(c) && ast_test_flag(ast_channel_flags(c), AST_FLAG_TIMINGDATA_IS_AO2_OBJ)) {
-               ao2_ref(ast_channel_timingdata(c), -1);
-       }
-
-       ast_channel_timingfunc_set(c, func);
-       ast_channel_timingdata_set(c, data);
-
-       if (data && is_ao2_obj) {
-               ao2_ref(data, 1);
-               ast_set_flag(ast_channel_flags(c), AST_FLAG_TIMINGDATA_IS_AO2_OBJ);
-       } else {
-               ast_clear_flag(ast_channel_flags(c), AST_FLAG_TIMINGDATA_IS_AO2_OBJ);
-       }
-
-       if (func == NULL && rate == 0 && ast_channel_fdno(c) == AST_TIMING_FD) {
-               /* Clearing the timing func and setting the rate to 0
-                * means that we don't want to be reading from the timingfd
-                * any more. Setting c->fdno to -1 means we won't have any
-                * errant reads from the timingfd, meaning we won't potentially
-                * miss any important frames.
-                */
-               ast_channel_fdno_set(c, -1);
-       }
-
-       ast_channel_unlock(c);
-
-       return res;
-}
-
-int ast_waitfordigit_full(struct ast_channel *c, int timeout_ms, int audiofd, int cmdfd)
-{
-       struct timeval start = ast_tvnow();
-       int ms;
-
-       /* Stop if we're a zombie or need a soft hangup */
-       if (ast_test_flag(ast_channel_flags(c), AST_FLAG_ZOMBIE) || ast_check_hangup(c))
-               return -1;
-
-       /* Only look for the end of DTMF, don't bother with the beginning and don't emulate things */
-       ast_set_flag(ast_channel_flags(c), AST_FLAG_END_DTMF_ONLY);
-
-       /* Wait for a digit, no more than timeout_ms milliseconds total.
-        * Or, wait indefinitely if timeout_ms is <0.
-        */
-       while ((ms = ast_remaining_ms(start, timeout_ms))) {
-               struct ast_channel *rchan;
-               int outfd = -1;
+       /* Wait for a digit, no more than timeout_ms milliseconds total.
+        * Or, wait indefinitely if timeout_ms is <0.
+        */
+       while ((ms = ast_remaining_ms(start, timeout_ms))) {
+               struct ast_channel *rchan;
+               int outfd = -1;
 
                errno = 0;
                /* While ast_waitfor_nandfds tries to help by reducing the timeout by how much was waited,
@@ -3478,32 +3251,39 @@ int ast_waitfordigit_full(struct ast_channel *c, int timeout_ms, int audiofd, in
                        if (errno == 0 || errno == EINTR)
                                continue;
                        ast_log(LOG_WARNING, "Wait failed (%s)\n", strerror(errno));
-                       ast_clear_flag(ast_channel_flags(c), AST_FLAG_END_DTMF_ONLY);
+                       ast_channel_clear_flag(c, AST_FLAG_END_DTMF_ONLY);
                        return -1;
                } else if (outfd > -1) {
                        /* The FD we were watching has something waiting */
                        ast_log(LOG_WARNING, "The FD we were waiting for has something waiting. Waitfordigit returning numeric 1\n");
-                       ast_clear_flag(ast_channel_flags(c), AST_FLAG_END_DTMF_ONLY);
+                       ast_channel_clear_flag(c, AST_FLAG_END_DTMF_ONLY);
                        return 1;
                } else if (rchan) {
                        int res;
                        struct ast_frame *f = ast_read(c);
-                       if (!f)
+
+                       if (!f) {
+                               ast_channel_clear_flag(c, AST_FLAG_END_DTMF_ONLY);
+
                                return -1;
+                       }
 
                        switch (f->frametype) {
                        case AST_FRAME_DTMF_BEGIN:
                                break;
                        case AST_FRAME_DTMF_END:
                                res = f->subclass.integer;
-                               ast_frfree(f);
-                               ast_clear_flag(ast_channel_flags(c), AST_FLAG_END_DTMF_ONLY);
-                               return res;
+                               if (!breakon || strchr(breakon, res)) {
+                                       ast_frfree(f);
+                                       ast_channel_clear_flag(c, AST_FLAG_END_DTMF_ONLY);
+                                       return res;
+                               }
+                               break;
                        case AST_FRAME_CONTROL:
                                switch (f->subclass.integer) {
                                case AST_CONTROL_HANGUP:
                                        ast_frfree(f);
-                                       ast_clear_flag(ast_channel_flags(c), AST_FLAG_END_DTMF_ONLY);
+                                       ast_channel_clear_flag(c, AST_FLAG_END_DTMF_ONLY);
                                        return -1;
                                case AST_CONTROL_STREAM_STOP:
                                case AST_CONTROL_STREAM_SUSPEND:
@@ -3514,7 +3294,7 @@ int ast_waitfordigit_full(struct ast_channel *c, int timeout_ms, int audiofd, in
                                         * that perform stream control will handle this. */
                                        res = f->subclass.integer;
                                        ast_frfree(f);
-                                       ast_clear_flag(ast_channel_flags(c), AST_FLAG_END_DTMF_ONLY);
+                                       ast_channel_clear_flag(c, AST_FLAG_END_DTMF_ONLY);
                                        return res;
                                case AST_CONTROL_PVT_CAUSE_CODE:
                                case AST_CONTROL_RINGING:
@@ -3549,7 +3329,7 @@ int ast_waitfordigit_full(struct ast_channel *c, int timeout_ms, int audiofd, in
                }
        }
 
-       ast_clear_flag(ast_channel_flags(c), AST_FLAG_END_DTMF_ONLY);
+       ast_channel_clear_flag(c, AST_FLAG_END_DTMF_ONLY);
 
        return 0; /* Time is up */
 }
@@ -3716,11 +3496,12 @@ static inline int calc_monitor_jump(int samples, int sample_rate, int seek_rate)
        return samples;
 }
 
-static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
+static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio, int dropnondefault)
 {
        struct ast_frame *f = NULL;     /* the return value */
        int prestate;
        int cause = 0;
+       struct ast_stream *stream = NULL, *default_stream = NULL;
 
        /* this function is very long so make sure there is only one return
         * point at the end (there are only two exceptions to this).
@@ -3877,6 +3658,17 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
                        default:
                                break;
                        }
+               } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) {
+                       if (ast_channel_tech(chan) && ast_channel_tech(chan)->read_stream) {
+                               stream = ast_stream_topology_get_stream(ast_channel_get_stream_topology(chan), f->stream_num);
+                               default_stream = ast_channel_get_default_stream(chan, ast_format_get_type(f->subclass.format));
+                       } else {
+                               /* Since this channel driver does not support multistream determine the default stream this frame
+                                * originated from and update the frame to include it.
+                                */
+                               stream = default_stream = ast_channel_get_default_stream(chan, ast_format_get_type(f->subclass.format));
+                               f->stream_num = ast_stream_get_position(stream);
+                       }
                }
        } else {
                ast_channel_blocker_set(chan, pthread_self());
@@ -3889,15 +3681,37 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
                        }
                        /* Clear the exception flag */
                        ast_clear_flag(ast_channel_flags(chan), AST_FLAG_EXCEPTION);
-               } else if (ast_channel_tech(chan) && ast_channel_tech(chan)->read)
+               } else if (ast_channel_tech(chan) && ast_channel_tech(chan)->read_stream) {
+                       f = ast_channel_tech(chan)->read_stream(chan);
+
+                       /* This channel driver supports multistream so the stream_num on the frame is valid, the only
+                        * thing different is that we need to find the default stream so we know whether to invoke the
+                        * default stream logic or not (such as transcoding).
+                        */
+                       if (f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)) {
+                               stream = ast_stream_topology_get_stream(ast_channel_get_stream_topology(chan), f->stream_num);
+                               default_stream = ast_channel_get_default_stream(chan, ast_format_get_type(f->subclass.format));
+                       }
+               } else if (ast_channel_tech(chan) && ast_channel_tech(chan)->read) {
                        f = ast_channel_tech(chan)->read(chan);
+
+                       /* Since this channel driver does not support multistream determine the default stream this frame
+                        * originated from and update the frame to include it.
+                        */
+                       if (f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)) {
+                               stream = default_stream = ast_channel_get_default_stream(chan, ast_format_get_type(f->subclass.format));
+                               f->stream_num = ast_stream_get_position(stream);
+                       }
+               }
                else
                        ast_log(LOG_WARNING, "No read routine on channel %s\n", ast_channel_name(chan));
        }
 
-       /* Perform the framehook read event here. After the frame enters the framehook list
-        * there is no telling what will happen, <insert mad scientist laugh here>!!! */
-       f = ast_framehook_list_read_event(ast_channel_framehooks(chan), f);
+       if (stream == default_stream) {
+               /* Perform the framehook read event here. After the frame enters the framehook list
+                * there is no telling what will happen, <insert mad scientist laugh here>!!! */
+               f = ast_framehook_list_read_event(ast_channel_framehooks(chan), f);
+       }
 
        /*
         * Reset the recorded file descriptor that triggered this read so that we can
@@ -3909,6 +3723,7 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
                struct ast_frame *readq_tail = AST_LIST_LAST(ast_channel_readq(chan));
                struct ast_control_read_action_payload *read_action_payload;
                struct ast_party_connected_line connected;
+               int hooked = 0;
 
                /* if the channel driver returned more than one frame, stuff the excess
                   into the readq for the next ast_read call
@@ -3919,18 +3734,28 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
                        AST_LIST_NEXT(f, frame_list) = NULL;
                }
 
+               if (dropnondefault && stream != default_stream) {
+                       /* If the frame originates from a non-default stream and the caller can not handle other streams
+                        * absorb the frame and replace it with a null one instead.
+                        */
+                       ast_frfree(f);
+                       f = &ast_null_frame;
+               }
+
                switch (f->frametype) {
                case AST_FRAME_CONTROL:
                        if (f->subclass.integer == AST_CONTROL_ANSWER) {
-                               if (!ast_test_flag(ast_channel_flags(chan), AST_FLAG_OUTGOING)) {
-                                       ast_debug(1, "Ignoring answer on an inbound call!\n");
-                                       ast_frfree(f);
-                                       f = &ast_null_frame;
-                               } else if (prestate == AST_STATE_UP && ast_channel_is_bridged(chan)) {
+                               if (prestate == AST_STATE_UP && ast_channel_is_bridged(chan)) {
                                        ast_debug(1, "Dropping duplicate answer!\n");
                                        ast_frfree(f);
                                        f = &ast_null_frame;
                                } else {
+                                       /*
+                                        * Mark when outgoing channel answered so we can know how
+                                        * long the channel has been up.
+                                        */
+                                       set_channel_answer_time(chan);
+
                                        ast_setstate(chan, AST_STATE_UP);
                                }
                        } else if (f->subclass.integer == AST_CONTROL_READ_ACTION) {
@@ -3957,6 +3782,19 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
                                }
                                ast_frfree(f);
                                f = &ast_null_frame;
+                       } else if (f->subclass.integer == AST_CONTROL_STREAM_TOPOLOGY_REQUEST_CHANGE && dropnondefault) {
+                               /* The caller of this function is incapable of handling streams so we don't accept the change request
+                                * and stick to the streams currently on the channel.
+                                */
+                               ast_channel_stream_topology_changed(chan, ast_channel_get_stream_topology(chan));
+                               ast_frfree(f);
+                               f = &ast_null_frame;
+                       } else if (f->subclass.integer == AST_CONTROL_STREAM_TOPOLOGY_CHANGED && dropnondefault) {
+                               /* The caller of this function is incapable of handling streams so we absord the notification that the
+                                * stream topology has changed.
+                                */
+                               ast_frfree(f);
+                               f = &ast_null_frame;
                        }
                        break;
                case AST_FRAME_DTMF_END:
@@ -4093,6 +3931,11 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
                        }
                        break;
                case AST_FRAME_VOICE:
+                       /* If media was received from a non-default stream don't perform any actions, let it just go through */
+                       if (stream != default_stream) {
+                               break;
+                       }
+
                        /* The EMULATE_DTMF flag must be cleared here as opposed to when the duration
                         * is reached , because we want to make sure we pass at least one
                         * voice frame through before starting the next digit, to ensure a gap
@@ -4131,79 +3974,166 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
                                        ast_frfree(f);
                                        f = &ast_null_frame;
                                }
-                       } else if ((f->frametype == AST_FRAME_VOICE) && ast_format_cap_iscompatible_format(ast_channel_nativeformats(chan), f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
-                               /* This frame is not one of the current native formats -- drop it on the floor */
-                               struct ast_str *codec_buf = ast_str_alloca(64);
-                               ast_log(LOG_NOTICE, "Dropping incompatible voice frame on %s of format %s since our native format has changed to %s\n",
-                                       ast_channel_name(chan), ast_format_get_name(f->subclass.format), ast_format_cap_get_names(ast_channel_nativeformats(chan), &codec_buf));
-                               ast_frfree(f);
-                               f = &ast_null_frame;
-                       } else if ((f->frametype == AST_FRAME_VOICE)) {
-                               /* Send frame to audiohooks if present */
-                               if (ast_channel_audiohooks(chan)) {
-                                       struct ast_frame *old_frame = f;
-                                       f = ast_audiohook_write_list(chan, ast_channel_audiohooks(chan), AST_AUDIOHOOK_DIRECTION_READ, f);
-                                       if (old_frame != f)
-                                               ast_frfree(old_frame);
+                               break;
+                       }
+                       if (f->frametype != AST_FRAME_VOICE) {
+                               break;
+                       }
+                       if (ast_format_cmp(f->subclass.format, ast_channel_rawreadformat(chan)) != AST_FORMAT_CMP_EQUAL
+                               && ast_format_cmp(f->subclass.format, ast_channel_readformat(chan)) != AST_FORMAT_CMP_EQUAL) {
+                               struct ast_format *core_format;
+
+                               /*
+                                * Note: This frame may not be one of the current native
+                                * formats.  We may have gotten it out of the read queue from
+                                * a previous multi-frame translation, from a framehook
+                                * injected frame, or the device we're talking to isn't
+                                * respecting negotiated formats.  Regardless we will accept
+                                * all frames.
+                                *
+                                * Update the read translation path to handle the new format
+                                * that just came in.  If the core wants slinear we need to
+                                * setup a new translation path because the core is usually
+                                * doing something with the audio itself and may not handle
+                                * any other format.  e.g., Softmix bridge, holding bridge
+                                * announcer channel, recording, AMD...  Otherwise, we'll
+                                * setup to pass the frame as is to the core.  In this case
+                                * the core doesn't care.  The channel is likely in
+                                * autoservice, safesleep, or the channel is in a bridge.
+                                * Let the bridge technology deal with format compatibility
+                                * between the channels in the bridge.
+                                *
+                                * Beware of the transcode_via_slin and genericplc options as
+                                * they force any transcoding to go through slin on a bridge.
+                                * Unfortunately transcode_via_slin is enabled by default and
+                                * genericplc is enabled in the codecs.conf.sample file.
+                                *
+                                * XXX Only updating translation to slinear frames has some
+                                * corner cases if slinear is one of the native formats and
+                                * there are different sample rates involved.  We might wind
+                                * up with conflicting translation paths between channels
+                                * where the read translation path on this channel reduces
+                                * the sample rate followed by a write translation path on
+                                * the peer channel that increases the sample rate.
+                                */
+                               core_format = ast_channel_readformat(chan);
+                               if (!ast_format_cache_is_slinear(core_format)) {
+                                       core_format = f->subclass.format;
                                }
-                               if (ast_channel_monitor(chan) && ast_channel_monitor(chan)->read_stream ) {
-                                       /* XXX what does this do ? */
+                               if (ast_set_read_format_path(chan, f->subclass.format, core_format)) {
+                                       /* Drop frame.  We couldn't make it compatible with the core. */
+                                       ast_frfree(f);
+                                       f = &ast_null_frame;
+                                       break;
+                               }
+                       }
+                       /*
+                        * Send frame to audiohooks if present, if frametype is linear, to preserve
+                        * functional compatibility with previous behavior. If not linear, hold off
+                        * until transcoding is done where we are more likely to have a linear frame
+                        */
+                       if (ast_channel_audiohooks(chan) && ast_format_cache_is_slinear(f->subclass.format)) {
+                               /* Place hooked after declaration */
+                               struct ast_frame *old_frame = f;
+                               hooked = 1;
+
+                               f = ast_audiohook_write_list(chan, ast_channel_audiohooks(chan), AST_AUDIOHOOK_DIRECTION_READ, f);
+                               if (old_frame != f) {
+                                       ast_frfree(old_frame);
+                               }
+                       }
+
+                       if (ast_channel_monitor(chan) && ast_channel_monitor(chan)->read_stream) {
+                               /* XXX what does this do ? */
 #ifndef MONITOR_CONSTANT_DELAY
-                                       int jump = ast_channel_outsmpl(chan) - ast_channel_insmpl(chan) - 4 * f->samples;
-                                       if (jump >= 0) {
-                                               jump = calc_monitor_jump((ast_channel_outsmpl(chan) - ast_channel_insmpl(chan)),
-                                                                        ast_format_get_sample_rate(f->subclass.format),
-                                                                        ast_format_get_sample_rate(ast_channel_monitor(chan)->read_stream->fmt->format));
-                                               if (ast_seekstream(ast_channel_monitor(chan)->read_stream, jump, SEEK_FORCECUR) == -1) {
-                                                       ast_log(LOG_WARNING, "Failed to perform seek in monitoring read stream, synchronization between the files may be broken\n");
-                                               }
-                                               ast_channel_insmpl_set(chan, ast_channel_insmpl(chan) + (ast_channel_outsmpl(chan) - ast_channel_insmpl(chan)) + f->samples);
-                                       } else {
-                                               ast_channel_insmpl_set(chan, ast_channel_insmpl(chan) + f->samples);
+                               int jump = ast_channel_outsmpl(chan) - ast_channel_insmpl(chan) - 4 * f->samples;
+                               if (jump >= 0) {
+                                       jump = calc_monitor_jump((ast_channel_outsmpl(chan) - ast_channel_insmpl(chan)),
+                                               ast_format_get_sample_rate(f->subclass.format),
+                                               ast_format_get_sample_rate(ast_channel_monitor(chan)->read_stream->fmt->format));
+                                       if (ast_seekstream(ast_channel_monitor(chan)->read_stream, jump, SEEK_FORCECUR) == -1) {
+                                               ast_log(LOG_WARNING, "Failed to perform seek in monitoring read stream, synchronization between the files may be broken\n");
                                        }
+                                       ast_channel_insmpl_set(chan, ast_channel_insmpl(chan) + (ast_channel_outsmpl(chan) - ast_channel_insmpl(chan)) + f->samples);
+                               } else {
+                                       ast_channel_insmpl_set(chan, ast_channel_insmpl(chan) + f->samples);
+                               }
 #else
-                                       int jump = calc_monitor_jump((ast_channel_outsmpl(chan) - ast_channel_insmpl(chan)),
-                                                                    ast_format_get_sample_rate(f->subclass.codec),
-                                                                    ast_format_get_sample_rate(ast_channel_monitor(chan)->read_stream->fmt->format));
-                                       if (jump - MONITOR_DELAY >= 0) {
-                                               if (ast_seekstream(ast_channel_monitor(chan)->read_stream, jump - f->samples, SEEK_FORCECUR) == -1)
-                                                       ast_log(LOG_WARNING, "Failed to perform seek in monitoring read stream, synchronization between the files may be broken\n");
-                                               ast_channel_insmpl(chan) += ast_channel_outsmpl(chan) - ast_channel_insmpl(chan);
-                                       } else
-                                               ast_channel_insmpl(chan) += f->samples;
-#endif
-                                       if (ast_channel_monitor(chan)->state == AST_MONITOR_RUNNING) {
-                                               if (ast_writestream(ast_channel_monitor(chan)->read_stream, f) < 0)
-                                                       ast_log(LOG_WARNING, "Failed to write data to channel monitor read stream\n");
+                               int jump = calc_monitor_jump((ast_channel_outsmpl(chan) - ast_channel_insmpl(chan)),
+                                       ast_format_get_sample_rate(f->subclass.format),
+                                       ast_format_get_sample_rate(ast_channel_monitor(chan)->read_stream->fmt->format));
+                               if (jump - MONITOR_DELAY >= 0) {
+                                       if (ast_seekstream(ast_channel_monitor(chan)->read_stream, jump - f->samples, SEEK_FORCECUR) == -1) {
+                                               ast_log(LOG_WARNING, "Failed to perform seek in monitoring read stream, synchronization between the files may be broken\n");
                                        }
+                                       ast_channel_insmpl(chan) += ast_channel_outsmpl(chan) - ast_channel_insmpl(chan);
+                               } else {
+                                       ast_channel_insmpl(chan) += f->samples;
                                }
+#endif
+                               if (ast_channel_monitor(chan)->state == AST_MONITOR_RUNNING) {
+                                       if (ast_writestream(ast_channel_monitor(chan)->read_stream, f) < 0)
+                                               ast_log(LOG_WARNING, "Failed to write data to channel monitor read stream\n");
+                               }
+                       }
 
-                               if (ast_channel_readtrans(chan) && (f = ast_translate(ast_channel_readtrans(chan), f, 1)) == NULL) {
+                       if (ast_channel_readtrans(chan)
+                               && ast_format_cmp(f->subclass.format, ast_channel_rawreadformat(chan)) == AST_FORMAT_CMP_EQUAL) {
+                               f = ast_translate(ast_channel_readtrans(chan), f, 1);
+                               if (!f) {
                                        f = &ast_null_frame;
                                }
+                       }
 
-                               /* it is possible for the translation process on chan->readtrans to have
-                                  produced multiple frames from the single input frame we passed it; if
-                                  this happens, queue the additional frames *before* the frames we may
-                                  have queued earlier. if the readq was empty, put them at the head of
-                                  the queue, and if it was not, put them just after the frame that was
-                                  at the end of the queue.
-                               */
-                               if (AST_LIST_NEXT(f, frame_list)) {
-                                       if (!readq_tail) {
-                                               ast_queue_frame_head(chan, AST_LIST_NEXT(f, frame_list));
-                                       } else {
-                                               __ast_queue_frame(chan, AST_LIST_NEXT(f, frame_list), 0, readq_tail);
-                                       }
-                                       ast_frfree(AST_LIST_NEXT(f, frame_list));
-                                       AST_LIST_NEXT(f, frame_list) = NULL;
+                       /* Second chance at hooking a linear frame, also the last chance */
+                       if (ast_channel_audiohooks(chan) && !hooked) {
+                               struct ast_frame *old_frame = f;
+
+                               f = ast_audiohook_write_list(chan, ast_channel_audiohooks(chan), AST_AUDIOHOOK_DIRECTION_READ, f);
+                               if (old_frame != f) {
+                                       ast_frfree(old_frame);
                                }
+                       }
+
+                       /*
+                        * It is possible for the translation process on the channel to have
+                        * produced multiple frames from the single input frame we passed it; if
+                        * this happens, queue the additional frames *before* the frames we may
+                        * have queued earlier. if the readq was empty, put them at the head of
+                        * the queue, and if it was not, put them just after the frame that was
+                        * at the end of the queue.
+                        */
+                       if (AST_LIST_NEXT(f, frame_list)) {
+                               struct ast_frame *cur, *multi_frame = AST_LIST_NEXT(f, frame_list);
 
-                               /* Run generator sitting on the line if timing device not available
-                               * and synchronous generation of outgoing frames is necessary       */
-                               ast_read_generator_actions(chan, f);
+                               /* Mark these frames as being re-queued */
+                               for (cur = multi_frame; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
+                                       ast_set_flag(cur, AST_FRFLAG_REQUEUED);
+                               }
+
+                               if (!readq_tail) {
+                                       ast_queue_frame_head(chan, multi_frame);
+                               } else {
+                                       __ast_queue_frame(chan, multi_frame, 0, readq_tail);
+                               }
+                               ast_frfree(multi_frame);
+                               AST_LIST_NEXT(f, frame_list) = NULL;
                        }
+
+                       /*
+                        * Run generator sitting on the line if timing device not available
+                        * and synchronous generation of outgoing frames is necessary
+                        */
+                       ast_read_generator_actions(chan, f);
                        break;
+               case AST_FRAME_RTCP:
+                       /* Incoming RTCP feedback needs to get to the translator for
+                        * outgoing media, which means we treat it as an ast_write */
+                       if (ast_channel_writetrans(chan)) {
+                               ast_translate(ast_channel_writetrans(chan), f, 0);
+                       }
+                       ast_frfree(f);
+                       f = &ast_null_frame;
                default:
                        /* Just pass it on! */
                        break;
@@ -4240,12 +4170,22 @@ done:
 
 struct ast_frame *ast_read(struct ast_channel *chan)
 {
-       return __ast_read(chan, 0);
+       return __ast_read(chan, 0, 1);
+}
+
+struct ast_frame *ast_read_stream(struct ast_channel *chan)
+{
+       return __ast_read(chan, 0, 0);
 }
 
 struct ast_frame *ast_read_noaudio(struct ast_channel *chan)
 {
-       return __ast_read(chan, 1);
+       return __ast_read(chan, 1, 1);
+}
+
+struct ast_frame *ast_read_stream_noaudio(struct ast_channel *chan)
+{
+       return __ast_read(chan, 1, 0);
 }
 
 int ast_indicate(struct ast_channel *chan, int condition)
@@ -4285,6 +4225,10 @@ static int attribute_const is_visible_indication(enum ast_control_frame_type con
        case AST_CONTROL_MCID:
        case AST_CONTROL_UPDATE_RTP_PEER:
        case AST_CONTROL_PVT_CAUSE_CODE:
+       case AST_CONTROL_MASQUERADE_NOTIFY:
+       case AST_CONTROL_STREAM_TOPOLOGY_REQUEST_CHANGE:
+       case AST_CONTROL_STREAM_TOPOLOGY_CHANGED:
+       case AST_CONTROL_STREAM_TOPOLOGY_SOURCE_CHANGED:
        case AST_CONTROL_STREAM_STOP:
        case AST_CONTROL_STREAM_SUSPEND:
        case AST_CONTROL_STREAM_REVERSE:
@@ -4437,65 +4381,47 @@ static int indicate_redirecting(struct ast_channel *chan, const void *data, size
        return res ? -1 : 0;
 }
 
-int ast_indicate_data(struct ast_channel *chan, int _condition,
-               const void *data, size_t datalen)
+static int indicate_data_internal(struct ast_channel *chan, int _condition, const void *data, size_t datalen)
 {
        /* By using an enum, we'll get compiler warnings for values not handled
         * in switch statements. */
        enum ast_control_frame_type condition = _condition;
        struct ast_tone_zone_sound *ts = NULL;
+       const struct ast_control_t38_parameters *t38_parameters;
        int res;
-       /* this frame is used by framehooks. if it is set, we must free it at the end of this function */
-       struct ast_frame *awesome_frame = NULL;
-
-       ast_channel_lock(chan);
-
-       /* Don't bother if the channel is about to go away, anyway. */
-       if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE) || ast_check_hangup(chan)) {
-               res = -1;
-               goto indicate_cleanup;
-       }
-
-       if (!ast_framehook_list_is_empty(ast_channel_framehooks(chan))) {
-               /* Do framehooks now, do it, go, go now */
-               struct ast_frame frame = {
-                       .frametype = AST_FRAME_CONTROL,
-                       .subclass.integer = condition,
-                       .data.ptr = (void *) data, /* this cast from const is only okay because we do the ast_frdup below */
-                       .datalen = datalen
-               };
-
-               /* we have now committed to freeing this frame */
-               awesome_frame = ast_frdup(&frame);
-
-               /* who knows what we will get back! the anticipation is killing me. */
-               if (!(awesome_frame = ast_framehook_list_write_event(ast_channel_framehooks(chan), awesome_frame))
-                       || awesome_frame->frametype != AST_FRAME_CONTROL) {
-                       res = 0;
-                       goto indicate_cleanup;
-               }
-
-               condition = awesome_frame->subclass.integer;
-               data = awesome_frame->data.ptr;
-               datalen = awesome_frame->datalen;
-       }
 
        switch (condition) {
        case AST_CONTROL_CONNECTED_LINE:
                if (indicate_connected_line(chan, data, datalen)) {
                        res = 0;
-                       goto indicate_cleanup;
+                       return res;
                }
                break;
        case AST_CONTROL_REDIRECTING:
                if (indicate_redirecting(chan, data, datalen)) {
                        res = 0;
-                       goto indicate_cleanup;
+                       return res;
                }
                break;
        case AST_CONTROL_HOLD:
        case AST_CONTROL_UNHOLD:
-               ast_channel_hold_state_set(chan, condition);
+               ast_channel_hold_state_set(chan, _condition);
+               break;
+       case AST_CONTROL_T38_PARAMETERS:
+               t38_parameters = data;
+               switch (t38_parameters->request_response) {
+               case AST_T38_REQUEST_NEGOTIATE:
+               case AST_T38_NEGOTIATED:
+                       ast_channel_set_is_t38_active_nolock(chan, 1);
+                       break;
+               case AST_T38_REQUEST_TERMINATE:
+               case AST_T38_TERMINATED:
+               case AST_T38_REFUSED:
+                       ast_channel_set_is_t38_active_nolock(chan, 0);
+                       break;
+               default:
+                       break;
+               }
                break;
        default:
                break;
@@ -4503,7 +4429,7 @@ int ast_indicate_data(struct ast_channel *chan, int _condition,
 
        if (is_visible_indication(condition)) {
                /* A new visible indication is requested. */
-               ast_channel_visible_indication_set(chan, condition);
+               ast_channel_visible_indication_set(chan, _condition);
        } else if (condition == AST_CONTROL_UNHOLD || _condition < 0) {
                /* Visible indication is cleared/stopped. */
                ast_channel_visible_indication_set(chan, 0);
@@ -4511,7 +4437,7 @@ int ast_indicate_data(struct ast_channel *chan, int _condition,
 
        if (ast_channel_tech(chan)->indicate) {
                /* See if the channel driver can handle this condition. */
-               res = ast_channel_tech(chan)->indicate(chan, condition, data, datalen);
+               res = ast_channel_tech(chan)->indicate(chan, _condition, data, datalen);
        } else {
                res = -1;
        }
@@ -4519,7 +4445,7 @@ int ast_indicate_data(struct ast_channel *chan, int _condition,
        if (!res) {
                /* The channel driver successfully handled this indication */
                res = 0;
-               goto indicate_cleanup;
+               return res;
        }
 
        /* The channel driver does not support this indication, let's fake
@@ -4532,7 +4458,7 @@ int ast_indicate_data(struct ast_channel *chan, int _condition,
                /* Stop any tones that are playing */
                ast_playtones_stop(chan);
                res = 0;
-               goto indicate_cleanup;
+               return res;
        }
 
        /* Handle conditions that we have tones for. */
@@ -4540,7 +4466,7 @@ int ast_indicate_data(struct ast_channel *chan, int _condition,
        case _XXX_AST_CONTROL_T38:
                /* deprecated T.38 control frame */
                res = -1;
-               goto indicate_cleanup;
+               return res;
        case AST_CONTROL_T38_PARAMETERS:
                /* there is no way to provide 'default' behavior for these
                 * control frames, so we need to return failure, but there
@@ -4549,7 +4475,7 @@ int ast_indicate_data(struct ast_channel *chan, int _condition,
                 * so just return right now. in addition, we want to return
                 * whatever value the channel driver returned, in case it
                 * has some meaning.*/
-               goto indicate_cleanup;
+               return res;
        case AST_CONTROL_RINGING:
                ts = ast_get_indication_tone(ast_channel_zone(chan), "ring");
                /* It is common practice for channel drivers to return -1 if trying
@@ -4599,7 +4525,11 @@ int ast_indicate_data(struct ast_channel *chan, int _condition,
        case AST_CONTROL_AOC:
        case AST_CONTROL_END_OF_Q:
        case AST_CONTROL_MCID:
+       case AST_CONTROL_MASQUERADE_NOTIFY:
        case AST_CONTROL_UPDATE_RTP_PEER:
+       case AST_CONTROL_STREAM_TOPOLOGY_REQUEST_CHANGE:
+       case AST_CONTROL_STREAM_TOPOLOGY_CHANGED:
+       case AST_CONTROL_STREAM_TOPOLOGY_SOURCE_CHANGED:
        case AST_CONTROL_STREAM_STOP:
        case AST_CONTROL_STREAM_SUSPEND:
        case AST_CONTROL_STREAM_REVERSE:
@@ -4618,6 +4548,11 @@ int ast_indicate_data(struct ast_channel *chan, int _condition,
                /* We have a tone to play, yay. */
                ast_debug(1, "Driver for channel '%s' does not support indication %u, emulating it\n", ast_channel_name(chan), condition);
                res = ast_playtones_start(chan, 0, ts->data, 1);
+               if (!res) {
+                       ast_test_suite_event_notify("RINGING_INBAND",
+                                       "Channel: %s\r\n",
+                                       ast_channel_name(chan));
+               }
                ts = ast_tone_zone_sound_unref(ts);
        }
 
@@ -4626,6 +4561,53 @@ int ast_indicate_data(struct ast_channel *chan, int _condition,
                ast_log(LOG_WARNING, "Unable to handle indication %u for '%s'\n", condition, ast_channel_name(chan));
        }
 
+       return res;
+}
+
+int ast_indicate_data(struct ast_channel *chan, int _condition, const void *data, size_t datalen)
+{
+       int res;
+       /* this frame is used by framehooks. if it is set, we must free it at the end of this function */
+       struct ast_frame *awesome_frame = NULL;
+
+       ast_channel_lock(chan);
+
+       /* Don't bother if the channel is about to go away, anyway. */
+       if ((ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE)
+                       || (ast_check_hangup(chan) && !ast_channel_is_leaving_bridge(chan)))
+               && _condition != AST_CONTROL_MASQUERADE_NOTIFY) {
+               res = -1;
+               goto indicate_cleanup;
+       }
+
+       if (!ast_framehook_list_is_empty(ast_channel_framehooks(chan))) {
+               /* Do framehooks now, do it, go, go now */
+               struct ast_frame frame = {
+                       .frametype = AST_FRAME_CONTROL,
+                       .subclass.integer = _condition,
+                       .data.ptr = (void *) data, /* this cast from const is only okay because we do the ast_frdup below */
+                       .datalen = datalen
+               };
+
+               /* we have now committed to freeing this frame */
+               awesome_frame = ast_frdup(&frame);
+
+               /* who knows what we will get back! the anticipation is killing me. */
+               awesome_frame = ast_framehook_list_write_event(ast_channel_framehooks(chan),
+                       awesome_frame);
+               if (!awesome_frame
+                       || awesome_frame->frametype != AST_FRAME_CONTROL) {
+                       res = 0;
+                       goto indicate_cleanup;
+               }
+
+               _condition = awesome_frame->subclass.integer;
+               data = awesome_frame->data.ptr;
+               datalen = awesome_frame->datalen;
+       }
+
+       res = indicate_data_internal(chan, _condition, data, datalen);
+
 indicate_cleanup:
        ast_channel_unlock(chan);
        if (awesome_frame) {
@@ -4700,16 +4682,18 @@ int ast_sendtext(struct ast_channel *chan, const char *text)
        if (ast_channel_tech(chan)->write_text && (ast_format_cap_has_type(ast_channel_nativeformats(chan), AST_MEDIA_TYPE_TEXT))) {
                struct ast_frame f;
 
+               memset(&f, 0, sizeof(f));
                f.frametype = AST_FRAME_TEXT;
                f.src = "DIALPLAN";
                f.mallocd = AST_MALLOCD_DATA;
                f.datalen = strlen(text);
                f.data.ptr = ast_strdup(text);
-               f.offset = 0;
-               f.seqno = 0;
-
                f.subclass.format = ast_format_t140;
-               res = ast_channel_tech(chan)->write_text(chan, &f);
+
+               if (f.data.ptr) {
+                       res = ast_channel_tech(chan)->write_text(chan, &f);
+                       ast_frfree(&f);
+               }
        } else if (ast_channel_tech(chan)->send_text) {
                res = ast_channel_tech(chan)->send_text(chan, text);
        }
@@ -4931,9 +4915,16 @@ static void apply_plc(struct ast_channel *chan, struct ast_frame *frame)
 
 int ast_write(struct ast_channel *chan, struct ast_frame *fr)
 {
+       return ast_write_stream(chan, -1, fr);
+}
+
+int ast_write_stream(struct ast_channel *chan, int stream_num, struct ast_frame *fr)
+{
+       struct ast_stream *stream = NULL, *default_stream = NULL;
        int res = -1;
        struct ast_frame *f = NULL;
        int count = 0;
+       int hooked = 0;
 
        /*Deadlock avoidance*/
        while(ast_channel_trylock(chan)) {
@@ -4944,13 +4935,39 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
                }
                usleep(1);
        }
+
        /* Stop if we're a zombie or need a soft hangup */
-       if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE) || ast_check_hangup(chan))
+       if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE) || ast_check_hangup(chan)) {
                goto done;
+       }
+
+       if (stream_num >= 0) {
+               /* If we were told to write to an explicit stream then allow this frame through, no matter
+                * if the type is expected or not (a framehook could change)
+                */
+               if (stream_num >= ast_stream_topology_get_count(ast_channel_get_stream_topology(chan))) {
+                       goto done;
+               }
+               stream = ast_stream_topology_get_stream(ast_channel_get_stream_topology(chan), stream_num);
+               default_stream = ast_channel_get_default_stream(chan, ast_stream_get_type(stream));
+       } else if (fr->frametype == AST_FRAME_VOICE || fr->frametype == AST_FRAME_VIDEO || fr->frametype == AST_FRAME_MODEM) {
+               /* If we haven't been told of a stream then we need to figure out which once we need */
+               enum ast_media_type type = AST_MEDIA_TYPE_UNKNOWN;
+
+               /* Some frame types have a fixed media type */
+               if (fr->frametype == AST_FRAME_VOICE || fr->frametype == AST_FRAME_VIDEO) {
+                       type = ast_format_get_type(fr->subclass.format);
+               } else if (fr->frametype == AST_FRAME_MODEM) {
+                       type = AST_MEDIA_TYPE_IMAGE;
+               }
+
+               /* No stream was specified, so use the default one */
+               stream = default_stream = ast_channel_get_default_stream(chan, type);
+       }
 
        /* Perform the framehook write event here. After the frame enters the framehook list
         * there is no telling what will happen, how awesome is that!!! */
-       if (!(fr = ast_framehook_list_write_event(ast_channel_framehooks(chan), fr))) {
+       if ((stream == default_stream) && !(fr = ast_framehook_list_write_event(ast_channel_framehooks(chan), fr))) {
                res = 0;
                goto done;
        }
@@ -4968,10 +4985,15 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
                                res = ast_senddigit_end(chan, fr->subclass.integer, fr->len);
                                ast_channel_lock(chan);
                                CHECK_BLOCKING(chan);
-                       } else if (fr->frametype == AST_FRAME_CONTROL && fr->subclass.integer == AST_CONTROL_UNHOLD) {
-                               /* This is a side case where Echo is basically being called and the person put themselves on hold and took themselves off hold */
-                               res = (ast_channel_tech(chan)->indicate == NULL) ? 0 :
-                                       ast_channel_tech(chan)->indicate(chan, fr->subclass.integer, fr->data.ptr, fr->datalen);
+                       } else if (fr->frametype == AST_FRAME_CONTROL
+                               && fr->subclass.integer == AST_CONTROL_UNHOLD) {
+                               /*
+                                * This is a side case where Echo is basically being called
+                                * and the person put themselves on hold and took themselves
+                                * off hold.
+                                */
+                               indicate_data_internal(chan, fr->subclass.integer, fr->data.ptr,
+                                       fr->datalen);
                        }
                        res = 0;        /* XXX explain, why 0 ? */
                        goto done;
@@ -4983,8 +5005,8 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
        CHECK_BLOCKING(chan);
        switch (fr->frametype) {
        case AST_FRAME_CONTROL:
-               res = (ast_channel_tech(chan)->indicate == NULL) ? 0 :
-                       ast_channel_tech(chan)->indicate(chan, fr->subclass.integer, fr->data.ptr, fr->datalen);
+               indicate_data_internal(chan, fr->subclass.integer, fr->data.ptr, fr->datalen);
+               res = 0;
                break;
        case AST_FRAME_DTMF_BEGIN:
                if (ast_channel_audiohooks(chan)) {
@@ -5031,45 +5053,88 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
                break;
        case AST_FRAME_VIDEO:
                /* XXX Handle translation of video codecs one day XXX */
-               res = (ast_channel_tech(chan)->write_video == NULL) ? 0 :
-                       ast_channel_tech(chan)->write_video(chan, fr);
+               if (ast_channel_tech(chan)->write_stream) {
+                       if (stream) {
+                               res = ast_channel_tech(chan)->write_stream(chan, ast_stream_get_position(stream), fr);
+                       } else {
+                               res = 0;
+                       }
+               } else if ((stream == default_stream) && ast_channel_tech(chan)->write_video) {
+                       res = ast_channel_tech(chan)->write_video(chan, fr);
+               } else {
+                       res = 0;
+               }
                break;
        case AST_FRAME_MODEM:
-               res = (ast_channel_tech(chan)->write == NULL) ? 0 :
-                       ast_channel_tech(chan)->write(chan, fr);
+               if (ast_channel_tech(chan)->write_stream) {
+                       if (stream) {
+                               res = ast_channel_tech(chan)->write_stream(chan, ast_stream_get_position(stream), fr);
+                       } else {
+                               res = 0;
+                       }
+               } else if ((stream == default_stream) && ast_channel_tech(chan)->write) {
+                       res = ast_channel_tech(chan)->write(chan, fr);
+               } else {
+                       res = 0;
+               }
                break;
        case AST_FRAME_VOICE:
-               if (ast_channel_tech(chan)->write == NULL)
-                       break;  /*! \todo XXX should return 0 maybe ? */
-
                if (ast_opt_generic_plc && ast_format_cmp(fr->subclass.format, ast_format_slin) == AST_FORMAT_CMP_EQUAL) {
                        apply_plc(chan, fr);
                }
 
+               f = fr;
+
+               /*
+                * Send frame to audiohooks if present, if frametype is linear (else, later as per
+                * previous behavior)
+                */
+               if ((stream == default_stream) && ast_channel_audiohooks(chan)) {
+                       if (ast_format_cache_is_slinear(fr->subclass.format)) {
+                               hooked = 1;
+                               f = ast_audiohook_write_list(chan, ast_channel_audiohooks(chan), AST_AUDIOHOOK_DIRECTION_WRITE, fr);
+                       }
+               }
+
                /* If the frame is in the raw write format, then it's easy... just use the frame - otherwise we will have to translate */
-               if (ast_format_cmp(fr->subclass.format, ast_channel_rawwriteformat(chan)) != AST_FORMAT_CMP_NOT_EQUAL) {
-                       f = fr;
-               } else {
-                       if ((ast_format_cap_iscompatible_format(ast_channel_nativeformats(chan), fr->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) &&
-                           (ast_format_cmp(ast_channel_writeformat(chan), fr->subclass.format) != AST_FORMAT_CMP_EQUAL)) {
-                               struct ast_str *codec_buf = ast_str_alloca(64);
+               if ((stream == default_stream) && ast_format_cmp(fr->subclass.format, ast_channel_rawwriteformat(chan)) != AST_FORMAT_CMP_EQUAL) {
+                       if (ast_format_cmp(ast_channel_writeformat(chan), fr->subclass.format) != AST_FORMAT_CMP_EQUAL) {
+                               struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
 
                                /*
-                                * XXX Something is not right.  We are not compatible with this
-                                * frame.  Bad things can happen.  Problems range from no audio,
-                                * one-way audio, to unexplained line hangups.  As a last resort
-                                * try to adjust the format.  Ideally, we do not want to do this
-                                * because it indicates a deeper problem.  For now, we log these
-                                * events to reduce user impact and help identify the problem
-                                * areas.
+                                * We are not setup to write this frame.  Things may have changed
+                                * on the peer side of the world and we try to adjust the format to
+                                * make it compatible again.  However, bad things can happen if we
+                                * cannot setup a new translation path.  Problems range from no
+                                * audio, one-way audio, to garbled audio.  The best we can do is
+                                * request the call to hangup since we could not make it compatible.
+                                *
+                                * Being continuously spammed by this message likely indicates a
+                                * problem with the peer because it cannot make up its mind about
+                                * which format to use.
                                 */
-                               ast_log(LOG_WARNING, "Codec mismatch on channel %s setting write format to %s from %s native formats %s\n",
-                                       ast_channel_name(chan), ast_format_get_name(fr->subclass.format), ast_format_get_name(ast_channel_writeformat(chan)),
+                               ast_debug(1, "Channel %s changing write format from %s to %s, native formats %s\n",
+                                       ast_channel_name(chan),
+                                       ast_format_get_name(ast_channel_writeformat(chan)),
+                                       ast_format_get_name(fr->subclass.format),
                                        ast_format_cap_get_names(ast_channel_nativeformats(chan), &codec_buf));
-                               ast_set_write_format(chan, fr->subclass.format);
+                               if (ast_set_write_format(chan, fr->subclass.format)) {
+                                       /* Could not handle the new write format.  Induce a hangup. */
+                                       break;
+                               }
                        }
 
-                       f = (ast_channel_writetrans(chan)) ? ast_translate(ast_channel_writetrans(chan), fr, 0) : fr;
+                       if (ast_channel_writetrans(chan)) {
+                               struct ast_frame *trans_frame = ast_translate(ast_channel_writetrans(chan), f, 0);
+                               if (trans_frame != f && f != fr) {
+                                       /*
+                                        * If translate gives us a new frame and so did the audio
+                                        * hook then we need to free the one from the audio hook.
+                                        */
+                                       ast_frfree(f);
+                               }
+                               f = trans_frame;
+                       }
                }
 
                if (!f) {
@@ -5077,7 +5142,7 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
                        break;
                }
 
-               if (ast_channel_audiohooks(chan)) {
+               if ((stream == default_stream) && ast_channel_audiohooks(chan) && !hooked) {
                        struct ast_frame *prev = NULL, *new_frame, *cur, *dup;
                        int freeoldlist = 0;
 
@@ -5126,7 +5191,7 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
                /* the translator on chan->writetrans may have returned multiple frames
                   from the single frame we passed in; if so, feed each one of them to the
                   monitor */
-               if (ast_channel_monitor(chan) && ast_channel_monitor(chan)->write_stream) {
+               if ((stream == default_stream) && ast_channel_monitor(chan) && ast_channel_monitor(chan)->write_stream) {
                        struct ast_frame *cur;
 
                        for (cur = f; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
@@ -5146,7 +5211,7 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
                                }
 #else
                                int jump = calc_monitor_jump((ast_channel_insmpl(chan) - ast_channel_outsmpl(chan)),
-                                                            ast_format_get_sample_rate(f->subclass.codec),
+                                                            ast_format_get_sample_rate(f->subclass.format),
                                                             ast_format_get_sample_rate(ast_channel_monitor(chan)->read_stream->fmt->format));
                                if (jump - MONITOR_DELAY >= 0) {
                                        if (ast_seekstream(ast_channel_monitor(chan)->write_stream, jump - cur->samples, SEEK_FORCECUR) == -1) {
@@ -5193,7 +5258,17 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
                        /* reset f so the code below doesn't attempt to free it */
                        f = NULL;
                } else {
-                       res = ast_channel_tech(chan)->write(chan, f);
+                       if (ast_channel_tech(chan)->write_stream) {
+                               if (stream) {
+                                       res = ast_channel_tech(chan)->write_stream(chan, ast_stream_get_position(stream), f);
+                               } else {
+                                       res = 0;
+                               }
+                       } else if ((stream == default_stream) && ast_channel_tech(chan)->write) {
+                               res = ast_channel_tech(chan)->write(chan, f);
+                       } else {
+                               res = 0;
+                       }
                }
                break;
        case AST_FRAME_NULL:
@@ -5229,54 +5304,165 @@ done:
        return res;
 }
 
-struct set_format_trans_access {
-       struct ast_trans_pvt *(*get)(const struct ast_channel *chan);
-       void (*set)(struct ast_channel *chan, struct ast_trans_pvt *value);
+int ast_set_read_format_path(struct ast_channel *chan, struct ast_format *raw_format, struct ast_format *core_format)
+{
+       struct ast_trans_pvt *trans_old;
+       struct ast_trans_pvt *trans_new;
+
+       if (ast_format_cmp(ast_channel_rawreadformat(chan), raw_format) == AST_FORMAT_CMP_EQUAL
+               && ast_format_cmp(ast_channel_readformat(chan), core_format) == AST_FORMAT_CMP_EQUAL) {
+               /* Nothing to setup */
+               return 0;
+       }
+
+       ast_debug(1, "Channel %s setting read format path: %s -> %s\n",
+               ast_channel_name(chan),
+               ast_format_get_name(raw_format),
+               ast_format_get_name(core_format));
+
+       /* Setup new translation path. */
+       if (ast_format_cmp(raw_format, core_format) != AST_FORMAT_CMP_EQUAL) {
+               trans_new = ast_translator_build_path(core_format, raw_format);
+               if (!trans_new) {
+                       return -1;
+               }
+       } else {
+               /* No translation needed. */
+               trans_new = NULL;
+       }
+       trans_old = ast_channel_readtrans(chan);
+       if (trans_old) {
+               ast_translator_free_path(trans_old);
+       }
+       ast_channel_readtrans_set(chan, trans_new);
+       ast_channel_set_rawreadformat(chan, raw_format);
+       ast_channel_set_readformat(chan, core_format);
+       return 0;
+}
+
+int ast_set_write_format_path(struct ast_channel *chan, struct ast_format *core_format, struct ast_format *raw_format)
+{
+       struct ast_trans_pvt *trans_old;
+       struct ast_trans_pvt *trans_new;
+
+       if (ast_format_cmp(ast_channel_rawwriteformat(chan), raw_format) == AST_FORMAT_CMP_EQUAL
+               && ast_format_cmp(ast_channel_writeformat(chan), core_format) == AST_FORMAT_CMP_EQUAL) {
+               /* Nothing to setup */
+               return 0;
+       }
+
+       ast_debug(1, "Channel %s setting write format path: %s -> %s\n",
+               ast_channel_name(chan),
+               ast_format_get_name(core_format),
+               ast_format_get_name(raw_format));
+
+       /* Setup new translation path. */
+       if (ast_format_cmp(raw_format, core_format) != AST_FORMAT_CMP_EQUAL) {
+               trans_new = ast_translator_build_path(raw_format, core_format);
+               if (!trans_new) {
+                       return -1;
+               }
+       } else {
+               /* No translation needed. */
+               trans_new = NULL;
+       }
+       trans_old = ast_channel_writetrans(chan);
+       if (trans_old) {
+               ast_translator_free_path(trans_old);
+       }
+       ast_channel_writetrans_set(chan, trans_new);
+       ast_channel_set_rawwriteformat(chan, raw_format);
+       ast_channel_set_writeformat(chan, core_format);
+       return 0;
+}
+
+struct set_format_access {
+       const char *direction;
+       struct ast_trans_pvt *(*get_trans)(const struct ast_channel *chan);
+       void (*set_trans)(struct ast_channel *chan, struct ast_trans_pvt *value);
+       struct ast_format *(*get_format)(struct ast_channel *chan);
+       void (*set_format)(struct ast_channel *chan, struct ast_format *format);
+       struct ast_format *(*get_rawformat)(struct ast_channel *chan);
+       void (*set_rawformat)(struct ast_channel *chan, struct ast_format *format);
+       int setoption;
 };
 
-static const struct set_format_trans_access set_format_readtrans = {
-       .get = ast_channel_readtrans,
-       .set = ast_channel_readtrans_set,
+static const struct set_format_access set_format_access_read = {
+       .direction = "read",
+       .get_trans = ast_channel_readtrans,
+       .set_trans = ast_channel_readtrans_set,
+       .get_format = ast_channel_readformat,
+       .set_format = ast_channel_set_readformat,
+       .get_rawformat = ast_channel_rawreadformat,
+       .set_rawformat = ast_channel_set_rawreadformat,
+       .setoption = AST_OPTION_FORMAT_READ,
 };
 
-static const struct set_format_trans_access set_format_writetrans = {
-       .get = ast_channel_writetrans,
-       .set = ast_channel_writetrans_set,
+static const struct set_format_access set_format_access_write = {
+       .direction = "write",
+       .get_trans = ast_channel_writetrans,
+       .set_trans = ast_channel_writetrans_set,
+       .get_format = ast_channel_writeformat,
+       .set_format = ast_channel_set_writeformat,
+       .get_rawformat = ast_channel_rawwriteformat,
+       .set_rawformat = ast_channel_set_rawwriteformat,
+       .setoption = AST_OPTION_FORMAT_WRITE,
 };
 
-static int set_format(struct ast_channel *chan,
-       struct ast_format_cap *cap_set,
-       struct ast_format *rawformat,
-       struct ast_format *format,
-       const struct set_format_trans_access *trans,
-       const int direction)
+static int set_format(struct ast_channel *chan, struct ast_format_cap *cap_set, const int direction, int interleaved_stereo)
 {
        struct ast_trans_pvt *trans_pvt;
        struct ast_format_cap *cap_native;
-       RAII_VAR(struct ast_format *, best_set_fmt, ast_format_cap_get_format(cap_set, 0), ao2_cleanup);
+       const struct set_format_access *access;
+       struct ast_format *rawformat;
+       struct ast_format *format;
+       RAII_VAR(struct ast_format *, best_set_fmt, NULL, ao2_cleanup);
        RAII_VAR(struct ast_format *, best_native_fmt, NULL, ao2_cleanup);
        int res;
 
-       ast_assert(format != NULL);
-       ast_assert(rawformat != NULL);
+       if (!direction) {
+               /* reading */
+               access = &set_format_access_read;
+       } else {
+               /* writing */
+               access = &set_format_access_write;
+       }
+
+       best_set_fmt = ast_format_cap_get_best_by_type(cap_set, AST_MEDIA_TYPE_AUDIO);
+       if (!best_set_fmt) {
+               /*
+                * Not setting any audio formats?
+                * Assume a call without any sounds (video, text)
+                */
+               return 0;
+       }
 
        /* See if the underlying channel driver is capable of performing transcoding for us */
-       if (!ast_channel_setoption(chan, direction ? AST_OPTION_FORMAT_WRITE : AST_OPTION_FORMAT_READ, &best_set_fmt, sizeof(best_set_fmt), 0)) {
-               ast_debug(1, "Channel driver natively set channel %s to %s format %s\n", ast_channel_name(chan),
-                         direction ? "write" : "read", ast_format_get_name(best_set_fmt));
+       res = ast_channel_setoption(chan, access->setoption,
+               &best_set_fmt, sizeof(best_set_fmt), 0);
+       if (!res) {
+               ast_debug(1, "Channel driver natively set channel %s to %s format %s\n",
+                       ast_channel_name(chan), access->direction, ast_format_get_name(best_set_fmt));
 
                ast_channel_lock(chan);
                cap_native = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
-               ast_format_cap_append(cap_native, best_set_fmt, 0);
+               if (!cap_native
+                       || ast_format_cap_append(cap_native, best_set_fmt, 0)) {
+                       ast_channel_unlock(chan);
+                       ao2_cleanup(cap_native);
+                       return -1;
+               }
                ast_channel_nativeformats_set(chan, cap_native);
                ao2_cleanup(cap_native);
-               ast_channel_unlock(chan);
+               access->set_format(chan, best_set_fmt);
+               access->set_rawformat(chan, best_set_fmt);
 
-               trans_pvt = trans->get(chan);
+               trans_pvt = access->get_trans(chan);
                if (trans_pvt) {
                        ast_translator_free_path(trans_pvt);
-                       trans->set(chan, NULL);
+                       access->set_trans(chan, NULL);
                }
+               ast_channel_unlock(chan);
 
                /* If there is a generator on the channel, it needs to know about this
                 * change if it is the write format. */
@@ -5288,7 +5474,19 @@ static int set_format(struct ast_channel *chan,
        }
 
        ast_channel_lock(chan);
+
+       format = access->get_format(chan);
+       rawformat = access->get_rawformat(chan);
+       ast_assert(format != NULL);
+       ast_assert(rawformat != NULL);
+
        cap_native = ast_channel_nativeformats(chan);
+       if (ast_format_cap_empty(cap_native)) {
+               ast_channel_unlock(chan);
+               ast_log(LOG_ERROR, "Unable to set format because channel %s supports no formats\n",
+                               ast_channel_name(chan));
+               return -1;
+       }
 
        /* Find a translation path from the native format to one of the desired formats */
        if (!direction) {
@@ -5299,32 +5497,37 @@ static int set_format(struct ast_channel *chan,
                res = ast_translator_best_choice(cap_native, cap_set, &best_native_fmt, &best_set_fmt);
        }
        if (res < 0) {
-               struct ast_str *codec_from = ast_str_alloca(64);
-               struct ast_str *codec_to = ast_str_alloca(64);
+               struct ast_str *codec_native = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
+               struct ast_str *codec_set = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
 
-               ast_format_cap_get_names(cap_native, &codec_from);
+               ast_format_cap_get_names(cap_native, &codec_native);
                ast_channel_unlock(chan);
-               ast_format_cap_get_names(cap_set, &codec_to);
+               ast_format_cap_get_names(cap_set, &codec_set);
 
-               ast_log(LOG_WARNING, "Unable to find a codec translation path from %s to %s\n",
-                       ast_str_buffer(codec_from), ast_str_buffer(codec_to));
+               ast_log(LOG_WARNING, "Unable to find a codec translation path: %s -> %s\n",
+                       ast_str_buffer(direction ? codec_set : codec_native),
+                       ast_str_buffer(direction ? codec_native : codec_set));
                return -1;
        }
 
        /* Now we have a good choice for both. */
+       trans_pvt = access->get_trans(chan);
        if ((ast_format_cmp(rawformat, best_native_fmt) != AST_FORMAT_CMP_NOT_EQUAL) &&
                (ast_format_cmp(format, best_set_fmt) != AST_FORMAT_CMP_NOT_EQUAL) &&
-               ((ast_format_cmp(rawformat, format) != AST_FORMAT_CMP_NOT_EQUAL) || trans->get(chan))) {
-               /* the channel is already in these formats, so nothing to do */
-               ast_channel_unlock(chan);
-               return 0;
+               ((ast_format_cmp(rawformat, format) != AST_FORMAT_CMP_NOT_EQUAL) || access->get_trans(chan))) {
+               /* the channel is already in these formats, so nothing to do, unless the interleaved format is not set correctly */
+               if (trans_pvt != NULL) {
+                       if (trans_pvt->interleaved_stereo == interleaved_stereo) {
+                               ast_channel_unlock(chan);
+                               return 0;
+                       }
+               }
        }
 
        /* Free any translation we have right now */
-       trans_pvt = trans->get(chan);
        if (trans_pvt) {
                ast_translator_free_path(trans_pvt);
-               trans->set(chan, NULL);
+               access->set_trans(chan, NULL);
        }
 
        /* Build a translation path from the raw format to the desired format */
@@ -5339,29 +5542,25 @@ static int set_format(struct ast_channel *chan,
                if (!direction) {
                        /* reading */
                        trans_pvt = ast_translator_build_path(best_set_fmt, best_native_fmt);
+                       trans_pvt->interleaved_stereo = 0;
                } else {
                        /* writing */
                        trans_pvt = ast_translator_build_path(best_native_fmt, best_set_fmt);
+                       trans_pvt->interleaved_stereo = interleaved_stereo;
                }
-               trans->set(chan, trans_pvt);
+               access->set_trans(chan, trans_pvt);
                res = trans_pvt ? 0 : -1;
        }
 
        if (!res) {
-               if (!direction) {
-                       /* reading */
-                       ast_channel_set_readformat(chan, best_set_fmt);
-                       ast_channel_set_rawreadformat(chan, best_native_fmt);
-               } else {
-                       /* writing */
-                       ast_channel_set_writeformat(chan, best_set_fmt);
-                       ast_channel_set_rawwriteformat(chan, best_native_fmt);
-               }
+               access->set_format(chan, best_set_fmt);
+               access->set_rawformat(chan, best_native_fmt);
 
-               ast_debug(1, "Set channel %s to %s format %s\n",
+               ast_debug(1, "Channel %s setting %s format path: %s -> %s\n",
                        ast_channel_name(chan),
-                       direction ? "write" : "read",
-                       ast_format_get_name(best_set_fmt));
+                       access->direction,
+                       ast_format_get_name(direction ? best_set_fmt : best_native_fmt),
+                       ast_format_get_name(direction ? best_native_fmt : best_set_fmt));
        }
 
        ast_channel_unlock(chan);
@@ -5387,12 +5586,7 @@ int ast_set_read_format(struct ast_channel *chan, struct ast_format *format)
        }
        ast_format_cap_append(cap, format, 0);
 
-       res = set_format(chan,
-               cap,
-               ast_channel_rawreadformat(chan),
-               ast_channel_readformat(chan),
-               &set_format_readtrans,
-               0);
+       res = set_format(chan, cap, 0, 0);
 
        ao2_cleanup(cap);
        return res;
@@ -5400,12 +5594,25 @@ int ast_set_read_format(struct ast_channel *chan, struct ast_format *format)
 
 int ast_set_read_format_from_cap(struct ast_channel *chan, struct ast_format_cap *cap)
 {
-       return set_format(chan,
-               cap,
-               ast_channel_rawreadformat(chan),
-               ast_channel_readformat(chan),
-               &set_format_readtrans,
-               0);
+       return set_format(chan, cap, 0, 0);
+}
+
+int ast_set_write_format_interleaved_stereo(struct ast_channel *chan, struct ast_format *format)
+{
+       struct ast_format_cap *cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
+       int res;
+
+       ast_assert(format != NULL);
+
+       if (!cap) {
+               return -1;
+       }
+       ast_format_cap_append(cap, format, 0);
+
+       res = set_format(chan, cap, 1, 1);
+
+       ao2_cleanup(cap);
+       return res;
 }
 
 int ast_set_write_format(struct ast_channel *chan, struct ast_format *format)
@@ -5420,12 +5627,7 @@ int ast_set_write_format(struct ast_channel *chan, struct ast_format *format)
        }
        ast_format_cap_append(cap, format, 0);
 
-       res = set_format(chan,
-               cap,
-               ast_channel_rawwriteformat(chan),
-               ast_channel_writeformat(chan),
-               &set_format_writetrans,
-               1);
+       res = set_format(chan, cap, 1, 0);
 
        ao2_cleanup(cap);
        return res;
@@ -5433,12 +5635,7 @@ int ast_set_write_format(struct ast_channel *chan, struct ast_format *format)
 
 int ast_set_write_format_from_cap(struct ast_channel *chan, struct ast_format_cap *cap)
 {
-       return set_format(chan,
-               cap,
-               ast_channel_rawwriteformat(chan),
-               ast_channel_writeformat(chan),
-               &set_format_writetrans,
-               1);
+       return set_format(chan, cap, 1, 0);
 }
 
 const char *ast_channel_reason2str(int reason)
@@ -5511,6 +5708,7 @@ static void call_forward_inherit(struct ast_channel *new_chan, struct ast_channe
        ast_channel_lock_both(parent, new_chan);
        ast_channel_inherit_variables(parent, new_chan);
        ast_channel_datastore_inherit(parent, new_chan);
+       ast_max_forwards_decrement(new_chan);
        ast_channel_unlock(new_chan);
        ast_channel_unlock(parent);
 }
@@ -5518,6 +5716,7 @@ static void call_forward_inherit(struct ast_channel *new_chan, struct ast_channe
 struct ast_channel *ast_call_forward(struct ast_channel *caller, struct ast_channel *orig, int *timeout, struct ast_format_cap *cap, struct outgoing_helper *oh, int *outstate)
 {
        char tmpchan[256];
+       char forwarder[AST_CHANNEL_NAME];
        struct ast_channel *new_chan = NULL;
        char *data, *type;
        int cause = 0;
@@ -5525,6 +5724,7 @@ struct ast_channel *ast_call_forward(struct ast_channel *caller, struct ast_chan
 
        /* gather data and request the new forward channel */
        ast_copy_string(tmpchan, ast_channel_call_forward(orig), sizeof(tmpchan));
+       ast_copy_string(forwarder, ast_channel_name(orig), sizeof(forwarder));
        if ((data = strchr(tmpchan, '/'))) {
                *data++ = '\0';
                type = tmpchan;
@@ -5565,9 +5765,10 @@ struct ast_channel *ast_call_forward(struct ast_channel *caller, struct ast_chan
        } else if (caller) { /* no outgoing helper so use caller if available */
                call_forward_inherit(new_chan, caller, orig);
        }
-       ast_set_flag(ast_channel_flags(new_chan), AST_FLAG_ORIGINATED);
 
        ast_channel_lock_both(orig, new_chan);
+       ast_channel_set_flag(new_chan, AST_FLAG_ORIGINATED);
+       pbx_builtin_setvar_helper(new_chan, "FORWARDERNAME", forwarder);
        ast_party_connected_line_copy(ast_channel_connected(new_chan), ast_channel_connected(orig));
        ast_party_redirecting_copy(ast_channel_redirecting(new_chan), ast_channel_redirecting(orig));
        ast_channel_req_accountcodes(new_chan, orig, AST_CHANNEL_REQUESTOR_REPLACEMENT);
@@ -5630,6 +5831,7 @@ struct ast_channel *__ast_request_and_dial(const char *type, struct ast_format_c
                        ast_channel_lock_both(oh->parent_channel, chan);
                        ast_channel_inherit_variables(oh->parent_channel, chan);
                        ast_channel_datastore_inherit(oh->parent_channel, chan);
+                       ast_max_forwards_decrement(chan);
                        ast_channel_unlock(oh->parent_channel);
                        ast_channel_unlock(chan);
                }
@@ -5830,10 +6032,11 @@ static int set_security_requirements(const struct ast_channel *requestor, struct
        return 0;
 }
 
-struct ast_channel *ast_request(const char *type, struct ast_format_cap *request_cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *addr, int *cause)
+static struct ast_channel *request_channel(const char *type, struct ast_format_cap *request_cap, struct ast_stream_topology *topology,
+       const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *addr, int *cause)
 {
        struct chanlist *chan;
-       struct ast_channel *c;
+       struct ast_channel *c = NULL;
        int res;
        int foo;
 
@@ -5847,13 +6050,44 @@ struct ast_channel *ast_request(const char *type, struct ast_format_cap *request
        }
 
        AST_RWLIST_TRAVERSE(&backends, chan, list) {
+               if (strcasecmp(type, chan->tech->type)) {
+                       continue;
+               }
+
+               break;
+       }
+
+       AST_RWLIST_UNLOCK(&backends);
+
+       if (!chan) {
+               ast_log(LOG_WARNING, "No channel type registered for '%s'\n", type);
+               *cause = AST_CAUSE_NOSUCHDRIVER;
+               return NULL;
+       }
+
+       /* Allow either format capabilities or stream topology to be provided and adapt */
+       if (chan->tech->requester_with_stream_topology) {
+               struct ast_stream_topology *tmp_converted_topology = NULL;
+
+               if (!topology && request_cap) {
+                       /* Turn the requested capabilities into a stream topology */
+                       topology = tmp_converted_topology = ast_stream_topology_create_from_format_cap(request_cap);
+               }
+
+               c = chan->tech->requester_with_stream_topology(type, topology, assignedids, requestor, addr, cause);
+
+               ast_stream_topology_free(tmp_converted_topology);
+       } else if (chan->tech->requester) {
+               struct ast_format_cap *tmp_converted_cap = NULL;
                struct ast_format_cap *tmp_cap;
                RAII_VAR(struct ast_format *, tmp_fmt, NULL, ao2_cleanup);
                RAII_VAR(struct ast_format *, best_audio_fmt, NULL, ao2_cleanup);
                struct ast_format_cap *joint_cap;
 
-               if (strcasecmp(type, chan->tech->type))
-                       continue;
+               if (!request_cap && topology) {
+                       /* Turn the request stream topology into capabilities */
+                       request_cap = tmp_converted_cap = ast_format_cap_from_stream_topology(topology);
+               }
 
                /* find the best audio format to use */
                tmp_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
@@ -5865,72 +6099,75 @@ struct ast_channel *ast_request(const char *type, struct ast_format_cap *request
                        res = ast_translator_best_choice(tmp_cap, chan->tech->capabilities, &tmp_fmt, &best_audio_fmt);
                        ao2_ref(tmp_cap, -1);
                        if (res < 0) {
-                               struct ast_str *tech_codecs = ast_str_alloca(64);
-                               struct ast_str *request_codecs = ast_str_alloca(64);
+                               struct ast_str *tech_codecs = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
+                               struct ast_str *request_codecs = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
 
                                ast_log(LOG_WARNING, "No translator path exists for channel type %s (native %s) to %s\n", type,
                                        ast_format_cap_get_names(chan->tech->capabilities, &tech_codecs),
                                        ast_format_cap_get_names(request_cap, &request_codecs));
                                *cause = AST_CAUSE_BEARERCAPABILITY_NOTAVAIL;
-                               AST_RWLIST_UNLOCK(&backends);
+                               ao2_cleanup(tmp_converted_cap);
                                return NULL;
                        }
                }
-               AST_RWLIST_UNLOCK(&backends);
-               if (!chan->tech->requester)
-                       return NULL;
 
                /* XXX Only the audio format calculated as being the best for translation
-                * purposes is used for the request. This needs to be re-evaluated.  It may be
-                * a better choice to send all the audio formats capable of being translated
-                * during the request and allow the channel drivers to pick the best one. */
+                * purposes is used for the request. This is because we don't have the ability
+                * to signal to the initiator which one of their codecs that was offered is
+                * the one that was selected, particularly in a chain of Local channels.
+                */
                joint_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
                if (!joint_cap) {
+                       ao2_cleanup(tmp_converted_cap);
                        return NULL;
                }
                ast_format_cap_append_from_cap(joint_cap, request_cap, AST_MEDIA_TYPE_UNKNOWN);
                ast_format_cap_remove_by_type(joint_cap, AST_MEDIA_TYPE_AUDIO);
                ast_format_cap_append(joint_cap, best_audio_fmt, 0);
+               ao2_cleanup(tmp_converted_cap);
 
-               if (!(c = chan->tech->requester(type, joint_cap, assignedids, requestor, addr, cause))) {
-                       ao2_ref(joint_cap, -1);
-                       return NULL;
-               }
+               c = chan->tech->requester(type, joint_cap, assignedids, requestor, addr, cause);
+               ao2_ref(joint_cap, -1);
+       }
 
-               if (requestor) {
-                       struct ast_callid *callid;
+       if (!c) {
+               return NULL;
+       }
 
-                       ast_channel_lock_both(c, (struct ast_channel *) requestor);
+       if (requestor) {
+               ast_callid callid;
 
-                       /* Set the newly created channel's callid to the same as the requestor. */
-                       callid = ast_channel_callid(requestor);
-                       if (callid) {
-                               ast_channel_callid_set(c, callid);
-                               callid = ast_callid_unref(callid);
-                       }
+               ast_channel_lock_both(c, (struct ast_channel *) requestor);
 
-                       ast_channel_unlock(c);
-                       ast_channel_unlock((struct ast_channel *) requestor);
+               /* Set the newly created channel's callid to the same as the requestor. */
+               callid = ast_channel_callid(requestor);
+               if (callid) {
+                       ast_channel_callid_set(c, callid);
                }
 
-               ao2_ref(joint_cap, -1);
-
-               if (set_security_requirements(requestor, c)) {
-                       ast_log(LOG_WARNING, "Setting security requirements failed\n");
-                       c = ast_channel_release(c);
-                       *cause = AST_CAUSE_BEARERCAPABILITY_NOTAVAIL;
-                       return NULL;
-               }
+               ast_channel_unlock(c);
+               ast_channel_unlock((struct ast_channel *) requestor);
+       }
 
-               /* no need to generate a Newchannel event here; it is done in the channel_alloc call */
-               return c;
+       if (set_security_requirements(requestor, c)) {
+               ast_log(LOG_WARNING, "Setting security requirements failed\n");
+               ast_hangup(c);
+               *cause = AST_CAUSE_BEARERCAPABILITY_NOTAVAIL;
+               return NULL;
        }
 
-       ast_log(LOG_WARNING, "No channel type registered for '%s'\n", type);
-       *cause = AST_CAUSE_NOSUCHDRIVER;
-       AST_RWLIST_UNLOCK(&backends);
+       /* no need to generate a Newchannel event here; it is done in the channel_alloc call */
+       return c;
+}
 
-       return NULL;
+struct ast_channel *ast_request(const char *type, struct ast_format_cap *request_cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *addr, int *cause)
+{
+       return request_channel(type, request_cap, NULL, assignedids, requestor, addr, cause);
+}
+
+struct ast_channel *ast_request_with_stream_topology(const char *type, struct ast_stream_topology *topology, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *addr, int *cause)
+{
+       return request_channel(type, NULL, topology, assignedids, requestor, addr, cause);
 }
 
 /*!
@@ -6131,11 +6368,11 @@ int ast_readstring_full(struct ast_channel *c, char *s, int len, int timeout, in
                                silgen = ast_channel_start_silence_generator(c);
                        usleep(1000);
                        if (!d)
-                               d = ast_waitfordigit_full(c, to, audiofd, ctrlfd);
+                               d = ast_waitfordigit_full(c, to, NULL, audiofd, ctrlfd);
                } else {
                        if (!silgen && ast_opt_transmit_silence)
                                silgen = ast_channel_start_silence_generator(c);
-                       d = ast_waitfordigit_full(c, to, audiofd, ctrlfd);
+                       d = ast_waitfordigit_full(c, to, NULL, audiofd, ctrlfd);
                }
                if (d < 0) {
                        ast_channel_stop_silence_generator(c, silgen);
@@ -6196,15 +6433,17 @@ static int ast_channel_make_compatible_helper(struct ast_channel *from, struct a
        RAII_VAR(struct ast_format *, best_dst_fmt, NULL, ao2_cleanup);
        int no_path;
 
-       ast_channel_lock_both(from, to);
+       /*
+        * We cannot short circuit this code because it is possible to ask
+        * to make compatible two channels that are "compatible" because
+        * they already have translation paths setup but together make for
+        * a sub-optimal path.  e.g., The From channel has g722 -> ulaw
+        * and the To channel has ulaw -> g722.  They are "compatible" but
+        * together the translations are unnecessary and the audio loses
+        * fidelity in the process.
+        */
 
-       if ((ast_format_cmp(ast_channel_readformat(from), ast_channel_writeformat(to)) != AST_FORMAT_CMP_NOT_EQUAL) &&
-               (ast_format_cmp(ast_channel_readformat(to), ast_channel_writeformat(from)) != AST_FORMAT_CMP_NOT_EQUAL)) {
-               /* Already compatible!  Moving on ... */
-               ast_channel_unlock(to);
-               ast_channel_unlock(from);
-               return 0;
-       }
+       ast_channel_lock_both(from, to);
 
        src_cap = ast_channel_nativeformats(from); /* shallow copy, do not destroy */
        dst_cap = ast_channel_nativeformats(to);   /* shallow copy, do not destroy */
@@ -6244,8 +6483,7 @@ static int ast_channel_make_compatible_helper(struct ast_channel *from, struct a
                                ast_format_get_sample_rate(best_src_fmt) : ast_format_get_sample_rate(best_dst_fmt);
 
                        /* pick the best signed linear format based upon what preserves the sample rate the best. */
-                       ao2_ref(best_src_fmt, -1);
-                       best_src_fmt = ao2_bump(ast_format_cache_get_slin_by_rate(best_sample_rate));
+                       ao2_replace(best_src_fmt, ast_format_cache_get_slin_by_rate(best_sample_rate));
                }
        }
 
@@ -6313,41 +6551,42 @@ void ast_change_name(struct ast_channel *chan, const char *newname)
 
 void ast_channel_inherit_variables(const struct ast_channel *parent, struct ast_channel *child)
 {
-       struct ast_var_t *current, *newvar;
+       struct ast_var_t *current;
+       struct ast_var_t *newvar;
        const char *varname;
+       int vartype;
 
        AST_LIST_TRAVERSE(ast_channel_varshead((struct ast_channel *) parent), current, entries) {
-               int vartype = 0;
-
                varname = ast_var_full_name(current);
-               if (!varname)
+               if (!varname) {
                        continue;
+               }
 
+               vartype = 0;
                if (varname[0] == '_') {
                        vartype = 1;
-                       if (varname[1] == '_')
+                       if (varname[1] == '_') {
                                vartype = 2;
+                       }
                }
 
                switch (vartype) {
                case 1:
                        newvar = ast_var_assign(&varname[1], ast_var_value(current));
-                       if (newvar) {
-                               AST_LIST_INSERT_TAIL(ast_channel_varshead(child), newvar, entries);
-                               ast_debug(1, "Inheriting variable %s from %s to %s.\n",
-                                       ast_var_name(newvar), ast_channel_name(parent), ast_channel_name(child));
-                       }
                        break;
                case 2:
                        newvar = ast_var_assign(varname, ast_var_value(current));
-                       if (newvar) {
-                               AST_LIST_INSERT_TAIL(ast_channel_varshead(child), newvar, entries);
-                               ast_debug(1, "Inheriting variable %s from %s to %s.\n",
-                                       ast_var_name(newvar), ast_channel_name(parent), ast_channel_name(child));
-                       }
                        break;
                default:
-                       break;
+                       continue;
+               }
+               if (newvar) {
+                       ast_debug(1, "Inheriting variable %s from %s to %s.\n",
+                               ast_var_full_name(newvar), ast_channel_name(parent),
+                               ast_channel_name(child));
+                       AST_LIST_INSERT_TAIL(ast_channel_varshead(child), newvar, entries);
+                       ast_channel_publish_varset(child, ast_var_full_name(newvar),
+                               ast_var_value(newvar));
                }
        }
 }
@@ -6402,6 +6641,7 @@ static void channel_do_masquerade(struct ast_channel *original, struct ast_chann
        int origstate;
        unsigned int orig_disablestatecache;
        unsigned int clone_disablestatecache;
+       int generator_fd;
        int visible_indication;
        int clone_hold_state;
        int moh_is_playing;
@@ -6429,6 +6669,11 @@ static void channel_do_masquerade(struct ast_channel *original, struct ast_chann
         * original channel's backend.  While the features are nice, which is the
         * reason we're keeping it, it's still awesomely weird. XXX */
 
+       /* Indicate to each channel that a masquerade is about to begin. */
+       x = 1;
+       ast_indicate_data(original, AST_CONTROL_MASQUERADE_NOTIFY, &x, sizeof(x));
+       ast_indicate_data(clonechan, AST_CONTROL_MASQUERADE_NOTIFY, &x, sizeof(x));
+
        /*
         * The container lock is necessary for proper locking order
         * because the channels must be unlinked to change their
@@ -6469,8 +6714,9 @@ static void channel_do_masquerade(struct ast_channel *original, struct ast_chann
        /* Start the masquerade channel contents rearangement. */
        ast_channel_lock_both(original, clonechan);
 
-       ast_debug(4, "Actually Masquerading %s(%u) into the structure of %s(%u)\n",
-               ast_channel_name(clonechan), ast_channel_state(clonechan), ast_channel_name(original), ast_channel_state(original));
+       ast_debug(1, "Actually Masquerading %s(%u) into the structure of %s(%u)\n",
+               ast_channel_name(clonechan), ast_channel_state(clonechan),
+               ast_channel_name(original), ast_channel_state(original));
 
        /*
         * Remember the original read/write formats.  We turn off any
@@ -6492,6 +6738,9 @@ static void channel_do_masquerade(struct ast_channel *original, struct ast_chann
         */
        ast_channel_internal_swap_uniqueid_and_linkedid(clonechan, original);
 
+       /* Make sure the Stasis topic on the channel is updated appropriately */
+       ast_channel_internal_swap_topics(clonechan, original);
+
        /* Swap channel names. This uses ast_channel_name_set directly, so we
         * don't get any spurious rename events.
         */
@@ -6583,8 +6832,13 @@ static void channel_do_masquerade(struct ast_channel *original, struct ast_chann
        /* Keep the same parkinglot. */
        ast_channel_parkinglot_set(original, ast_channel_parkinglot(clonechan));
 
-       /* Copy the FD's other than the generator fd */
-       for (x = 0; x < AST_MAX_FDS; x++) {
+       /* Clear all existing file descriptors but retain the generator */
+       generator_fd = ast_channel_fd(original, AST_GENERATOR_FD);
+       ast_channel_internal_fd_clear_all(original);
+       ast_channel_set_fd(original, AST_GENERATOR_FD, generator_fd);
+
+       /* Copy all file descriptors present on clonechan to original, skipping generator */
+       for (x = 0; x < ast_channel_fd_count(clonechan); x++) {
                if (x != AST_GENERATOR_FD)
                        ast_channel_set_fd(original, x, ast_channel_fd(clonechan, x));
        }
@@ -6730,6 +6984,8 @@ static void channel_do_masquerade(struct ast_channel *original, struct ast_chann
                        ast_channel_tech(clonechan)->type, ast_channel_name(clonechan));
        }
 
+       ast_channel_internal_swap_stream_topology(original, clonechan);
+
        /*
         * Now, at this point, the "clone" channel is totally F'd up.
         * We mark it as a zombie so nothing tries to touch it.
@@ -6743,6 +6999,19 @@ static void channel_do_masquerade(struct ast_channel *original, struct ast_chann
        ast_channel_unlock(original);
        ast_channel_unlock(clonechan);
 
+       /*
+        * Indicate to each channel that a masquerade is complete.
+        *
+        * We can still do this to clonechan even though it is a
+        * zombie because ast_indicate_data() will explicitly pass
+        * this control and ast_hangup() is held off until the
+        * ast_channel_masq() and ast_channel_masqr() pointers are
+        * cleared.
+        */
+       x = 0;
+       ast_indicate_data(original, AST_CONTROL_MASQUERADE_NOTIFY, &x, sizeof(x));
+       ast_indicate_data(clonechan, AST_CONTROL_MASQUERADE_NOTIFY, &x, sizeof(x));
+
        ast_bridge_notify_masquerade(original);
 
        if (clone_hold_state == AST_CONTROL_HOLD) {
@@ -7271,7 +7540,7 @@ int ast_moh_start(struct ast_channel *chan, const char *mclass, const char *inte
 
        ast_verb(3, "Music class %s requested but no musiconhold loaded.\n", mclass ? mclass : (interpclass ? interpclass : "default"));
 
-       return 0;
+       return -1;
 }
 
 void ast_moh_stop(struct ast_channel *chan)
@@ -7317,121 +7586,6 @@ int ast_plc_reload(void)
 
 /*!
  * \internal
- * \brief Implements the channels provider.
- */
-static int data_channels_provider_handler(const struct ast_data_search *search,
-       struct ast_data *root)
-{
-       struct ast_channel *c;
-       struct ast_channel_iterator *iter = NULL;
-       struct ast_data *data_channel;
-
-       for (iter = ast_channel_iterator_all_new();
-               iter && (c = ast_channel_iterator_next(iter)); ast_channel_unref(c)) {
-               ast_channel_lock(c);
-
-               data_channel = ast_data_add_node(root, "channel");
-               if (!data_channel) {
-                       ast_channel_unlock(c);
-                       continue;
-               }
-
-               if (ast_channel_data_add_structure(data_channel, c, 1) < 0) {
-                       ast_log(LOG_ERROR, "Unable to add channel structure for channel: %s\n", ast_channel_name(c));
-               }
-
-               ast_channel_unlock(c);
-
-               if (!ast_data_search_match(search, data_channel)) {
-                       ast_data_remove_node(root, data_channel);
-               }
-       }
-       if (iter) {
-               ast_channel_iterator_destroy(iter);
-       }
-
-       return 0;
-}
-
-/*!
- * \internal
- * \brief Implements the channeltypes provider.
- */
-static int data_channeltypes_provider_handler(const struct ast_data_search *search,
-       struct ast_data *data_root)
-{
-       struct chanlist *cl;
-       struct ast_data *data_type;
-
-       AST_RWLIST_RDLOCK(&backends);
-       AST_RWLIST_TRAVERSE(&backends, cl, list) {
-               data_type = ast_data_add_node(data_root, "type");
-               if (!data_type) {
-                       continue;
-               }
-               ast_data_add_str(data_type, "name", cl->tech->type);
-               ast_data_add_str(data_type, "description", cl->tech->description);
-               ast_data_add_bool(data_type, "devicestate", cl->tech->devicestate ? 1 : 0);
-               ast_data_add_bool(data_type, "indications", cl->tech->indicate ? 1 : 0);
-               ast_data_add_bool(data_type, "transfer", cl->tech->transfer ? 1 : 0);
-               ast_data_add_bool(data_type, "send_digit_begin", cl->tech->send_digit_begin ? 1 : 0);
-               ast_data_add_bool(data_type, "send_digit_end", cl->tech->send_digit_end ? 1 : 0);
-               ast_data_add_bool(data_type, "call", cl->tech->call ? 1 : 0);
-               ast_data_add_bool(data_type, "hangup", cl->tech->hangup ? 1 : 0);
-               ast_data_add_bool(data_type, "answer", cl->tech->answer ? 1 : 0);
-               ast_data_add_bool(data_type, "read", cl->tech->read ? 1 : 0);
-               ast_data_add_bool(data_type, "write", cl->tech->write ? 1 : 0);
-               ast_data_add_bool(data_type, "send_text", cl->tech->send_text ? 1 : 0);
-               ast_data_add_bool(data_type, "send_image", cl->tech->send_image ? 1 : 0);
-               ast_data_add_bool(data_type, "send_html", cl->tech->send_html ? 1 : 0);
-               ast_data_add_bool(data_type, "exception", cl->tech->exception ? 1 : 0);
-               ast_data_add_bool(data_type, "early_bridge", cl->tech->early_bridge ? 1 : 0);
-               ast_data_add_bool(data_type, "fixup", cl->tech->fixup ? 1 : 0);
-               ast_data_add_bool(data_type, "setoption", cl->tech->setoption ? 1 : 0);
-               ast_data_add_bool(data_type, "queryoption", cl->tech->queryoption ? 1 : 0);
-               ast_data_add_bool(data_type, "write_video", cl->tech->write_video ? 1 : 0);
-               ast_data_add_bool(data_type, "write_text", cl->tech->write_text ? 1 : 0);
-               ast_data_add_bool(data_type, "func_channel_read", cl->tech->func_channel_read ? 1 : 0);
-               ast_data_add_bool(data_type, "func_channel_write", cl->tech->func_channel_write ? 1 : 0);
-               ast_data_add_bool(data_type, "get_pvt_uniqueid", cl->tech->get_pvt_uniqueid ? 1 : 0);
-               ast_data_add_bool(data_type, "cc_callback", cl->tech->cc_callback ? 1 : 0);
-
-               ast_data_add_codecs(data_type, "capabilities", cl->tech->capabilities);
-
-               if (!ast_data_search_match(search, data_type)) {
-                       ast_data_remove_node(data_root, data_type);
-               }
-       }
-       AST_RWLIST_UNLOCK(&backends);
-
-       return 0;
-}
-
-/*!
- * \internal
- * \brief /asterisk/core/channels provider.
- */
-static const struct ast_data_handler channels_provider = {
-       .version = AST_DATA_HANDLER_VERSION,
-       .get = data_channels_provider_handler
-};
-
-/*!
- * \internal
- * \brief /asterisk/core/channeltypes provider.
- */
-static const struct ast_data_handler channeltypes_provider = {
-       .version = AST_DATA_HANDLER_VERSION,
-       .get = data_channeltypes_provider_handler
-};
-
-static const struct ast_data_entry channel_providers[] = {
-       AST_DATA_ENTRY("/asterisk/core/channels", &channels_provider),
-       AST_DATA_ENTRY("/asterisk/core/channeltypes", &channeltypes_provider),
-};
-
-/*!
- * \internal
  * \brief Print channel object key (name).
  * \since 12.0.0
  *
@@ -7460,35 +7614,48 @@ struct manager_channel_variable {
        char name[];
 };
 
-static AST_RWLIST_HEAD_STATIC(channelvars, manager_channel_variable);
+AST_RWLIST_HEAD(external_vars, manager_channel_variable);
 
-static void free_channelvars(void)
+static struct external_vars ami_vars;
+static struct external_vars ari_vars;
+
+static void free_external_channelvars(struct external_vars *channelvars)
 {
        struct manager_channel_variable *var;
-       AST_RWLIST_WRLOCK(&channelvars);
-       while ((var = AST_RWLIST_REMOVE_HEAD(&channelvars, entry))) {
+       AST_RWLIST_WRLOCK(channelvars);
+       while ((var = AST_RWLIST_REMOVE_HEAD(channelvars, entry))) {
                ast_free(var);
        }
-       AST_RWLIST_UNLOCK(&channelvars);
+       AST_RWLIST_UNLOCK(channelvars);
 }
 
-int ast_channel_has_manager_vars(void)
+static int channel_has_external_vars(struct external_vars *channelvars)
 {
        int vars_present;
 
-       AST_RWLIST_RDLOCK(&channelvars);
-       vars_present = !AST_LIST_EMPTY(&channelvars);
-       AST_RWLIST_UNLOCK(&channelvars);
+       AST_RWLIST_RDLOCK(channelvars);
+       vars_present = !AST_LIST_EMPTY(channelvars);
+       AST_RWLIST_UNLOCK(channelvars);
 
        return vars_present;
 }
 
-void ast_channel_set_manager_vars(size_t varc, char **vars)
+int ast_channel_has_manager_vars(void)
+{
+       return channel_has_external_vars(&ami_vars);
+}
+
+int ast_channel_has_ari_vars(void)
+{
+       return channel_has_external_vars(&ari_vars);
+}
+
+static void channel_set_external_vars(struct external_vars *channelvars, size_t varc, char **vars)
 {
        size_t i;
 
-       free_channelvars();
-       AST_RWLIST_WRLOCK(&channelvars);
+       free_external_channelvars(channelvars);
+       AST_RWLIST_WRLOCK(channelvars);
        for (i = 0; i < varc; ++i) {
                const char *var = vars[i];
                struct manager_channel_variable *mcv;
@@ -7499,9 +7666,20 @@ void ast_channel_set_manager_vars(size_t varc, char **vars)
                if (strchr(var, '(')) {
                        mcv->isfunc = 1;
                }
-               AST_RWLIST_INSERT_TAIL(&channelvars, mcv, entry);
+               AST_RWLIST_INSERT_TAIL(channelvars, mcv, entry);
        }
-       AST_RWLIST_UNLOCK(&channelvars);
+       AST_RWLIST_UNLOCK(channelvars);
+
+}
+
+void ast_channel_set_manager_vars(size_t varc, char **vars)
+{
+       channel_set_external_vars(&ami_vars, varc, vars);
+}
+
+void ast_channel_set_ari_vars(size_t varc, char **vars)
+{
+       channel_set_external_vars(&ari_vars, varc, vars);
 }
 
 /*!
@@ -7543,14 +7721,15 @@ struct varshead *ast_channel_get_vars(struct ast_channel *chan)
        return ret;
 }
 
-struct varshead *ast_channel_get_manager_vars(struct ast_channel *chan)
+static struct varshead *channel_get_external_vars(struct external_vars *channelvars,
+       struct ast_channel *chan)
 {
        RAII_VAR(struct varshead *, ret, NULL, ao2_cleanup);
        RAII_VAR(struct ast_str *, tmp, NULL, ast_free);
        struct manager_channel_variable *mcv;
-       SCOPED_LOCK(lock, &channelvars, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK);
+       SCOPED_LOCK(lock, channelvars, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK);
 
-       if (AST_LIST_EMPTY(&channelvars)) {
+       if (AST_LIST_EMPTY(channelvars)) {
                return NULL;
        }
 
@@ -7561,7 +7740,7 @@ struct varshead *ast_channel_get_manager_vars(struct ast_channel *chan)
                return NULL;
        }
 
-       AST_LIST_TRAVERSE(&channelvars, mcv, entry) {
+       AST_LIST_TRAVERSE(channelvars, mcv, entry) {
                const char *val = NULL;
                struct ast_var_t *var;
 
@@ -7586,13 +7765,24 @@ struct varshead *ast_channel_get_manager_vars(struct ast_channel *chan)
 
        ao2_ref(ret, +1);
        return ret;
+
+}
+
+struct varshead *ast_channel_get_manager_vars(struct ast_channel *chan)
+{
+       return channel_get_external_vars(&ami_vars, chan);
+}
+
+struct varshead *ast_channel_get_ari_vars(struct ast_channel *chan)
+{
+       return channel_get_external_vars(&ari_vars, chan);
 }
 
 static void channels_shutdown(void)
 {
-       free_channelvars();
+       free_external_channelvars(&ami_vars);
+       free_external_channelvars(&ari_vars);
 
-       ast_data_unregister(NULL);
        ast_cli_unregister_multiple(cli_channel, ARRAY_LEN(cli_channel));
        if (channels) {
                ao2_container_unregister("channels");
@@ -7602,13 +7792,14 @@ static void channels_shutdown(void)
        ast_channel_unregister(&surrogate_tech);
 }
 
-void ast_channels_init(void)
+int ast_channels_init(void)
 {
        channels = ao2_container_alloc(NUM_CHANNEL_BUCKETS,
                        ast_channel_hash_cb, ast_channel_cmp_cb);
-       if (channels) {
-               ao2_container_register("channels", channels, prnt_channel_key);
+       if (!channels) {
+               return -1;
        }
+       ao2_container_register("channels", channels, prnt_channel_key);
 
        ast_channel_register(&surrogate_tech);
 
@@ -7616,12 +7807,14 @@ void ast_channels_init(void)
 
        ast_cli_register_multiple(cli_channel, ARRAY_LEN(cli_channel));
 
-       ast_data_register_multiple_core(channel_providers, ARRAY_LEN(channel_providers));
-
        ast_plc_reload();
 
-       ast_register_atexit(channels_shutdown);
+       ast_register_cleanup(channels_shutdown);
 
+       AST_RWLIST_HEAD_INIT(&ami_vars);
+       AST_RWLIST_HEAD_INIT(&ari_vars);
+
+       return 0;
 }
 
 /*! \brief Print call group and pickup group ---*/
@@ -7917,6 +8110,7 @@ void ast_channel_set_connected_line(struct ast_channel *chan, const struct ast_p
 
        ast_channel_lock(chan);
        ast_party_connected_line_set(ast_channel_connected(chan), connected, update);
+       ast_channel_publish_snapshot(chan);
        ast_channel_unlock(chan);
 }
 
@@ -8851,7 +9045,7 @@ static int redirecting_reason_build_data(unsigned char *data, size_t datalen,
 
        if (reason->str) {
                length = strlen(reason->str);
-               if (datalen < pos + sizeof(data[0] * 2) + length) {
+               if (datalen < pos + (sizeof(data[0]) * 2) + length) {
                        ast_log(LOG_WARNING, "No space left for %s string\n", label);
                        return -1;
                }
@@ -9906,6 +10100,36 @@ void ast_channel_queue_redirecting_update(struct ast_channel *chan, const struct
        ast_queue_control_data(chan, AST_CONTROL_REDIRECTING, data, datalen);
 }
 
+/*!
+ * Storage to determine if the current thread is running an intercept dialplan routine.
+ */
+AST_THREADSTORAGE_RAW(in_intercept_routine);
+
+/*!
+ * \internal
+ * \brief Set the current intercept dialplan routine status mode.
+ * \since 13.14.0
+ *
+ * \param in_intercept_mode New intercept mode.  (Non-zero if in intercept mode)
+ *
+ * \return Nothing
+ */
+static void channel_set_intercept_mode(int in_intercept_mode)
+{
+       int status;
+
+       status = ast_threadstorage_set_ptr(&in_intercept_routine,
+               in_intercept_mode ? (void *) 1 : (void *) 0);
+       if (status) {
+               ast_log(LOG_ERROR, "Failed to set dialplan intercept mode\n");
+       }
+}
+
+int ast_channel_get_intercept_mode(void)
+{
+       return ast_threadstorage_get_ptr(&in_intercept_routine) ? 1 : 0;
+}
+
 int ast_channel_connected_line_macro(struct ast_channel *autoservice_chan, struct ast_channel *macro_chan, const void *connected_info, int is_caller, int is_frame)
 {
        static int deprecation_warning = 0;
@@ -9941,7 +10165,9 @@ int ast_channel_connected_line_macro(struct ast_channel *autoservice_chan, struc
        }
        ast_channel_unlock(macro_chan);
 
+       channel_set_intercept_mode(1);
        retval = ast_app_run_macro(autoservice_chan, macro_chan, macro, macro_args);
+       channel_set_intercept_mode(0);
        if (!retval) {
                struct ast_party_connected_line saved_connected;
 
@@ -9991,7 +10217,9 @@ int ast_channel_redirecting_macro(struct ast_channel *autoservice_chan, struct a
        }
        ast_channel_unlock(macro_chan);
 
+       channel_set_intercept_mode(1);
        retval = ast_app_run_macro(autoservice_chan, macro_chan, macro, macro_args);
+       channel_set_intercept_mode(0);
        if (!retval) {
                struct ast_party_redirecting saved_redirecting;
 
@@ -10034,7 +10262,9 @@ int ast_channel_connected_line_sub(struct ast_channel *autoservice_chan, struct
        }
        ast_channel_unlock(sub_chan);
 
+       channel_set_intercept_mode(1);
        retval = ast_app_run_sub(autoservice_chan, sub_chan, sub, sub_args, 0);
+       channel_set_intercept_mode(0);
        if (!retval) {
                struct ast_party_connected_line saved_connected;
 
@@ -10077,7 +10307,9 @@ int ast_channel_redirecting_sub(struct ast_channel *autoservice_chan, struct ast
        }
        ast_channel_unlock(sub_chan);
 
+       channel_set_intercept_mode(1);
        retval = ast_app_run_sub(autoservice_chan, sub_chan, sub, sub_args, 0);
+       channel_set_intercept_mode(0);
        if (!retval) {
                struct ast_party_redirecting saved_redirecting;
 
@@ -10217,13 +10449,15 @@ int ast_channel_is_bridged(const struct ast_channel *chan)
 int ast_channel_is_leaving_bridge(struct ast_channel *chan)
 {
        int hangup_flags = ast_channel_softhangup_internal_flag(chan);
-       int hangup_test = hangup_flags & (AST_SOFTHANGUP_ASYNCGOTO | AST_SOFTHANGUP_UNBRIDGE);
+       int hangup_test = hangup_flags & AST_SOFTHANGUP_ASYNCGOTO;
+       int unbridge = ast_channel_unbridged(chan);
 
-       /* This function should only return true if either ASYNCGOTO
-        * or UNBRIDGE is set, or both flags are set. It should return
-        * false if any other flag is set.
+       /* This function should only return true if either the unbridged flag or
+        * the ASYNCGOTO soft hangup flag is set and when no other soft hangup
+        * flags are set. Any other soft hangup flags being set should make it
+        * return false.
         */
-       return (hangup_test && (hangup_test == hangup_flags));
+       return ((hangup_test || unbridge) && (hangup_test == hangup_flags));
 }
 
 struct ast_channel *ast_channel_bridge_peer(struct ast_channel *chan)
@@ -10264,6 +10498,7 @@ struct ast_channel *ast_channel_yank(struct ast_channel *yankee)
                char *context;
                char *name;
                int amaflags;
+               int priority;
                struct ast_format *readformat;
                struct ast_format *writeformat;
        } my_vars = { 0, };
@@ -10274,6 +10509,16 @@ struct ast_channel *ast_channel_yank(struct ast_channel *yankee)
        my_vars.context = ast_strdupa(ast_channel_context(yankee));
        my_vars.name = ast_strdupa(ast_channel_name(yankee));
        my_vars.amaflags = ast_channel_amaflags(yankee);
+       my_vars.priority = ast_channel_priority(yankee);
+       /* The priority as returned by ast_channel_yank is where the channel
+        * should go if the dialplan is executed on it. If the channel is
+        * already executing dialplan then the priority currently set is
+        * where it is currently. We increment it so it becomes where it should
+        * execute.
+        */
+       if (ast_test_flag(ast_channel_flags(yankee), AST_FLAG_IN_AUTOLOOP)) {
+               my_vars.priority++;
+       }
        my_vars.writeformat = ao2_bump(ast_channel_writeformat(yankee));
        my_vars.readformat = ao2_bump(ast_channel_readformat(yankee));
        ast_channel_unlock(yankee);
@@ -10293,6 +10538,7 @@ struct ast_channel *ast_channel_yank(struct ast_channel *yankee)
        ast_channel_set_writeformat(yanked_chan, my_vars.writeformat);
        ao2_cleanup(my_vars.readformat);
        ao2_cleanup(my_vars.writeformat);
+       ast_channel_priority_set(yanked_chan, my_vars.priority);
 
        ast_channel_unlock(yanked_chan);
 
@@ -10421,7 +10667,7 @@ static const struct ast_datastore_info *suppress_get_datastore_information(enum
 
 int ast_channel_suppress(struct ast_channel *chan, unsigned int direction, enum ast_frame_type frametype)
 {
-       RAII_VAR(struct suppress_data *, suppress, NULL, ao2_cleanup);
+       struct suppress_data *suppress;
        const struct ast_datastore_info *datastore_info = NULL;
        struct ast_datastore *datastore = NULL;
        struct ast_framehook_interface interface = {
@@ -10457,6 +10703,7 @@ int ast_channel_suppress(struct ast_channel *chan, unsigned int direction, enum
        if (framehook_id < 0) {
                /* Hook attach failed.  Get rid of the evidence. */
                ast_log(LOG_WARNING, "Failed to attach framehook while attempting to suppress a stream.\n");
+               ao2_ref(suppress, -1);
                return -1;
        }
 
@@ -10468,11 +10715,11 @@ int ast_channel_suppress(struct ast_channel *chan, unsigned int direction, enum
        if (!(datastore = ast_datastore_alloc(datastore_info, NULL))) {
                ast_log(LOG_WARNING, "Failed to allocate datastore while attempting to suppress a stream.\n");
                ast_framehook_detach(chan, framehook_id);
+               ao2_ref(suppress, -1);
                return -1;
        }
 
-       /* and another ref for the datastore */
-       ao2_ref(suppress, +1);
+       /* the ref provided by the allocation is taken by the datastore */
        datastore->data = suppress;
 
        ast_channel_datastore_add(chan, datastore);
@@ -10518,7 +10765,7 @@ void ast_channel_end_dtmf(struct ast_channel *chan, char digit, struct timeval s
        ast_channel_lock(chan);
        dead = ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE)
                || (ast_channel_softhangup_internal_flag(chan)
-                       & ~(AST_SOFTHANGUP_ASYNCGOTO | AST_SOFTHANGUP_UNBRIDGE));
+                       & ~AST_SOFTHANGUP_ASYNCGOTO);
        ast_channel_unlock(chan);
        if (dead) {
                /* Channel is a zombie or a real hangup. */
@@ -10601,3 +10848,62 @@ int ast_channel_feature_hooks_replace(struct ast_channel *chan, struct ast_bridg
 {
        return channel_feature_hooks_set_full(chan, features, 1);
 }
+
+enum ast_channel_error ast_channel_errno(void)
+{
+       return ast_channel_internal_errno();
+}
+
+int ast_channel_request_stream_topology_change(struct ast_channel *chan,
+               struct ast_stream_topology *topology, void *change_source)
+{
+       int res;
+
+       ast_assert(chan != NULL);
+       ast_assert(topology != NULL);
+
+       ast_channel_lock(chan);
+       if (!ast_channel_is_multistream(chan) || !ast_channel_tech(chan)->indicate) {
+               ast_channel_unlock(chan);
+               return -1;
+       }
+
+       if (ast_stream_topology_equal(ast_channel_get_stream_topology(chan), topology)) {
+               ast_debug(3, "Topology of %s already matches what is requested so ignoring topology change request\n",
+                               ast_channel_name(chan));
+               ast_channel_unlock(chan);
+               return 0;
+       }
+
+       ast_channel_internal_set_stream_topology_change_source(chan, change_source);
+
+       res = ast_channel_tech(chan)->indicate(chan, AST_CONTROL_STREAM_TOPOLOGY_REQUEST_CHANGE, topology, sizeof(topology));
+       ast_channel_unlock(chan);
+       return res;
+}
+
+int ast_channel_stream_topology_changed(struct ast_channel *chan, struct ast_stream_topology *topology)
+{
+       ast_assert(chan != NULL);
+       ast_assert(topology != NULL);
+
+       if (!ast_channel_is_multistream(chan) || !ast_channel_tech(chan)->indicate) {
+               return -1;
+       }
+
+       return ast_channel_tech(chan)->indicate(chan, AST_CONTROL_STREAM_TOPOLOGY_CHANGED, topology, sizeof(topology));
+}
+
+void ast_channel_set_flag(struct ast_channel *chan, unsigned int flag)
+{
+       ast_channel_lock(chan);
+       ast_set_flag(ast_channel_flags(chan), flag);
+       ast_channel_unlock(chan);
+}
+
+void ast_channel_clear_flag(struct ast_channel *chan, unsigned int flag)
+{
+       ast_channel_lock(chan);
+       ast_clear_flag(ast_channel_flags(chan), flag);
+       ast_channel_unlock(chan);
+}