loader: Correct overly strict startup checks.
[asterisk/asterisk.git] / main / channel.c
index 12a30e0..7eb40d1 100644 (file)
@@ -66,7 +66,6 @@
 #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"
 /*** 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
@@ -850,10 +840,6 @@ __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. */
@@ -1011,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;
 }
 
@@ -1058,9 +1047,6 @@ struct ast_channel *__ast_dummy_channel_alloc(const char *file, int line, const
        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);
 
@@ -1304,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;
 }
@@ -1313,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,
@@ -2223,9 +2212,6 @@ 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;
@@ -2233,6 +2219,8 @@ static void ast_channel_destructor(void *obj)
        char device_name[AST_CHANNEL_NAME];
        ast_callid callid;
 
+       ast_debug(1, "Channel %p '%s' destroying\n", chan, ast_channel_name(chan));
+
        /* Stop monitoring */
        if (ast_channel_monitor(chan)) {
                ast_channel_monitor(chan)->stop(chan, 0);
@@ -2323,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);
 
@@ -2481,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);
@@ -2675,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);
@@ -2734,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);
        }
@@ -3061,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;
@@ -3090,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]))) {
@@ -3114,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 */
@@ -3135,12 +3041,12 @@ 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));
                }
-               ast_channel_lock(c[x]);
                CHECK_BLOCKING(c[x]);
                ast_channel_unlock(c[x]);
        }
@@ -3234,205 +3140,6 @@ 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 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;
-
-       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;
-               }
-       }
-
-       ast_channel_unlock(chan);
-
-       /* Time to make this channel block... */
-       CHECK_BLOCKING(chan);
-
-       if (*ms > 0) {
-               start = ast_tvnow();
-       }
-
-       /* 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);
-
-       /* Stop blocking */
-       ast_clear_flag(ast_channel_flags(chan), AST_FLAG_BLOCKING);
-
-       /* Simulate a timeout if we were interrupted */
-       if (res < 0) {
-               if (errno != EINTR) {
-                       *ms = -1;
-               }
-               return 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;
-               }
-       }
-
-       /* No fd ready, reset timeout and be done for now */
-       if (!res) {
-               *ms = 0;
-               return winner;
-       }
-
-       /* 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);
-       } else {
-               ast_clear_flag(ast_channel_flags(chan), AST_FLAG_EXCEPTION);
-       }
-
-       if (*ms > 0) {
-               *ms -= ast_tvdiff_ms(ast_tvnow(), start);
-               if (*ms < 0) {
-                       *ms = 0;
-               }
-       }
-
-       return chan;
-}
-
-static struct ast_channel *ast_waitfor_nandfds_complex(struct ast_channel **c, int n, int *ms)
-{
-       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;
-               }
-       }
-
-       if (*ms > 0) {
-               start = ast_tvnow();
-       }
-
-       res = epoll_wait(ast_channel_epfd(c[0]), ev, 25, rms);
-
-       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);
@@ -3453,7 +3160,7 @@ int ast_waitfor(struct ast_channel *c, int ms)
 
 int ast_waitfordigit(struct ast_channel *c, int ms)
 {
-       return ast_waitfordigit_full(c, ms, -1, -1);
+       return ast_waitfordigit_full(c, ms, NULL, -1, -1);
 }
 
 int ast_settimeout(struct ast_channel *c, unsigned int rate, int (*func)(const void *data), void *data)
@@ -3515,7 +3222,7 @@ int ast_settimeout_full(struct ast_channel *c, unsigned int rate, int (*func)(co
        return res;
 }
 
-int ast_waitfordigit_full(struct ast_channel *c, int timeout_ms, int audiofd, int cmdfd)
+int ast_waitfordigit_full(struct ast_channel *c, int timeout_ms, const char *breakon, int audiofd, int cmdfd)
 {
        struct timeval start = ast_tvnow();
        int ms;
@@ -3525,7 +3232,7 @@ int ast_waitfordigit_full(struct ast_channel *c, int timeout_ms, int audiofd, in
                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);
+       ast_channel_set_flag(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.
@@ -3544,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:
@@ -3580,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:
@@ -3615,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 */
 }
@@ -4068,6 +3782,19 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio, int
                                }
                                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:
@@ -4333,7 +4060,7 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio, int
                                }
 #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(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) {
@@ -4456,6 +4183,11 @@ struct ast_frame *ast_read_noaudio(struct ast_channel *chan)
        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)
 {
        return ast_indicate_data(chan, condition, NULL, 0);
@@ -4494,6 +4226,9 @@ static int attribute_const is_visible_indication(enum ast_control_frame_type con
        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:
@@ -4792,6 +4527,9 @@ static int indicate_data_internal(struct ast_channel *chan, int _condition, cons
        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:
@@ -5203,17 +4941,28 @@ int ast_write_stream(struct ast_channel *chan, int stream_num, struct ast_frame
                goto done;
        }
 
-       /* If this frame is writing an audio or video frame get the stream information */
-       if (fr->frametype == AST_FRAME_VOICE || fr->frametype == AST_FRAME_VIDEO) {
-               /* Initially use the default stream unless an explicit stream is provided */
-               stream = default_stream = ast_channel_get_default_stream(chan, ast_format_get_type(fr->subclass.format));
+       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;
 
-               if (stream_num >= 0) {
-                       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);
+               /* 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
@@ -5305,43 +5054,50 @@ int ast_write_stream(struct ast_channel *chan, int stream_num, struct ast_frame
        case AST_FRAME_VIDEO:
                /* XXX Handle translation of video codecs one day XXX */
                if (ast_channel_tech(chan)->write_stream) {
-                       res = ast_channel_tech(chan)->write_stream(chan, ast_stream_get_position(stream), fr);
+                       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_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)) {
-                               struct ast_frame *old_frame;
                                hooked = 1;
-                               old_frame = fr;
-                               fr = ast_audiohook_write_list(chan, ast_channel_audiohooks(chan), AST_AUDIOHOOK_DIRECTION_WRITE, fr);
-                               if (old_frame != fr) {
-                                       ast_frfree(old_frame);
-                               }
+                               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 ((stream != default_stream) || ast_format_cmp(fr->subclass.format, ast_channel_rawwriteformat(chan)) == AST_FORMAT_CMP_EQUAL) {
-                       f = fr;
-               } else {
+               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);
 
@@ -5367,7 +5123,18 @@ int ast_write_stream(struct ast_channel *chan, int stream_num, struct ast_frame
                                        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) {
@@ -5444,7 +5211,7 @@ int ast_write_stream(struct ast_channel *chan, int stream_num, struct ast_frame
                                }
 #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) {
@@ -5492,7 +5259,11 @@ int ast_write_stream(struct ast_channel *chan, int stream_num, struct ast_frame
                        f = NULL;
                } else {
                        if (ast_channel_tech(chan)->write_stream) {
-                               res = ast_channel_tech(chan)->write_stream(chan, ast_stream_get_position(stream), f);
+                               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 {
@@ -5994,9 +5765,9 @@ 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));
@@ -6261,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;
 
@@ -6278,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);
@@ -6303,13 +6106,10 @@ struct ast_channel *ast_request(const char *type, struct ast_format_cap *request
                                        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 is because we don't have the ability
@@ -6318,50 +6118,56 @@ struct ast_channel *ast_request(const char *type, struct ast_format_cap *request
                 */
                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) {
-                       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);
-                       }
+               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");
-                       ast_hangup(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);
 }
 
 /*!
@@ -6562,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);
@@ -6835,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;
@@ -7025,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));
        }
@@ -7774,122 +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, "presencestate", cl->tech->presencestate ? 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
  *
@@ -8087,7 +7783,6 @@ static void channels_shutdown(void)
        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");
@@ -8112,8 +7807,6 @@ int 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_cleanup(channels_shutdown);
@@ -9352,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;
                }
@@ -10805,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, };
@@ -10815,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);
@@ -10834,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);
 
@@ -10962,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 = {
@@ -10998,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;
        }
 
@@ -11009,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);
@@ -11147,3 +10853,57 @@ 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);
+}