Merge "res_calendar: Specialized calendars depend on symbols of general calendar."
[asterisk/asterisk.git] / main / bridge.c
index 55fc7fd..4f79852 100644 (file)
                <description>
                        <para>Returns detailed information about the available bridging technologies.</para>
                </description>
+               <see-also>
+                       <ref type="manager">BridgeTechnologySuspend</ref>
+                       <ref type="manager">BridgeTechnologyUnsuspend</ref>
+               </see-also>
        </manager>
        <manager name="BridgeTechnologySuspend" language="en_US">
                <synopsis>
                <description>
                        <para>Marks a bridging technology as suspended, which prevents subsequently created bridges from using it.</para>
                </description>
+               <see-also>
+                       <ref type="manager">BridgeTechnologySuspend</ref>
+                       <ref type="manager">BridgeTechnologyUnsuspend</ref>
+               </see-also>
        </manager>
        <manager name="BridgeTechnologyUnsuspend" language="en_US">
                <synopsis>
                <description>
                        <para>Clears a previously suspended bridging technology, which allows subsequently created bridges to use it.</para>
                </description>
+               <see-also>
+                       <ref type="manager">BridgeTechnologyList</ref>
+                       <ref type="manager">BridgeTechnologySuspend</ref>
+               </see-also>
        </manager>
 ***/
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
 #include "asterisk/logger.h"
 #include "asterisk/channel.h"
 #include "asterisk/options.h"
@@ -129,7 +139,6 @@ static unsigned int optimization_id;
 #define ATTENDEDTRANSFER "ATTENDEDTRANSFER"
 
 static void cleanup_video_mode(struct ast_bridge *bridge);
-static int bridge_make_compatible(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel);
 
 /*! Default DTMF keys for built in features */
 static char builtin_features_dtmf[AST_BRIDGE_BUILTIN_END][MAXIMUM_DTMF_FEATURE_STRING];
@@ -225,8 +234,21 @@ int __ast_bridge_technology_register(struct ast_bridge_technology *technology, s
        /* Copy module pointer so reference counting can keep the module from unloading */
        technology->mod = module;
 
-       /* Insert our new bridge technology into the list and print out a pretty message */
-       AST_RWLIST_INSERT_TAIL(&bridge_technologies, technology, entry);
+       /* Find the correct position to insert the technology. */
+       AST_RWLIST_TRAVERSE_SAFE_BEGIN(&bridge_technologies, current, entry) {
+               /* Put the highest preference tech's first in the list. */
+               if (technology->preference >= current->preference) {
+                       AST_RWLIST_INSERT_BEFORE_CURRENT(technology, entry);
+
+                       break;
+               }
+       }
+       AST_RWLIST_TRAVERSE_SAFE_END;
+
+       if (!current) {
+               /* Insert our new bridge technology to the end of the list. */
+               AST_RWLIST_INSERT_TAIL(&bridge_technologies, technology, entry);
+       }
 
        AST_RWLIST_UNLOCK(&bridge_technologies);
 
@@ -415,23 +437,34 @@ static void bridge_reconfigured_connected_line_update(struct ast_bridge *bridge)
  */
 static void bridge_channel_complete_join(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
 {
-       /* Make the channel compatible with the bridge */
-       bridge_make_compatible(bridge, bridge_channel);
-
        /* Tell the bridge technology we are joining so they set us up */
        ast_debug(1, "Bridge %s: %p(%s) is joining %s technology\n",
                bridge->uniqueid, bridge_channel, ast_channel_name(bridge_channel->chan),
                bridge->technology->name);
        if (bridge->technology->join
                && bridge->technology->join(bridge, bridge_channel)) {
-               ast_debug(1, "Bridge %s: %p(%s) failed to join %s technology\n",
+               /* We cannot leave the channel partially in the bridge so we must kick it out */
+               ast_debug(1, "Bridge %s: %p(%s) failed to join %s technology (Kicking it out)\n",
                        bridge->uniqueid, bridge_channel, ast_channel_name(bridge_channel->chan),
                        bridge->technology->name);
                bridge_channel->just_joined = 1;
+               ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END, 0);
                return;
        }
 
        bridge_channel->just_joined = 0;
+
+       /*
+        * When a channel joins the bridge its streams need to be mapped to the bridge's
+        * media types vector. This way all streams map to the same media type index for
+        * a given channel.
+        */
+       if (bridge_channel->bridge->technology->stream_topology_changed) {
+               bridge_channel->bridge->technology->stream_topology_changed(
+                       bridge_channel->bridge, bridge_channel);
+       } else {
+               ast_bridge_channel_stream_map(bridge_channel);
+       }
 }
 
 /*!
@@ -461,6 +494,7 @@ static void bridge_complete_join(struct ast_bridge *bridge)
        }
 
        AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
+               bridge_channel_queue_deferred_frames(bridge_channel);
                if (!bridge_channel->just_joined) {
                        continue;
                }
@@ -496,12 +530,17 @@ static struct ast_bridge_technology *find_best_technology(uint32_t capabilities,
                                current->name);
                        continue;
                }
+               if (!ast_module_running_ref(current->mod)) {
+                       ast_debug(1, "Bridge technology %s is not running, skipping.\n", current->name);
+                       continue;
+               }
+               if (best) {
+                       ast_module_unref(best->mod);
+               }
                best = current;
        }
 
        if (best) {
-               /* Increment it's module reference count if present so it does not get unloaded while in use */
-               ast_module_ref(best->mod);
                ast_debug(1, "Chose bridge technology %s\n", best->name);
        }
 
@@ -681,6 +720,8 @@ static void destroy_bridge(void *obj)
                bridge->technology = NULL;
        }
 
+       AST_VECTOR_FREE(&bridge->media_types);
+
        bridge->callid = 0;
 
        cleanup_video_mode(bridge);
@@ -736,6 +777,8 @@ struct ast_bridge *bridge_alloc(size_t size, const struct ast_bridge_methods *v_
 
        bridge->v_table = v_table;
 
+       AST_VECTOR_INIT(&bridge->media_types, AST_MEDIA_TYPE_END);
+
        return bridge;
 }
 
@@ -761,11 +804,13 @@ struct ast_bridge *bridge_base_init(struct ast_bridge *self, uint32_t capabiliti
        ast_set_flag(&self->feature_flags, flags);
        self->allowed_capabilities = capabilities;
 
-       if (bridge_topics_init(self) != 0) {
-               ast_log(LOG_WARNING, "Bridge %s: Could not initialize topics\n",
-                       self->uniqueid);
-               ao2_ref(self, -1);
-               return NULL;
+       if (!(flags & AST_BRIDGE_FLAG_INVISIBLE)) {
+               if (bridge_topics_init(self) != 0) {
+                       ast_log(LOG_WARNING, "Bridge %s: Could not initialize topics\n",
+                               self->uniqueid);
+                       ao2_ref(self, -1);
+                       return NULL;
+               }
        }
 
        /* Use our helper function to find the "best" bridge technology. */
@@ -795,9 +840,11 @@ struct ast_bridge *bridge_base_init(struct ast_bridge *self, uint32_t capabiliti
                return NULL;
        }
 
-       if (!ast_bridge_topic(self)) {
-               ao2_ref(self, -1);
-               return NULL;
+       if (!(flags & AST_BRIDGE_FLAG_INVISIBLE)) {
+               if (!ast_bridge_topic(self)) {
+                       ao2_ref(self, -1);
+                       return NULL;
+               }
        }
 
        return self;
@@ -955,74 +1002,6 @@ int ast_bridge_destroy(struct ast_bridge *bridge, int cause)
        return 0;
 }
 
-static int bridge_make_compatible(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
-{
-       struct ast_str *codec_buf = ast_str_alloca(64);
-       struct ast_format *best_format;
-       RAII_VAR(struct ast_format *, read_format, NULL, ao2_cleanup);
-       RAII_VAR(struct ast_format *, write_format, NULL, ao2_cleanup);
-
-       ast_channel_lock(bridge_channel->chan);
-       read_format = ao2_bump(ast_channel_readformat(bridge_channel->chan));
-       write_format = ao2_bump(ast_channel_writeformat(bridge_channel->chan));
-       ast_channel_unlock(bridge_channel->chan);
-
-       /* Are the formats currently in use something this bridge can handle? */
-       if (ast_format_cap_iscompatible_format(bridge->technology->format_capabilities, read_format) == AST_FORMAT_CMP_NOT_EQUAL) {
-               best_format = ast_format_cap_get_format(bridge->technology->format_capabilities, 0);
-
-               /* Read format is a no go... */
-               ast_debug(1, "Bridge technology %s wants to read any of formats %s but channel has %s\n",
-                       bridge->technology->name,
-                       ast_format_cap_get_names(bridge->technology->format_capabilities, &codec_buf),
-                       ast_format_get_name(read_format));
-
-               /* Switch read format to the best one chosen */
-               if (ast_set_read_format(bridge_channel->chan, best_format)) {
-                       ast_log(LOG_WARNING, "Failed to set channel %s to read format %s\n",
-                               ast_channel_name(bridge_channel->chan), ast_format_get_name(best_format));
-                       ao2_cleanup(best_format);
-                       return -1;
-               }
-               ast_debug(1, "Bridge %s put channel %s into read format %s\n",
-                       bridge->uniqueid, ast_channel_name(bridge_channel->chan),
-                       ast_format_get_name(best_format));
-               ao2_cleanup(best_format);
-       } else {
-               ast_debug(1, "Bridge %s is happy that channel %s already has read format %s\n",
-                       bridge->uniqueid, ast_channel_name(bridge_channel->chan),
-                       ast_format_get_name(read_format));
-       }
-
-       if (ast_format_cap_iscompatible_format(bridge->technology->format_capabilities, write_format) == AST_FORMAT_CMP_NOT_EQUAL) {
-               best_format = ast_format_cap_get_format(bridge->technology->format_capabilities, 0);
-
-               /* Write format is a no go... */
-               ast_debug(1, "Bridge technology %s wants to write any of formats %s but channel has %s\n",
-                       bridge->technology->name,
-                       ast_format_cap_get_names(bridge->technology->format_capabilities, &codec_buf),
-                       ast_format_get_name(write_format));
-
-               /* Switch write format to the best one chosen */
-               if (ast_set_write_format(bridge_channel->chan, best_format)) {
-                       ast_log(LOG_WARNING, "Failed to set channel %s to write format %s\n",
-                               ast_channel_name(bridge_channel->chan), ast_format_get_name(best_format));
-                       ao2_cleanup(best_format);
-                       return -1;
-               }
-               ast_debug(1, "Bridge %s put channel %s into write format %s\n",
-                       bridge->uniqueid, ast_channel_name(bridge_channel->chan),
-                       ast_format_get_name(best_format));
-               ao2_cleanup(best_format);
-       } else {
-               ast_debug(1, "Bridge %s is happy that channel %s already has write format %s\n",
-                       bridge->uniqueid, ast_channel_name(bridge_channel->chan),
-                       ast_format_get_name(write_format));
-       }
-
-       return 0;
-}
-
 /*!
  * \internal
  * \brief Perform the smart bridge operation.
@@ -1283,7 +1262,7 @@ static void check_bridge_play_sounds(struct ast_bridge *bridge)
        }
 }
 
-static void update_bridge_vars_set(struct ast_channel *chan, const char *name, const char *pvtid)
+void ast_bridge_vars_set(struct ast_channel *chan, const char *name, const char *pvtid)
 {
        ast_channel_stage_snapshot(chan);
        pbx_builtin_setvar_helper(chan, "BRIDGEPEER", name);
@@ -1323,12 +1302,12 @@ static void set_bridge_peer_vars_2party(struct ast_channel *c0, struct ast_chann
        ast_channel_unlock(c1);
 
        ast_channel_lock(c0);
-       update_bridge_vars_set(c0, c1_name, c1_pvtid);
+       ast_bridge_vars_set(c0, c1_name, c1_pvtid);
        UPDATE_BRIDGE_VARS_GET(c0, c0_name, c0_pvtid);
        ast_channel_unlock(c0);
 
        ast_channel_lock(c1);
-       update_bridge_vars_set(c1, c0_name, c0_pvtid);
+       ast_bridge_vars_set(c1, c0_name, c0_pvtid);
        ast_channel_unlock(c1);
 }
 
@@ -1429,7 +1408,7 @@ static void set_bridge_peer_vars_multiparty(struct ast_bridge *bridge)
                ++idx;
 
                ast_channel_lock(bridge_channel->chan);
-               update_bridge_vars_set(bridge_channel->chan, buf, NULL);
+               ast_bridge_vars_set(bridge_channel->chan, buf, NULL);
                ast_channel_unlock(bridge_channel->chan);
        }
 }
@@ -1451,7 +1430,7 @@ static void set_bridge_peer_vars_holding(struct ast_bridge *bridge)
 
        AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
                ast_channel_lock(bridge_channel->chan);
-               update_bridge_vars_set(bridge_channel->chan, NULL, NULL);
+               ast_bridge_vars_set(bridge_channel->chan, NULL, NULL);
                ast_channel_unlock(bridge_channel->chan);
        }
 }
@@ -1553,6 +1532,150 @@ void ast_bridge_notify_masquerade(struct ast_channel *chan)
        ao2_ref(bridge_channel, -1);
 }
 
+/*!
+ * \brief Internal bridge impart wait condition and associated conditional.
+ */
+struct bridge_channel_impart_cond {
+       AST_LIST_ENTRY(bridge_channel_impart_cond) node;
+       /*! Lock for the data structure */
+       ast_mutex_t lock;
+       /*! Wait condition */
+       ast_cond_t cond;
+       /*! Wait until done */
+       int done;
+};
+
+AST_LIST_HEAD_NOLOCK(bridge_channel_impart_ds_head, bridge_channel_impart_cond);
+
+/*!
+ * \internal
+ * \brief Signal imparting threads to wake up.
+ * \since 13.9.0
+ *
+ * \param ds_head List of imparting threads to wake up.
+ *
+ * \return Nothing
+ */
+static void bridge_channel_impart_ds_head_signal(struct bridge_channel_impart_ds_head *ds_head)
+{
+       if (ds_head) {
+               struct bridge_channel_impart_cond *cond;
+
+               while ((cond = AST_LIST_REMOVE_HEAD(ds_head, node))) {
+                       ast_mutex_lock(&cond->lock);
+                       cond->done = 1;
+                       ast_cond_signal(&cond->cond);
+                       ast_mutex_unlock(&cond->lock);
+               }
+       }
+}
+
+static void bridge_channel_impart_ds_head_dtor(void *doomed)
+{
+       bridge_channel_impart_ds_head_signal(doomed);
+       ast_free(doomed);
+}
+
+/*!
+ * \internal
+ * \brief Fixup the bridge impart datastore.
+ * \since 13.9.0
+ *
+ * \param data Bridge impart datastore data to fixup from old_chan.
+ * \param old_chan The datastore is moving from this channel.
+ * \param new_chan The datastore is moving to this channel.
+ *
+ * \return Nothing
+ */
+static void bridge_channel_impart_ds_head_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
+{
+       /*
+        * Signal any waiting impart threads.  The masquerade is going to kill
+        * old_chan and we don't need to be waiting on new_chan.
+        */
+       bridge_channel_impart_ds_head_signal(data);
+}
+
+static const struct ast_datastore_info bridge_channel_impart_ds_info = {
+       .type = "bridge-impart-ds",
+       .destroy = bridge_channel_impart_ds_head_dtor,
+       .chan_fixup = bridge_channel_impart_ds_head_fixup,
+};
+
+/*!
+ * \internal
+ * \brief Add impart wait datastore conditional to channel.
+ * \since 13.9.0
+ *
+ * \param chan Channel to add the impart wait conditional.
+ * \param cond Imparting conditional to add.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int bridge_channel_impart_add(struct ast_channel *chan, struct bridge_channel_impart_cond *cond)
+{
+       struct ast_datastore *datastore;
+       struct bridge_channel_impart_ds_head *ds_head;
+
+       ast_channel_lock(chan);
+
+       datastore = ast_channel_datastore_find(chan, &bridge_channel_impart_ds_info, NULL);
+       if (!datastore) {
+               datastore = ast_datastore_alloc(&bridge_channel_impart_ds_info, NULL);
+               if (!datastore) {
+                       ast_channel_unlock(chan);
+                       return -1;
+               }
+               ds_head = ast_calloc(1, sizeof(*ds_head));
+               if (!ds_head) {
+                       ast_channel_unlock(chan);
+                       ast_datastore_free(datastore);
+                       return -1;
+               }
+               datastore->data = ds_head;
+               ast_channel_datastore_add(chan, datastore);
+       } else {
+               ds_head = datastore->data;
+               ast_assert(ds_head != NULL);
+       }
+
+       AST_LIST_INSERT_TAIL(ds_head, cond, node);
+
+       ast_channel_unlock(chan);
+       return 0;
+}
+
+void bridge_channel_impart_signal(struct ast_channel *chan)
+{
+       struct ast_datastore *datastore;
+
+       ast_channel_lock(chan);
+       datastore = ast_channel_datastore_find(chan, &bridge_channel_impart_ds_info, NULL);
+       if (datastore) {
+               bridge_channel_impart_ds_head_signal(datastore->data);
+       }
+       ast_channel_unlock(chan);
+}
+
+/*!
+ * \internal
+ * \brief Block imparting channel thread until signaled.
+ * \since 13.9.0
+ *
+ * \param cond Imparting conditional to wait for.
+ *
+ * \return Nothing
+ */
+static void bridge_channel_impart_wait(struct bridge_channel_impart_cond *cond)
+{
+       ast_mutex_lock(&cond->lock);
+       while (!cond->done) {
+               ast_cond_wait(&cond->cond, &cond->lock);
+       }
+       ast_mutex_unlock(&cond->lock);
+}
+
 /*
  * XXX ASTERISK-21271 make ast_bridge_join() require features to be allocated just like ast_bridge_impart() and not expect the struct back.
  *
@@ -1636,8 +1759,9 @@ int ast_bridge_join(struct ast_bridge *bridge,
 
        ao2_ref(bridge_channel, -1);
 
-join_exit:;
+join_exit:
        ast_bridge_run_after_callback(chan);
+       bridge_channel_impart_signal(chan);
        if (!(ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_ASYNCGOTO)
                && !ast_bridge_setup_after_goto(chan)) {
                /* Claim the after bridge goto is an async goto destination. */
@@ -1652,12 +1776,13 @@ join_exit:;
 static void *bridge_channel_depart_thread(void *data)
 {
        struct ast_bridge_channel *bridge_channel = data;
+       int res = 0;
 
        if (bridge_channel->callid) {
                ast_callid_threadassoc_add(bridge_channel->callid);
        }
 
-       bridge_channel_internal_join(bridge_channel);
+       res = bridge_channel_internal_join(bridge_channel);
 
        /*
         * cleanup
@@ -1669,7 +1794,10 @@ static void *bridge_channel_depart_thread(void *data)
        ast_bridge_features_destroy(bridge_channel->features);
        bridge_channel->features = NULL;
 
-       ast_bridge_discard_after_callback(bridge_channel->chan, AST_BRIDGE_AFTER_CB_REASON_DEPART);
+       ast_bridge_discard_after_callback(bridge_channel->chan,
+               res ? AST_BRIDGE_AFTER_CB_REASON_IMPART_FAILED : AST_BRIDGE_AFTER_CB_REASON_DEPART);
+       /* If join failed there will be impart threads waiting. */
+       bridge_channel_impart_signal(bridge_channel->chan);
        ast_bridge_discard_after_goto(bridge_channel->chan);
 
        return NULL;
@@ -1702,15 +1830,18 @@ static void *bridge_channel_ind_thread(void *data)
        ao2_ref(bridge_channel, -1);
 
        ast_bridge_run_after_callback(chan);
+       /* If join failed there will be impart threads waiting. */
+       bridge_channel_impart_signal(chan);
        ast_bridge_run_after_goto(chan);
        return NULL;
 }
 
-int ast_bridge_impart(struct ast_bridge *bridge,
+static int bridge_impart_internal(struct ast_bridge *bridge,
        struct ast_channel *chan,
        struct ast_channel *swap,
        struct ast_bridge_features *features,
-       enum ast_bridge_impart_flags flags)
+       enum ast_bridge_impart_flags flags,
+       struct bridge_channel_impart_cond *cond)
 {
        int res = 0;
        struct ast_bridge_channel *bridge_channel;
@@ -1769,6 +1900,9 @@ int ast_bridge_impart(struct ast_bridge *bridge,
 
        /* Actually create the thread that will handle the channel */
        if (!res) {
+               res = bridge_channel_impart_add(chan, cond);
+       }
+       if (!res) {
                if ((flags & AST_BRIDGE_IMPART_CHAN_MASK) == AST_BRIDGE_IMPART_CHAN_INDEPENDENT) {
                        res = ast_pthread_create_detached(&bridge_channel->thread, NULL,
                                bridge_channel_ind_thread, bridge_channel);
@@ -1776,6 +1910,10 @@ int ast_bridge_impart(struct ast_bridge *bridge,
                        res = ast_pthread_create(&bridge_channel->thread, NULL,
                                bridge_channel_depart_thread, bridge_channel);
                }
+
+               if (!res) {
+                       bridge_channel_impart_wait(cond);
+               }
        }
 
        if (res) {
@@ -1796,6 +1934,32 @@ int ast_bridge_impart(struct ast_bridge *bridge,
        return 0;
 }
 
+int ast_bridge_impart(struct ast_bridge *bridge,
+       struct ast_channel *chan,
+       struct ast_channel *swap,
+       struct ast_bridge_features *features,
+       enum ast_bridge_impart_flags flags)
+{
+       struct bridge_channel_impart_cond cond = {
+               .done = 0,
+       };
+       int res;
+
+       ast_mutex_init(&cond.lock);
+       ast_cond_init(&cond.cond, NULL);
+
+       res = bridge_impart_internal(bridge, chan, swap, features, flags, &cond);
+       if (res) {
+               /* Impart failed.  Signal any other waiting impart threads */
+               bridge_channel_impart_signal(chan);
+       }
+
+       ast_cond_destroy(&cond.cond);
+       ast_mutex_destroy(&cond.lock);
+
+       return res;
+}
+
 int ast_bridge_depart(struct ast_channel *chan)
 {
        struct ast_bridge_channel *bridge_channel;
@@ -2241,7 +2405,7 @@ int bridge_do_move(struct ast_bridge *dst_bridge, struct ast_bridge_channel *bri
 
        bridge_channel_moving(bridge_channel, orig_bridge, dst_bridge);
 
-       if (bridge_channel_internal_push(bridge_channel)) {
+       if (bridge_channel_internal_push_full(bridge_channel, optimized)) {
                /* Try to put the channel back into the original bridge. */
                ast_bridge_features_remove(bridge_channel->features,
                        AST_BRIDGE_HOOK_REMOVE_ON_PULL);
@@ -2254,7 +2418,6 @@ int bridge_do_move(struct ast_bridge *dst_bridge, struct ast_bridge_channel *bri
                                        AST_BRIDGE_HOOK_REMOVE_ON_PULL);
                                ast_bridge_channel_leave_bridge(bridge_channel,
                                        BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, bridge_channel->bridge->cause);
-                               bridge_channel_settle_owed_events(orig_bridge, bridge_channel);
                        }
                } else {
                        ast_bridge_channel_leave_bridge(bridge_channel,
@@ -2262,7 +2425,7 @@ int bridge_do_move(struct ast_bridge *dst_bridge, struct ast_bridge_channel *bri
                        bridge_channel_settle_owed_events(orig_bridge, bridge_channel);
                }
                res = -1;
-       } else {
+       } else if (!optimized) {
                bridge_channel_settle_owed_events(orig_bridge, bridge_channel);
        }
 
@@ -2366,6 +2529,8 @@ int ast_bridge_add_channel(struct ast_bridge *bridge, struct ast_channel *chan,
        RAII_VAR(struct ast_bridge *, chan_bridge, NULL, ao2_cleanup);
        RAII_VAR(struct ast_channel *, yanked_chan, NULL, ao2_cleanup);
 
+       ast_moh_stop(chan);
+
        ast_channel_lock(chan);
        chan_bridge = ast_channel_get_bridge(chan);
        ast_channel_unlock(chan);
@@ -2373,6 +2538,9 @@ int ast_bridge_add_channel(struct ast_bridge *bridge, struct ast_channel *chan,
        if (chan_bridge) {
                struct ast_bridge_channel *bridge_channel;
 
+               /* The channel is in a bridge so it is not getting any new features. */
+               ast_bridge_features_destroy(features);
+
                ast_bridge_lock_both(bridge, chan_bridge);
                bridge_channel = bridge_find_channel(chan_bridge, chan);
 
@@ -2395,9 +2563,6 @@ int ast_bridge_add_channel(struct ast_bridge *bridge, struct ast_channel *chan,
                bridge_dissolve_check_stolen(chan_bridge, bridge_channel);
                ast_bridge_unlock(chan_bridge);
                ast_bridge_unlock(bridge);
-
-               /* The channel was in a bridge so it is not getting any new features. */
-               ast_bridge_features_destroy(features);
        } else {
                /* Slightly less easy case. We need to yank channel A from
                 * where he currently is and impart him into our bridge.
@@ -2405,6 +2570,7 @@ int ast_bridge_add_channel(struct ast_bridge *bridge, struct ast_channel *chan,
                yanked_chan = ast_channel_yank(chan);
                if (!yanked_chan) {
                        ast_log(LOG_WARNING, "Could not gain control of channel %s\n", ast_channel_name(chan));
+                       ast_bridge_features_destroy(features);
                        return -1;
                }
                if (ast_channel_state(yanked_chan) != AST_STATE_UP) {
@@ -3609,6 +3775,13 @@ void ast_bridge_set_mixing_interval(struct ast_bridge *bridge, unsigned int mixi
        ast_bridge_unlock(bridge);
 }
 
+void ast_bridge_set_binaural_active(struct ast_bridge *bridge, unsigned int binaural_active)
+{
+       ast_bridge_lock(bridge);
+       bridge->softmix.binaural_active = binaural_active;
+       ast_bridge_unlock(bridge);
+}
+
 void ast_bridge_set_internal_sample_rate(struct ast_bridge *bridge, unsigned int sample_rate)
 {
        ast_bridge_lock(bridge);
@@ -3633,6 +3806,8 @@ static void cleanup_video_mode(struct ast_bridge *bridge)
                if (bridge->softmix.video_mode.mode_data.talker_src_data.chan_old_vsrc) {
                        ast_channel_unref(bridge->softmix.video_mode.mode_data.talker_src_data.chan_old_vsrc);
                }
+       case AST_BRIDGE_VIDEO_MODE_SFU:
+               break;
        }
        memset(&bridge->softmix.video_mode, 0, sizeof(bridge->softmix.video_mode));
 }
@@ -3643,8 +3818,11 @@ void ast_bridge_set_single_src_video_mode(struct ast_bridge *bridge, struct ast_
        cleanup_video_mode(bridge);
        bridge->softmix.video_mode.mode = AST_BRIDGE_VIDEO_MODE_SINGLE_SRC;
        bridge->softmix.video_mode.mode_data.single_src_data.chan_vsrc = ast_channel_ref(video_src_chan);
-       ast_test_suite_event_notify("BRIDGE_VIDEO_MODE", "Message: video mode set to single source\r\nVideo Mode: %u\r\nVideo Channel: %s",
-               bridge->softmix.video_mode.mode, ast_channel_name(video_src_chan));
+       ast_verb(5, "Video source in bridge '%s' (%s) is now '%s' (%s)\n",
+               bridge->name, bridge->uniqueid,
+               ast_channel_name(video_src_chan),
+               ast_channel_uniqueid(video_src_chan));
+       ast_bridge_publish_state(bridge);
        ast_indicate(video_src_chan, AST_CONTROL_VIDUPDATE);
        ast_bridge_unlock(bridge);
 }
@@ -3654,8 +3832,21 @@ void ast_bridge_set_talker_src_video_mode(struct ast_bridge *bridge)
        ast_bridge_lock(bridge);
        cleanup_video_mode(bridge);
        bridge->softmix.video_mode.mode = AST_BRIDGE_VIDEO_MODE_TALKER_SRC;
-       ast_test_suite_event_notify("BRIDGE_VIDEO_MODE", "Message: video mode set to talker source\r\nVideo Mode: %u",
-               bridge->softmix.video_mode.mode);
+       ast_bridge_unlock(bridge);
+}
+
+void ast_bridge_set_sfu_video_mode(struct ast_bridge *bridge)
+{
+       ast_bridge_lock(bridge);
+       cleanup_video_mode(bridge);
+       bridge->softmix.video_mode.mode = AST_BRIDGE_VIDEO_MODE_SFU;
+       ast_bridge_unlock(bridge);
+}
+
+void ast_bridge_set_video_update_discard(struct ast_bridge *bridge, unsigned int video_update_discard)
+{
+       ast_bridge_lock(bridge);
+       bridge->softmix.video_mode.video_update_discard = video_update_discard;
        ast_bridge_unlock(bridge);
 }
 
@@ -3675,7 +3866,7 @@ void ast_bridge_update_talker_src_video_mode(struct ast_bridge *bridge, struct a
                data->average_talking_energy = talker_energy;
        } else if ((data->average_talking_energy < talker_energy) && is_keyframe) {
                if (data->chan_old_vsrc) {
-                       ast_channel_unref(data->chan_old_vsrc);
+                       data->chan_old_vsrc = ast_channel_unref(data->chan_old_vsrc);
                }
                if (data->chan_vsrc) {
                        data->chan_old_vsrc = data->chan_vsrc;
@@ -3683,14 +3874,22 @@ void ast_bridge_update_talker_src_video_mode(struct ast_bridge *bridge, struct a
                }
                data->chan_vsrc = ast_channel_ref(chan);
                data->average_talking_energy = talker_energy;
-               ast_test_suite_event_notify("BRIDGE_VIDEO_SRC", "Message: video source updated\r\nVideo Channel: %s", ast_channel_name(data->chan_vsrc));
+               ast_verb(5, "Video source in bridge '%s' (%s) is now '%s' (%s)\n",
+                       bridge->name, bridge->uniqueid,
+                       ast_channel_name(data->chan_vsrc),
+                       ast_channel_uniqueid(data->chan_vsrc));
+               ast_bridge_publish_state(bridge);
                ast_indicate(data->chan_vsrc, AST_CONTROL_VIDUPDATE);
        } else if ((data->average_talking_energy < talker_energy) && !is_keyframe) {
                ast_indicate(chan, AST_CONTROL_VIDUPDATE);
        } else if (!data->chan_vsrc && is_keyframe) {
                data->chan_vsrc = ast_channel_ref(chan);
                data->average_talking_energy = talker_energy;
-               ast_test_suite_event_notify("BRIDGE_VIDEO_SRC", "Message: video source updated\r\nVideo Channel: %s", ast_channel_name(data->chan_vsrc));
+               ast_verb(5, "Video source in bridge '%s' (%s) is now '%s' (%s)\n",
+                       bridge->name, bridge->uniqueid,
+                       ast_channel_name(data->chan_vsrc),
+                       ast_channel_uniqueid(data->chan_vsrc));
+               ast_bridge_publish_state(bridge);
                ast_indicate(chan, AST_CONTROL_VIDUPDATE);
        } else if (!data->chan_old_vsrc && is_keyframe) {
                data->chan_old_vsrc = ast_channel_ref(chan);
@@ -3719,6 +3918,8 @@ int ast_bridge_number_video_src(struct ast_bridge *bridge)
                if (bridge->softmix.video_mode.mode_data.talker_src_data.chan_old_vsrc) {
                        res++;
                }
+       case AST_BRIDGE_VIDEO_MODE_SFU:
+               break;
        }
        ast_bridge_unlock(bridge);
        return res;
@@ -3743,7 +3944,8 @@ int ast_bridge_is_video_src(struct ast_bridge *bridge, struct ast_channel *chan)
                } else if (bridge->softmix.video_mode.mode_data.talker_src_data.chan_old_vsrc == chan) {
                        res = 2;
                }
-
+       case AST_BRIDGE_VIDEO_MODE_SFU:
+               break;
        }
        ast_bridge_unlock(bridge);
        return res;
@@ -3777,10 +3979,27 @@ void ast_bridge_remove_video_src(struct ast_bridge *bridge, struct ast_channel *
                        }
                        bridge->softmix.video_mode.mode_data.talker_src_data.chan_old_vsrc = NULL;
                }
+       case AST_BRIDGE_VIDEO_MODE_SFU:
+               break;
        }
        ast_bridge_unlock(bridge);
 }
 
+const char *ast_bridge_video_mode_to_string(enum ast_bridge_video_mode_type video_mode)
+{
+       switch (video_mode) {
+       case AST_BRIDGE_VIDEO_MODE_TALKER_SRC:
+               return "talker";
+       case AST_BRIDGE_VIDEO_MODE_SINGLE_SRC:
+               return "single";
+       case AST_BRIDGE_VIDEO_MODE_SFU:
+               return "sfu";
+       case AST_BRIDGE_VIDEO_MODE_NONE:
+       default:
+               return "none";
+       }
+}
+
 static int channel_hash(const void *obj, int flags)
 {
        const struct ast_channel *chan = obj;
@@ -4025,6 +4244,15 @@ static enum ast_transfer_result attended_transfer_bridge(struct ast_channel *cha
                struct ast_channel *chan2, struct ast_bridge *bridge1, struct ast_bridge *bridge2,
                struct ast_attended_transfer_message *transfer_msg)
 {
+#define BRIDGE_LOCK_ONE_OR_BOTH(b1, b2) \
+       do { \
+               if (b2) { \
+                       ast_bridge_lock_both(b1, b2); \
+               } else { \
+                       ast_bridge_lock(b1); \
+               } \
+       } while (0)
+
        static const char *dest = "_attended@transfer/m";
        struct ast_channel *local_chan;
        int cause;
@@ -4055,8 +4283,18 @@ static enum ast_transfer_result attended_transfer_bridge(struct ast_channel *cha
                return AST_BRIDGE_TRANSFER_FAIL;
        }
 
+       /*
+        * Since bridges need to be unlocked before entering ast_bridge_impart and
+        * core_local may call into it then the bridges need to be unlocked here.
+        */
+       ast_bridge_unlock(bridge1);
+       if (bridge2) {
+               ast_bridge_unlock(bridge2);
+       }
+
        if (ast_call(local_chan, dest, 0)) {
                ast_hangup(local_chan);
+               BRIDGE_LOCK_ONE_OR_BOTH(bridge1, bridge2);
                return AST_BRIDGE_TRANSFER_FAIL;
        }
 
@@ -4066,23 +4304,32 @@ static enum ast_transfer_result attended_transfer_bridge(struct ast_channel *cha
                AST_BRIDGE_IMPART_CHAN_INDEPENDENT)) {
                ast_hangup(local_chan);
                ao2_cleanup(local_chan);
+               BRIDGE_LOCK_ONE_OR_BOTH(bridge1, bridge2);
                return AST_BRIDGE_TRANSFER_FAIL;
        }
+       BRIDGE_LOCK_ONE_OR_BOTH(bridge1, bridge2);
 
        if (bridge2) {
-               RAII_VAR(struct ast_channel *, local_chan2, NULL, ao2_cleanup);
+               void *tech;
                struct ast_channel *locals[2];
 
-               ast_channel_lock(local_chan);
-               local_chan2 = ast_local_get_peer(local_chan);
-               ast_channel_unlock(local_chan);
-
-               ast_assert(local_chan2 != NULL);
+               /* Have to lock everything just in case a hangup comes in early */
+               ast_local_lock_all(local_chan, &tech, &locals[0], &locals[1]);
+               if (!locals[0] || !locals[1]) {
+                       ast_log(LOG_ERROR, "Transfer failed probably due to an early hangup - "
+                               "missing other half of '%s'\n", ast_channel_name(local_chan));
+                       ast_local_unlock_all(tech, locals[0], locals[1]);
+                       ao2_cleanup(local_chan);
+                       return AST_BRIDGE_TRANSFER_FAIL;
+               }
 
-               locals[0] = local_chan;
-               locals[1] = local_chan2;
+               /* Make sure the peer is properly set */
+               if (local_chan != locals[0]) {
+                       SWAP(locals[0], locals[1]);
+               }
 
                ast_attended_transfer_message_add_link(transfer_msg, locals);
+               ast_local_unlock_all(tech, locals[0], locals[1]);
        } else {
                ast_attended_transfer_message_add_app(transfer_msg, app, local_chan);
        }
@@ -4181,8 +4428,8 @@ static struct ast_bridge *acquire_bridge(struct ast_channel *chan)
        bridge = ast_channel_get_bridge(chan);
        ast_channel_unlock(chan);
 
-       if (bridge
-               && ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_MASQUERADE_ONLY)) {
+       if (bridge && ast_test_flag(&bridge->feature_flags,
+                       (AST_BRIDGE_FLAG_MASQUERADE_ONLY | AST_BRIDGE_FLAG_INVISIBLE))) {
                ao2_ref(bridge, -1);
                bridge = NULL;
        }
@@ -4459,6 +4706,7 @@ enum ast_transfer_result ast_bridge_transfer_attended(struct ast_channel *to_tra
        int do_bridge_transfer;
        enum ast_transfer_result res;
        const char *app = NULL;
+       int hangup_target = 0;
 
        to_transferee_bridge = acquire_bridge(to_transferee);
        to_target_bridge = acquire_bridge(to_transfer_target);
@@ -4538,7 +4786,7 @@ enum ast_transfer_result ast_bridge_transfer_attended(struct ast_channel *to_tra
                ast_bridge_unlock(to_transferee_bridge);
                ast_bridge_unlock(to_target_bridge);
 
-               ast_softhangup(to_transfer_target, AST_SOFTHANGUP_DEV);
+               hangup_target = 1;
                goto end;
        }
 
@@ -4546,6 +4794,12 @@ enum ast_transfer_result ast_bridge_transfer_attended(struct ast_channel *to_tra
        chan_bridged = to_transferee_bridge ? to_transferee : to_transfer_target;
        chan_unbridged = to_transferee_bridge ? to_transfer_target : to_transferee;
 
+       /*
+        * Race condition makes it possible for app to be NULL, so get the app prior to
+        * transferring with a fallback of "unknown".
+        */
+       app = ast_strdupa(ast_channel_appl(chan_unbridged) ?: "unknown");
+
        {
                int chan_count;
                SCOPED_LOCK(lock, the_bridge, ast_bridge_lock, ast_bridge_unlock);
@@ -4575,6 +4829,11 @@ enum ast_transfer_result ast_bridge_transfer_attended(struct ast_channel *to_tra
        set_transfer_variables_all(to_transferee, channels, 1);
 
        if (do_bridge_transfer) {
+               /*
+                * Hang up the target if it was bridged. Note, if it is not bridged
+                * it is hung up during the masquerade.
+                */
+               hangup_target = chan_bridged == to_transfer_target;
                ast_bridge_lock(the_bridge);
                res = attended_transfer_bridge(chan_bridged, chan_unbridged, the_bridge, NULL, transfer_msg);
                ast_bridge_unlock(the_bridge);
@@ -4587,7 +4846,6 @@ enum ast_transfer_result ast_bridge_transfer_attended(struct ast_channel *to_tra
                goto end;
        }
 
-       app = ast_strdupa(ast_channel_appl(chan_unbridged));
        if (bridge_channel_internal_queue_attended_transfer(transferee, chan_unbridged)) {
                res = AST_BRIDGE_TRANSFER_FAIL;
                goto end;
@@ -4599,6 +4857,10 @@ enum ast_transfer_result ast_bridge_transfer_attended(struct ast_channel *to_tra
        res = AST_BRIDGE_TRANSFER_SUCCESS;
 
 end:
+       if ((res == AST_BRIDGE_TRANSFER_SUCCESS && hangup_target) || res == AST_BRIDGE_TRANSFER_FAIL) {
+               ast_softhangup(to_transfer_target, AST_SOFTHANGUP_DEV);
+       }
+
        transfer_msg->result = res;
        ast_bridge_publish_attended_transfer(transfer_msg);
        return res;
@@ -4979,12 +5241,6 @@ static char *complete_bridge_participant(const char *bridge_name, const char *li
                return NULL;
        }
 
-       if (!state) {
-               ao2_ref(bridge, -1);
-               return ast_strdup("all");
-       }
-       state--;
-
        {
                SCOPED_LOCK(bridge_lock, bridge, ast_bridge_lock, ast_bridge_unlock);
 
@@ -5006,6 +5262,8 @@ static char *complete_bridge_participant(const char *bridge_name, const char *li
 
 static char *handle_bridge_kick_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
+       static const char * const completions[] = { "all", NULL };
+       char *complete;
        struct ast_bridge *bridge;
 
        switch (cmd) {
@@ -5022,7 +5280,11 @@ static char *handle_bridge_kick_channel(struct ast_cli_entry *e, int cmd, struct
                        return complete_bridge_live(a->word, a->n);
                }
                if (a->pos == 3) {
-                       return complete_bridge_participant(a->argv[2], a->line, a->word, a->pos, a->n);
+                       complete = ast_cli_complete(a->word, completions, a->n);
+                       if (!complete) {
+                               complete = complete_bridge_participant(a->argv[2], a->line, a->word, a->pos, a->n - 1);
+                       }
+                       return complete;
                }
                return NULL;
        }