Merge "res_calendar: Specialized calendars depend on symbols of general calendar."
[asterisk/asterisk.git] / main / bridge.c
index c28d49c..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_REGISTER_FILE()
-
 #include "asterisk/logger.h"
 #include "asterisk/channel.h"
 #include "asterisk/options.h"
@@ -224,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);
 
@@ -430,6 +453,18 @@ static void bridge_channel_complete_join(struct ast_bridge *bridge, struct ast_b
        }
 
        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);
+       }
 }
 
 /*!
@@ -459,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;
                }
@@ -494,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);
        }
 
@@ -679,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);
@@ -734,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;
 }
 
@@ -759,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. */
@@ -793,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;
@@ -1710,7 +1759,7 @@ 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)
@@ -1727,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
@@ -1744,7 +1794,8 @@ 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);
@@ -2478,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);
@@ -2485,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);
 
@@ -2507,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.
@@ -2517,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) {
@@ -3721,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);
@@ -3745,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));
 }
@@ -3755,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);
 }
@@ -3766,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);
 }
 
@@ -3787,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;
@@ -3795,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);
@@ -3831,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;
@@ -3855,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;
@@ -3889,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;
@@ -4203,14 +4310,15 @@ static enum ast_transfer_result attended_transfer_bridge(struct ast_channel *cha
        BRIDGE_LOCK_ONE_OR_BOTH(bridge1, bridge2);
 
        if (bridge2) {
+               void *tech;
                struct ast_channel *locals[2];
 
                /* Have to lock everything just in case a hangup comes in early */
-               ast_local_lock_all(local_chan, &locals[0], &locals[1]);
+               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(local_chan);
+                       ast_local_unlock_all(tech, locals[0], locals[1]);
                        ao2_cleanup(local_chan);
                        return AST_BRIDGE_TRANSFER_FAIL;
                }
@@ -4221,7 +4329,7 @@ static enum ast_transfer_result attended_transfer_bridge(struct ast_channel *cha
                }
 
                ast_attended_transfer_message_add_link(transfer_msg, locals);
-               ast_local_unlock_all(local_chan);
+               ast_local_unlock_all(tech, locals[0], locals[1]);
        } else {
                ast_attended_transfer_message_add_app(transfer_msg, app, local_chan);
        }
@@ -4320,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;
        }
@@ -4749,7 +4857,7 @@ 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) {
+       if ((res == AST_BRIDGE_TRANSFER_SUCCESS && hangup_target) || res == AST_BRIDGE_TRANSFER_FAIL) {
                ast_softhangup(to_transfer_target, AST_SOFTHANGUP_DEV);
        }
 
@@ -5133,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);
 
@@ -5160,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) {
@@ -5176,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;
        }